summaryrefslogtreecommitdiff
path: root/system/easy-kernel
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2022-03-13 18:37:36 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2022-05-01 17:05:54 -0500
commit5ee14d3ae6662498723b1daf6f00f1a71521740f (patch)
tree9898987815da56f4f2b79c6e85ceb384c24ebb15 /system/easy-kernel
parent59e83832ec569bcc4b2dd0b39d5553aa5210cb81 (diff)
downloadpackages-5ee14d3ae6662498723b1daf6f00f1a71521740f.tar.gz
packages-5ee14d3ae6662498723b1daf6f00f1a71521740f.tar.bz2
packages-5ee14d3ae6662498723b1daf6f00f1a71521740f.tar.xz
packages-5ee14d3ae6662498723b1daf6f00f1a71521740f.zip
system/easy-kernel: Replace with 5.15 test-kernel
Diffstat (limited to 'system/easy-kernel')
-rw-r--r--system/easy-kernel/0000-README77
-rw-r--r--system/easy-kernel/0100-linux-5.15.11.patch80405
-rw-r--r--system/easy-kernel/0120-XATTR_USER_PREFIX.patch67
-rw-r--r--system/easy-kernel/0122-link-security-restrictions.patch20
-rw-r--r--system/easy-kernel/0124-bluetooth-keysize-check.patch37
-rw-r--r--system/easy-kernel/0126-sign-file-libressl.patch16
-rw-r--r--system/easy-kernel/0130-lrng.patch28362
-rw-r--r--system/easy-kernel/0250-projectc-5.15-r1.patch9746
-rw-r--r--system/easy-kernel/0255-ultra-ksm.patch6970
-rw-r--r--system/easy-kernel/0260-reduce-swappiness.patch11
-rw-r--r--system/easy-kernel/0300-tmp513-regression-fix.patch30
-rw-r--r--system/easy-kernel/0500-print-fw-info.patch14
-rw-r--r--system/easy-kernel/0502-gcc9-kcflags.patch680
-rw-r--r--system/easy-kernel/1000-version.patch1840
-rw-r--r--system/easy-kernel/APKBUILD76
-rw-r--r--system/easy-kernel/config-ppc641195
-rw-r--r--system/easy-kernel/config-x86_642332
-rw-r--r--system/easy-kernel/kernel.h17
-rw-r--r--system/easy-kernel/no-require-gnu-tar.patch10
-rw-r--r--system/easy-kernel/no-require-lilo.patch15
-rw-r--r--system/easy-kernel/uapi-iphdr.patch47
21 files changed, 130757 insertions, 1210 deletions
diff --git a/system/easy-kernel/0000-README b/system/easy-kernel/0000-README
new file mode 100644
index 000000000..a59328389
--- /dev/null
+++ b/system/easy-kernel/0000-README
@@ -0,0 +1,77 @@
+kernel-mc README
+--------------------------------------------------------------------------
+This patchset is Horst Burkhardt's "mc" patchset.
+It is also the upstream for Adelie Linux' "easy-kernel".
+
+This patchset is designed for compatibility with all distributions, and
+is tuned for performance and memory consumption on all architectures.
+
+It integrates some of the patches from Gentoo Linux' "gentoo-sources" to
+leverage the bug-finding power of the Gentoo community.
+
+Unless otherwise explicitly stated, the resulting kernel should be
+considered to be suitable under all loads and in all environments.
+
+Patchset Sequence
+--------------------------------------------------------------------------
+0100 cumulative linux patch
+0120-0199 security patches
+0200-0249 arch-specific fixes
+0250-0299 performance patches
+0300-0399 device driver patches
+0400-0499 kernel subsystem patches
+0500-0549 feature additions
+0550-0599 experimental patches
+0600-0999 not yet allocated
+ 1000 version update patch
+
+Individual Patch Descriptions (0120-1000):
+--------------------------------------------------------------------------
+
+File: 0120-XATTR_USER_PREFIX.patch
+From: https://bugs.gentoo.org/show_bug.cgi?id=470644
+Desc: Support for namespace user.pax.* on tmpfs.
+
+File: 0122-link-security-restrictions.patch
+From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/
+Desc: Enable link security restrictions by default.
+
+File: 0124-bluetooth-keysize-check.patch
+From: https://lore.kernel.org/linux-bluetooth/20190522070540.48895-1-marcel@holtmann.org/raw
+Desc: Check key sizes when Bluetooth "Secure Simple Pairing" is enabled.
+
+File: 0126-sign-file-libressl.patch
+From: https://bugs.gentoo.org/717166
+Desc: Allow recent versions of LibreSSL to provide full functionality for sign-file.
+
+File: 0130-lrng.patch
+From: https://github.com/smuellerDD/lrng
+Desc: An ABI- and API- compatible replacement for the Linux /dev/random implementation focused on security, performance, and correctness.
+
+File: 0250-projectc-5.15-r1.patch
+From: https://gitlab.com/alfredchen/linux-prjc
+Desc: "Project C", incorporating the PDQ scheduler descended from ck's Brain Fuck Scheduler
+
+File: 0255-ultraksm.patch
+From: https://github.com/sirlucjan/kernel-patches/
+Desc: Ultra Same-Page Merging provides an aggressive KSM implementation to further enhance memory usage over RedHat KSM in mainline
+
+File: 0260-reduce-swappiness.patch
+From: Horst Burkhardt <horst@burkhardt.com.au> - originally from -ck patchset by Con Kolivas
+Desc: Reduces the proclivity of the kernel to page out memory contents to disk
+
+File: 0300-tmp513-regression-fix.patch
+From: https://bugs.gentoo.org/710790
+Desc: Fix to regression in Kconfig from kernel 5.5.6 to enable tmp513 hardware monitoring module to build.
+
+File: 0500-print-fw-info.patch
+From: https://bugs.gentoo.org/732852
+Desc: Makes kernel print exact firmware file that kernel attempts to load.
+
+File: 0502-gcc9-kcflags.patch
+From: https://github.com/graysky2/kernel_gcc_patch/
+Desc: Enables gcc >=9.1 optimizations for the very latest x86_64 CPUs.
+
+File: 1000-version.patch
+From: Horst Burkhardt (horst@burkhardt.com.au)
+Desc: Adjust Makefile to represent patchset version, adds cool logo to boot logo options
diff --git a/system/easy-kernel/0100-linux-5.15.11.patch b/system/easy-kernel/0100-linux-5.15.11.patch
new file mode 100644
index 000000000..5f2c26f1a
--- /dev/null
+++ b/system/easy-kernel/0100-linux-5.15.11.patch
@@ -0,0 +1,80405 @@
+diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
+index 43dc35fe5bc03..1396fd2d90319 100644
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -6349,6 +6349,13 @@
+ improve timer resolution at the expense of processing
+ more timer interrupts.
+
++ 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.
+diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
+index 426162009ce99..0e486f41185ef 100644
+--- a/Documentation/admin-guide/sysctl/kernel.rst
++++ b/Documentation/admin-guide/sysctl/kernel.rst
+@@ -1099,7 +1099,7 @@ task_delayacct
+ ===============
+
+ Enables/disables task delay accounting (see
+-:doc:`accounting/delay-accounting.rst`). Enabling this feature incurs
++Documentation/accounting/delay-accounting.rst. Enabling this feature incurs
+ a small amount of overhead in the scheduler but is useful for debugging
+ and performance tuning. It is required by some tools such as iotop.
+
+diff --git a/Documentation/dev-tools/kfence.rst b/Documentation/dev-tools/kfence.rst
+index 0fbe3308bf37f..48244d32780f6 100644
+--- a/Documentation/dev-tools/kfence.rst
++++ b/Documentation/dev-tools/kfence.rst
+@@ -231,10 +231,14 @@ Guarded allocations are set up based on the sample interval. After expiration
+ of the sample interval, the next allocation through the main allocator (SLAB or
+ SLUB) returns a guarded allocation from the KFENCE object pool (allocation
+ sizes up to PAGE_SIZE are supported). At this point, the timer is reset, and
+-the next allocation is set up after the expiration of the interval. To "gate" a
+-KFENCE allocation through the main allocator's fast-path without overhead,
+-KFENCE relies on static branches via the static keys infrastructure. The static
+-branch is toggled to redirect the allocation to KFENCE.
++the next allocation is set up after the expiration of the interval.
++
++When using ``CONFIG_KFENCE_STATIC_KEYS=y``, KFENCE allocations are "gated"
++through the main allocator's fast-path by relying on static branches via the
++static keys infrastructure. The static branch is toggled to redirect the
++allocation to KFENCE. Depending on sample interval, target workloads, and
++system architecture, this may perform better than the simple dynamic branch.
++Careful benchmarking is recommended.
+
+ KFENCE objects each reside on a dedicated page, at either the left or right
+ page boundaries selected at random. The pages to the left and right of the
+diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml
+index d5c54813ce872..a8f7720d1e3e2 100644
+--- a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml
++++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml
+@@ -54,7 +54,7 @@ examples:
+
+ ad5766@0 {
+ compatible = "adi,ad5766";
+- output-range-microvolts = <(-5000) 5000>;
++ output-range-microvolts = <(-5000000) 5000000>;
+ reg = <0>;
+ spi-cpol;
+ spi-max-frequency = <1000000>;
+diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
+index 877183cf42787..1ef849dc74d7e 100644
+--- a/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
++++ b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
+@@ -79,6 +79,8 @@ properties:
+
+ properties:
+ data-lanes:
++ description:
++ Note that 'fsl,imx7-mipi-csi2' only supports up to 2 data lines.
+ items:
+ minItems: 1
+ maxItems: 4
+@@ -91,18 +93,6 @@ properties:
+ required:
+ - data-lanes
+
+- allOf:
+- - if:
+- properties:
+- compatible:
+- contains:
+- const: fsl,imx7-mipi-csi2
+- then:
+- properties:
+- data-lanes:
+- items:
+- maxItems: 2
+-
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
+index 2766fe45bb98b..ee42328a109dc 100644
+--- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml
++++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
+@@ -91,6 +91,14 @@ properties:
+ 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:
+diff --git a/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
+index 093edda0c8dfc..6cd83d920155f 100644
+--- a/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
++++ b/Documentation/devicetree/bindings/regulator/samsung,s5m8767.txt
+@@ -13,6 +13,14 @@ common regulator binding documented in:
+
+
+ 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 @@ Required properties of the main device node (the parent!):
+ 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.
+diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
+index 0eb799d9d05a2..7940a45d39522 100644
+--- a/Documentation/filesystems/fscrypt.rst
++++ b/Documentation/filesystems/fscrypt.rst
+@@ -176,11 +176,11 @@ Master Keys
+
+ Each encrypted directory tree is protected by a *master key*. Master
+ keys can be up to 64 bytes long, and must be at least as long as the
+-greater of the key length needed by the contents and filenames
+-encryption modes being used. For example, if AES-256-XTS is used for
+-contents encryption, the master key must be 64 bytes (512 bits). Note
+-that the XTS mode is defined to require a key twice as long as that
+-required by the underlying block cipher.
++greater of the security strength of the contents and filenames
++encryption modes being used. For example, if any AES-256 mode is
++used, the master key must be at least 256 bits, i.e. 32 bytes. A
++stricter requirement applies if the key is used by a v1 encryption
++policy and AES-256-XTS is used; such keys must be 64 bytes.
+
+ To "unlock" an encrypted directory tree, userspace must provide the
+ appropriate master key. There can be any number of master keys, each
+diff --git a/Documentation/locking/locktypes.rst b/Documentation/locking/locktypes.rst
+index ddada4a537493..4fd7b70fcde19 100644
+--- a/Documentation/locking/locktypes.rst
++++ b/Documentation/locking/locktypes.rst
+@@ -439,11 +439,9 @@ preemption. The following substitution works on both kernels::
+ spin_lock(&p->lock);
+ p->count += this_cpu_read(var2);
+
+-On a non-PREEMPT_RT kernel migrate_disable() maps to preempt_disable()
+-which makes the above code fully equivalent. On a PREEMPT_RT kernel
+ migrate_disable() ensures that the task is pinned on the current CPU which
+ in turn guarantees that the per-CPU access to var1 and var2 are staying on
+-the same CPU.
++the same CPU while the task remains preemptible.
+
+ The migrate_disable() substitution is not valid for the following
+ scenario::
+@@ -456,9 +454,8 @@ scenario::
+ p = this_cpu_ptr(&var1);
+ p->val = func2();
+
+-While correct on a non-PREEMPT_RT kernel, this breaks on PREEMPT_RT because
+-here migrate_disable() does not protect against reentrancy from a
+-preempting task. A correct substitution for this case is::
++This breaks because migrate_disable() does not protect against reentrancy from
++a preempting task. A correct substitution for this case is::
+
+ func()
+ {
+diff --git a/Documentation/networking/device_drivers/ethernet/intel/ixgbe.rst b/Documentation/networking/device_drivers/ethernet/intel/ixgbe.rst
+index f1d5233e5e510..0a233b17c664e 100644
+--- a/Documentation/networking/device_drivers/ethernet/intel/ixgbe.rst
++++ b/Documentation/networking/device_drivers/ethernet/intel/ixgbe.rst
+@@ -440,6 +440,22 @@ NOTE: For 82599-based network connections, if you are enabling jumbo frames in
+ a virtual function (VF), jumbo frames must first be enabled in the physical
+ function (PF). The VF MTU setting cannot be larger than the PF MTU.
+
++NBASE-T Support
++---------------
++The ixgbe driver supports NBASE-T on some devices. However, the advertisement
++of NBASE-T speeds is suppressed by default, to accommodate broken network
++switches which cannot cope with advertised NBASE-T speeds. Use the ethtool
++command to enable advertising NBASE-T speeds on devices which support it::
++
++ ethtool -s eth? advertise 0x1800000001028
++
++On Linux systems with INTERFACES(5), this can be specified as a pre-up command
++in /etc/network/interfaces so that the interface is always brought up with
++NBASE-T support, e.g.::
++
++ iface eth? inet dhcp
++ pre-up ethtool -s eth? advertise 0x1800000001028 || true
++
+ Generic Receive Offload, aka GRO
+ --------------------------------
+ The driver supports the in-kernel software implementation of GRO. GRO has
+diff --git a/Documentation/networking/ipvs-sysctl.rst b/Documentation/networking/ipvs-sysctl.rst
+index 2afccc63856ee..1cfbf1add2fc9 100644
+--- a/Documentation/networking/ipvs-sysctl.rst
++++ b/Documentation/networking/ipvs-sysctl.rst
+@@ -37,8 +37,7 @@ conn_reuse_mode - INTEGER
+
+ 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
+diff --git a/Makefile b/Makefile
+index ed6e7ec60eff6..37a1144c32df7 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 15
+-SUBLEVEL = 0
++SUBLEVEL = 11
+ EXTRAVERSION =
+ NAME = Trick or Treat
+
+diff --git a/arch/Kconfig b/arch/Kconfig
+index 8df1c71026435..d1e69d6e8498b 100644
+--- a/arch/Kconfig
++++ b/arch/Kconfig
+@@ -1234,6 +1234,9 @@ config RELR
+ config ARCH_HAS_MEM_ENCRYPT
+ bool
+
++config ARCH_HAS_CC_PLATFORM
++ bool
++
+ config HAVE_SPARSE_SYSCALL_NR
+ bool
+ help
+diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
+index 3793876f42d9b..8e90052f6f056 100644
+--- a/arch/arc/kernel/process.c
++++ b/arch/arc/kernel/process.c
+@@ -294,7 +294,7 @@ int elf_check_arch(const struct elf32_hdr *x)
+ eflags = x->e_flags;
+ if ((eflags & EF_ARC_OSABI_MSK) != EF_ARC_OSABI_CURRENT) {
+ pr_err("ABI mismatch - you need newer toolchain\n");
+- force_sigsegv(SIGSEGV);
++ force_fatal_sig(SIGSEGV);
+ return 0;
+ }
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index dcf2df6da98f0..4ebd512043be5 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1455,6 +1455,7 @@ config HIGHMEM
+ bool "High Memory Support"
+ depends on MMU
+ select KMAP_LOCAL
++ select KMAP_LOCAL_NON_LINEAR_PTE_ARRAY
+ help
+ The address space of ARM processors is only 4 Gigabytes large
+ and it has to accommodate user address space, kernel address
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 847c31e7c3687..fa45837b8065c 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -60,15 +60,15 @@ KBUILD_CFLAGS += $(call cc-option,-fno-ipa-sra)
+ # 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
+@@ -82,7 +82,7 @@ tune-$(CONFIG_CPU_ARM720T) =-mtune=arm7tdmi
+ 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
+@@ -90,11 +90,11 @@ tune-$(CONFIG_CPU_ARM926T) =-mtune=arm9tdmi
+ 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)
+diff --git a/arch/arm/boot/dts/at91-tse850-3.dts b/arch/arm/boot/dts/at91-tse850-3.dts
+index 3ca97b47c69ce..7e5c598e7e68f 100644
+--- a/arch/arm/boot/dts/at91-tse850-3.dts
++++ b/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>;
+diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
+index 748df7955ae67..e96ddb2e26e2c 100644
+--- a/arch/arm/boot/dts/bcm-nsp.dtsi
++++ b/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>;
+@@ -219,7 +219,7 @@
+ status = "disabled";
+ };
+
+- sdio: sdhci@21000 {
++ sdio: mmc@21000 {
+ compatible = "brcm,sdhci-iproc-cygnus";
+ reg = <0x21000 0x100>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi
+index 3b60297af7f60..9e01dbca4a011 100644
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -506,11 +506,17 @@
+ #address-cells = <3>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+- interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
++ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "pcie", "msi";
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &gicv2 GIC_SPI 144
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &gicv2 GIC_SPI 145
++ IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &gicv2 GIC_SPI 146
+ IRQ_TYPE_LEVEL_HIGH>;
+ msi-controller;
+ msi-parent = <&pcie0>;
+diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+index 61c7b137607e5..7900aac4f35a9 100644
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -20,7 +20,7 @@
+ bootargs = "console=ttyS0,115200 earlycon";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+index 6c6bb7b17d27a..7546c8d07bcd7 100644
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -19,7 +19,7 @@
+ bootargs = "console=ttyS0,115200";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+index d29e7f80ea6aa..beae9eab9cb8c 100644
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -19,7 +19,7 @@
+ bootargs = "console=ttyS0,115200";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x18000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts
+index 9b6887d477d86..7879f7d7d9c33 100644
+--- a/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts
++++ b/arch/arm/boot/dts/bcm4709-linksys-ea9200.dts
+@@ -16,7 +16,7 @@
+ bootargs = "console=ttyS0,115200";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+index 7989a53597d4f..56d309dbc6b0d 100644
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -19,7 +19,7 @@
+ bootargs = "console=ttyS0,115200";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+index 87b655be674c5..184e3039aa864 100644
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -30,7 +30,7 @@
+ bootargs = "console=ttyS0,115200";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x08000000>;
+diff --git a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
+index f806be5da7237..c2a266a439d05 100644
+--- a/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
++++ b/arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
+@@ -15,7 +15,7 @@
+ bootargs = "console=ttyS0,115200 earlycon";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+diff --git a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+index 05d4f2931772b..9bef6b9bfa8d9 100644
+--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
++++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+@@ -129,7 +129,7 @@
+ };
+ };
+
+- mdio-bus-mux@18003000 {
++ mdio-mux@18003000 {
+
+ /* BIT(9) = 1 => external mdio */
+ mdio@200 {
+diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
+index 452b8d0ab180e..b0d8a688141d3 100644
+--- a/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
++++ b/arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
+@@ -16,7 +16,7 @@
+ bootargs = "earlycon";
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>,
+ <0x88000000 0x18000000>;
+diff --git a/arch/arm/boot/dts/bcm53016-meraki-mr32.dts b/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
+index 3b978dc8997a4..577a4dc604d93 100644
+--- a/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
++++ b/arch/arm/boot/dts/bcm53016-meraki-mr32.dts
+@@ -20,7 +20,7 @@
+ bootargs = " console=ttyS0,115200n8 earlycon";
+ };
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x08000000>;
+ device_type = "memory";
+ };
+@@ -195,3 +195,25 @@
+ };
+ };
+ };
++
++&srab {
++ status = "okay";
++
++ ports {
++ port@0 {
++ reg = <0>;
++ label = "poe";
++ };
++
++ port@5 {
++ reg = <5>;
++ label = "cpu";
++ ethernet = <&gmac0>;
++
++ fixed-link {
++ speed = <1000>;
++ duplex-full;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
+index f92089290ccd5..f69d2af3c1fa4 100644
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -19,7 +19,7 @@
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+
+- chipcommonA@18000000 {
++ chipcommon-a-bus@18000000 {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x18000000 0x00001000>;
+ #address-cells = <1>;
+@@ -44,7 +44,7 @@
+ };
+ };
+
+- mpcore@19000000 {
++ mpcore-bus@19000000 {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x19000000 0x00023000>;
+ #address-cells = <1>;
+@@ -242,6 +242,8 @@
+
+ gpio-controller;
+ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pcie0: pcie@12000 {
+@@ -369,8 +371,8 @@
+ #address-cells = <1>;
+ };
+
+- mdio-bus-mux@18003000 {
+- compatible = "mdio-mux-mmioreg";
++ mdio-mux@18003000 {
++ compatible = "mdio-mux-mmioreg", "mdio-mux";
+ mdio-parent-bus = <&mdio>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -408,14 +410,14 @@
+ 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>;
+ status = "disabled";
+ };
+
+- dmu@1800c000 {
++ dmu-bus@1800c000 {
+ compatible = "simple-bus";
+ ranges = <0 0x1800c000 0x1000>;
+ #address-cells = <1>;
+diff --git a/arch/arm/boot/dts/bcm94708.dts b/arch/arm/boot/dts/bcm94708.dts
+index 3d13e46c69494..d9eb2040b9631 100644
+--- a/arch/arm/boot/dts/bcm94708.dts
++++ b/arch/arm/boot/dts/bcm94708.dts
+@@ -38,7 +38,7 @@
+ model = "NorthStar SVK (BCM94708)";
+ compatible = "brcm,bcm94708", "brcm,bcm4708";
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+diff --git a/arch/arm/boot/dts/bcm94709.dts b/arch/arm/boot/dts/bcm94709.dts
+index 5017b7b259cbe..618c812eef73e 100644
+--- a/arch/arm/boot/dts/bcm94709.dts
++++ b/arch/arm/boot/dts/bcm94709.dts
+@@ -38,7 +38,7 @@
+ model = "NorthStar SVK (BCM94709)";
+ compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708";
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+diff --git a/arch/arm/boot/dts/imx6ull-pinfunc.h b/arch/arm/boot/dts/imx6ull-pinfunc.h
+index eb025a9d47592..7328d4ef8559f 100644
+--- a/arch/arm/boot/dts/imx6ull-pinfunc.h
++++ b/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 */
+diff --git a/arch/arm/boot/dts/ls1021a-tsn.dts b/arch/arm/boot/dts/ls1021a-tsn.dts
+index 9d8f0c2a8aba3..aca78b5eddf20 100644
+--- a/arch/arm/boot/dts/ls1021a-tsn.dts
++++ b/arch/arm/boot/dts/ls1021a-tsn.dts
+@@ -251,7 +251,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>;
+diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
+index 4fce81422943b..f3b8540750b61 100644
+--- a/arch/arm/boot/dts/ls1021a.dtsi
++++ b/arch/arm/boot/dts/ls1021a.dtsi
+@@ -329,39 +329,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>;
+@@ -1016,4 +983,37 @@
+ big-endian;
+ };
+ };
++
++ 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>;
++ };
++ };
++ };
++ };
+ };
+diff --git a/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
+index 7f6aefd134514..e7534fe9c53cf 100644
+--- a/arch/arm/boot/dts/omap-gpmc-smsc9221.dtsi
++++ b/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>;
+diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
+index 938cc691bb2fe..23ab27fe4ee5d 100644
+--- a/arch/arm/boot/dts/omap3-gta04.dtsi
++++ b/arch/arm/boot/dts/omap3-gta04.dtsi
+@@ -515,7 +515,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 */
+ };
+diff --git a/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
+index e5da3bc6f1050..218a10c0d8159 100644
+--- a/arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
++++ b/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>;
+diff --git a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
+index f7ea2e5dd1914..971d2e2292600 100644
+--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
++++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
+@@ -19,12 +19,12 @@
+ stdout-path = "serial0:115200n8";
+ };
+
+- memory@0 {
++ memory@42000000 {
+ reg = <0x42000000 0x3e000000>;
+ device_type = "memory";
+ };
+
+- mdio0: mdio@0 {
++ mdio0: mdio-0 {
+ status = "okay";
+ compatible = "virtual,mdio-gpio";
+ gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>,
+@@ -91,7 +91,7 @@
+ };
+ };
+
+- mdio1: mdio@1 {
++ mdio1: mdio-1 {
+ status = "okay";
+ compatible = "virtual,mdio-gpio";
+ gpios = <&qcom_pinmux 11 GPIO_ACTIVE_HIGH>,
+diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
+index 78ec496d5bc30..2b01bc29ddf23 100644
+--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
++++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
+@@ -1589,8 +1589,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";
+ };
+ };
+
+diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
+index 2b645642b9352..2a745522404d6 100644
+--- a/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
++++ b/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>;
+
+diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts
+index 90e676e7019f2..1b02d46496a85 100644
+--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts
++++ b/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>;
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+index 6f138b2b26163..51bb436784e24 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
++++ b/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>;
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+index c155ff02eb6e0..cae9ddd5ed38b 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
++++ b/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>;
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
+index 8d5d3996f6f27..ca18b959e6559 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
++++ b/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;
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
+index 99a71757cdf46..3f7aa7bf0863a 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
++++ b/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>;
+
+diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
+index a060718758b67..25874e1b9c829 100644
+--- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
++++ b/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;
+diff --git a/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts b/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts
+index 264f3e9b5fce5..86e83639fadc1 100644
+--- a/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts
++++ b/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts
+@@ -292,10 +292,10 @@
+ };
+
+ ab8500_ldo_aux2 {
+- /* Supplies the Cypress TMA140 touchscreen only with 3.3V */
++ /* Supplies the Cypress TMA140 touchscreen only with 3.0V */
+ regulator-name = "AUX2";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
++ regulator-min-microvolt = <3000000>;
++ regulator-max-microvolt = <3000000>;
+ };
+
+ ab8500_ldo_aux3 {
+@@ -314,9 +314,9 @@
+
+ ab8500_ldo_aux5 {
+ regulator-name = "AUX5";
++ /* Intended for 1V8 for touchscreen but actually left unused */
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <2790000>;
+- regulator-always-on;
+ };
+
+ ab8500_ldo_aux6 {
+diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+index 5b60ecbd718f0..2ebafe27a865b 100644
+--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
++++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+@@ -1179,7 +1179,7 @@
+ };
+ };
+
+- sai2a_pins_c: sai2a-4 {
++ sai2a_pins_c: sai2a-2 {
+ pins {
+ pinmux = <STM32_PINMUX('D', 13, AF10)>, /* SAI2_SCK_A */
+ <STM32_PINMUX('D', 11, AF10)>, /* SAI2_SD_A */
+@@ -1190,7 +1190,7 @@
+ };
+ };
+
+- sai2a_sleep_pins_c: sai2a-5 {
++ sai2a_sleep_pins_c: sai2a-2 {
+ pins {
+ pinmux = <STM32_PINMUX('D', 13, ANALOG)>, /* SAI2_SCK_A */
+ <STM32_PINMUX('D', 11, ANALOG)>, /* SAI2_SD_A */
+@@ -1235,14 +1235,14 @@
+ };
+ };
+
+- sai2b_pins_c: sai2a-4 {
++ sai2b_pins_c: sai2b-2 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 11, AF10)>; /* SAI2_SD_B */
+ bias-disable;
+ };
+ };
+
+- sai2b_sleep_pins_c: sai2a-sleep-5 {
++ sai2b_sleep_pins_c: sai2b-sleep-2 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 11, ANALOG)>; /* SAI2_SD_B */
+ };
+diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
+index bd289bf5d2690..6992a4b0ba79b 100644
+--- a/arch/arm/boot/dts/stm32mp151.dtsi
++++ b/arch/arm/boot/dts/stm32mp151.dtsi
+@@ -824,7 +824,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>;
+@@ -834,7 +834,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>;
+@@ -855,7 +855,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>;
+@@ -865,7 +865,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>;
+@@ -886,7 +886,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>;
+@@ -896,7 +896,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>;
+@@ -1271,7 +1271,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>;
+@@ -1281,7 +1281,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>;
+diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi
+index 2b0ac605549d7..44ecc47085871 100644
+--- a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi
++++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi
+@@ -202,7 +202,7 @@
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+- spi-max-frequency = <108000000>;
++ spi-max-frequency = <50000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+index 899bfe04aeb91..48beed0f1f30a 100644
+--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
++++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+@@ -249,7 +249,7 @@
+ stusb1600@28 {
+ compatible = "st,stusb1600";
+ reg = <0x28>;
+- interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpioi>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&stusb1600_pins_a>;
+diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
+index 2beddbb3c5183..b3d1bdfb5118e 100644
+--- a/arch/arm/boot/dts/sun8i-a33.dtsi
++++ b/arch/arm/boot/dts/sun8i-a33.dtsi
+@@ -46,7 +46,7 @@
+ #include <dt-bindings/thermal/thermal.h>
+
+ / {
+- cpu0_opp_table: opp_table0 {
++ cpu0_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+@@ -164,7 +164,7 @@
+ io-channels = <&ths>;
+ };
+
+- mali_opp_table: gpu-opp-table {
++ mali_opp_table: opp-table-gpu {
+ compatible = "operating-points-v2";
+
+ opp-144000000 {
+diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
+index ac97eac91349b..82fdb04122caa 100644
+--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
++++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
+@@ -200,7 +200,7 @@
+ status = "disabled";
+ };
+
+- cpu0_opp_table: opp_table0 {
++ cpu0_opp_table: opp-table-cluster0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+@@ -253,7 +253,7 @@
+ };
+ };
+
+- cpu1_opp_table: opp_table1 {
++ cpu1_opp_table: opp-table-cluster1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
+index 4e89701df91f8..ae4f933abb895 100644
+--- a/arch/arm/boot/dts/sun8i-h3.dtsi
++++ b/arch/arm/boot/dts/sun8i-h3.dtsi
+@@ -44,7 +44,7 @@
+ #include <dt-bindings/thermal/thermal.h>
+
+ / {
+- cpu0_opp_table: opp_table0 {
++ cpu0_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+@@ -112,7 +112,7 @@
+ };
+ };
+
+- gpu_opp_table: gpu-opp-table {
++ gpu_opp_table: opp-table-gpu {
+ compatible = "operating-points-v2";
+
+ opp-120000000 {
+diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
+index 76ea4178a55cb..db798eac74315 100644
+--- a/arch/arm/kernel/stacktrace.c
++++ b/arch/arm/kernel/stacktrace.c
+@@ -54,8 +54,7 @@ int notrace unwind_frame(struct stackframe *frame)
+
+ frame->sp = frame->fp;
+ frame->fp = *(unsigned long *)(fp);
+- frame->pc = frame->lr;
+- frame->lr = *(unsigned long *)(fp + 4);
++ frame->pc = *(unsigned long *)(fp + 4);
+ #else
+ /* check current frame pointer is within bounds */
+ if (fp < low + 12 || fp > high - 4)
+diff --git a/arch/arm/mach-s3c/irq-s3c24xx.c b/arch/arm/mach-s3c/irq-s3c24xx.c
+index 3edc5f614eefc..c1c2f041ad3b1 100644
+--- a/arch/arm/mach-s3c/irq-s3c24xx.c
++++ b/arch/arm/mach-s3c/irq-s3c24xx.c
+@@ -361,11 +361,25 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
+ static 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;
+
+diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h
+index fc2608b18a0d0..18f01190dcfd4 100644
+--- a/arch/arm/mach-socfpga/core.h
++++ b/arch/arm/mach-socfpga/core.h
+@@ -33,7 +33,7 @@ extern void __iomem *sdr_ctl_base_addr;
+ 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;
+
+diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c
+index fbb80b883e5dd..201191cf68f32 100644
+--- a/arch/arm/mach-socfpga/platsmp.c
++++ b/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_boot_secondary(unsigned int cpu, struct task_struct *idle)
+
+ 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));
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 8355c38958942..82aa990c4180c 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -750,7 +750,7 @@ config CPU_BIG_ENDIAN
+ 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.
+
+diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
+index 9c348042a7244..4b1619584b23c 100644
+--- a/arch/arm/mm/kasan_init.c
++++ b/arch/arm/mm/kasan_init.c
+@@ -226,7 +226,7 @@ void __init kasan_init(void)
+ BUILD_BUG_ON(pgd_index(KASAN_SHADOW_START) !=
+ pgd_index(KASAN_SHADOW_END));
+ memcpy(tmp_pmd_table,
+- pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_START)),
++ (void*)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_START)),
+ sizeof(tmp_pmd_table));
+ set_pgd(&tmp_pgd_table[pgd_index(KASAN_SHADOW_START)],
+ __pgd(__pa(tmp_pmd_table) | PMD_TYPE_TABLE | L_PGD_SWAPPER));
+diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
+index a4e0060051070..274e4f73fd33c 100644
+--- a/arch/arm/mm/mmu.c
++++ b/arch/arm/mm/mmu.c
+@@ -390,9 +390,9 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
+ BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) < FIXADDR_START);
+ 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))
+diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
+index cc321c04f1219..f6d7d7f7fdabe 100644
+--- a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
++++ b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
+@@ -343,19 +343,19 @@
+ };
+
+ thermal-zones {
+- cpu-thermal-zone {
++ cpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 0>;
+ };
+
+- ddr-thermal-zone {
++ ddr-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 2>;
+ };
+
+- gpu-thermal-zone {
++ gpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-cpu-opp.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-cpu-opp.dtsi
+index 578c37490d901..e39db51eb4489 100644
+--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-cpu-opp.dtsi
++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-cpu-opp.dtsi
+@@ -4,7 +4,7 @@
+ */
+
+ / {
+- cpu0_opp_table: opp_table0 {
++ cpu0_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi
+index b2657201957eb..1afad8b437d72 100644
+--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi
++++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-cpu-opp.dtsi
+@@ -2,7 +2,7 @@
+ // Copyright (C) 2020 Chen-Yu Tsai <wens@csie.org>
+
+ / {
+- cpu_opp_table: cpu-opp-table {
++ cpu_opp_table: opp-table-cpu {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+index 578a63dedf466..9988e87ea7b3d 100644
+--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
++++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+@@ -217,7 +217,7 @@
+ };
+ };
+
+- gpu_thermal {
++ gpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-cpu-opp.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-cpu-opp.dtsi
+index 8c6e8536b69fa..0baf0f8e4d272 100644
+--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-cpu-opp.dtsi
++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-cpu-opp.dtsi
+@@ -3,7 +3,7 @@
+ // Copyright (C) 2020 Clément Péron <peron.clem@gmail.com>
+
+ / {
+- cpu_opp_table: cpu-opp-table {
++ cpu_opp_table: opp-table-cpu {
+ compatible = "allwinner,sun50i-h6-operating-points";
+ nvmem-cells = <&cpu_speed_grade>;
+ opp-shared;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
+index 81269ccc24968..d8838dde0f0f4 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
++++ b/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>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
+index a26bfe72550fe..4b5d11e56364d 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
++++ b/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>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
+index 579f3d02d613e..b4e86196e3468 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
++++ b/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>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
+index f42cf4b8af2d4..16dd409051b40 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
+@@ -18,7 +18,7 @@
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <1050000>;
+
+- vin-supply = <&dc_in>;
++ pwm-supply = <&dc_in>;
+
+ pwms = <&pwm_ab 0 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+@@ -37,7 +37,7 @@
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <1050000>;
+
+- vin-supply = <&vsys_3v3>;
++ pwm-supply = <&vsys_3v3>;
+
+ pwms = <&pwm_AO_cd 1 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
+index 344573e157a7b..4f33820aba1f1 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
+@@ -130,7 +130,7 @@
+ regulator-min-microvolt = <721000>;
+ regulator-max-microvolt = <1022000>;
+
+- vin-supply = <&main_12v>;
++ pwm-supply = <&main_12v>;
+
+ pwms = <&pwm_ab 0 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+@@ -149,7 +149,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>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-w400.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-w400.dtsi
+index feb0885047400..b40d2c1002c92 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-g12b-w400.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-w400.dtsi
+@@ -96,7 +96,7 @@
+ regulator-min-microvolt = <721000>;
+ regulator-max-microvolt = <1022000>;
+
+- vin-supply = <&main_12v>;
++ pwm-supply = <&main_12v>;
+
+ pwms = <&pwm_ab 0 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+@@ -115,7 +115,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>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
+index effaa138b5f98..212c6aa5a3b86 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
+@@ -173,7 +173,7 @@
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <1050000>;
+
+- vin-supply = <&dc_in>;
++ pwm-supply = <&dc_in>;
+
+ pwms = <&pwm_AO_cd 1 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts
+index f2c0981435944..9c0b544e22098 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts
+@@ -24,7 +24,7 @@
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <1050000>;
+
+- vin-supply = <&vsys_3v3>;
++ pwm-supply = <&vsys_3v3>;
+
+ pwms = <&pwm_AO_cd 1 1250 0>;
+ pwm-dutycycle-range = <100 0>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
+index fd0ad85c165ba..5779e70caccd3 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
+@@ -116,7 +116,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>;
+@@ -263,6 +263,10 @@
+ reg = <0>;
+ max-speed = <1000>;
+
++ reset-assert-us = <10000>;
++ reset-deassert-us = <80000>;
++ reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
++
+ interrupt-parent = <&gpio_intc>;
+ /* MAC_INTR on GPIOZ_14 */
+ interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
+index 2194a778973f1..427475846fc70 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
+@@ -185,7 +185,7 @@
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <1050000>;
+
+- vin-supply = <&dc_in>;
++ pwm-supply = <&dc_in>;
+
+ pwms = <&pwm_AO_cd 1 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
+index a5a64d17d9ea6..5118816b1ed76 100644
+--- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
++++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
+@@ -292,7 +292,7 @@
+ reg = <0x640 0x18>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+- clock-names = "periph";
++ clock-names = "refclk";
+ status = "okay";
+ };
+
+@@ -326,12 +326,12 @@
+ #reset-cells = <1>;
+ };
+ };
++ };
+
+- reboot {
+- compatible = "syscon-reboot";
+- regmap = <&timer>;
+- offset = <0x34>;
+- mask = <1>;
+- };
++ reboot {
++ compatible = "syscon-reboot";
++ regmap = <&timer>;
++ offset = <0x34>;
++ mask = <1>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+index 79f155dedb2d0..e662677a6e28f 100644
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts
+@@ -15,6 +15,7 @@
+ compatible = "fsl,ls1012a-rdb", "fsl,ls1012a";
+
+ aliases {
++ serial0 = &duart0;
+ mmc0 = &esdhc0;
+ mmc1 = &esdhc1;
+ };
+diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
+index 3063851c2fb91..d3f03dcbb8c38 100644
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
+@@ -38,7 +38,6 @@
+ powerdn {
+ label = "External Power Down";
+ gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
+- interrupts = <&gpio1 17 IRQ_TYPE_EDGE_FALLING>;
+ linux,code = <KEY_POWER>;
+ };
+
+@@ -46,7 +45,6 @@
+ admin {
+ label = "ADMIN button";
+ gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
+- interrupts = <&gpio3 8 IRQ_TYPE_EDGE_RISING>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+index f85e437f80b73..6050723172436 100644
+--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+@@ -847,7 +847,7 @@
+ };
+
+ cluster1_core0_watchdog: wdt@c000000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc000000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -857,7 +857,7 @@
+ };
+
+ cluster1_core1_watchdog: wdt@c010000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc010000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -867,7 +867,7 @@
+ };
+
+ cluster1_core2_watchdog: wdt@c020000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc020000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -877,7 +877,7 @@
+ };
+
+ cluster1_core3_watchdog: wdt@c030000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc030000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -887,7 +887,7 @@
+ };
+
+ cluster2_core0_watchdog: wdt@c100000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc100000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -897,7 +897,7 @@
+ };
+
+ cluster2_core1_watchdog: wdt@c110000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc110000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -907,7 +907,7 @@
+ };
+
+ cluster2_core2_watchdog: wdt@c120000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc120000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+@@ -917,7 +917,7 @@
+ };
+
+ cluster2_core3_watchdog: wdt@c130000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc130000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(16)>,
+diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+index 801ba9612d361..1282b61da8a55 100644
+--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+@@ -387,7 +387,7 @@
+ };
+
+ cluster1_core0_watchdog: wdt@c000000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc000000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -397,7 +397,7 @@
+ };
+
+ cluster1_core1_watchdog: wdt@c010000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc010000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -407,7 +407,7 @@
+ };
+
+ cluster2_core0_watchdog: wdt@c100000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc100000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -417,7 +417,7 @@
+ };
+
+ cluster2_core1_watchdog: wdt@c110000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc110000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -427,7 +427,7 @@
+ };
+
+ cluster3_core0_watchdog: wdt@c200000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc200000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -437,7 +437,7 @@
+ };
+
+ cluster3_core1_watchdog: wdt@c210000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc210000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -447,7 +447,7 @@
+ };
+
+ cluster4_core0_watchdog: wdt@c300000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc300000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+@@ -457,7 +457,7 @@
+ };
+
+ cluster4_core1_watchdog: wdt@c310000 {
+- compatible = "arm,sp805-wdt", "arm,primecell";
++ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0 0xc310000 0x0 0x1000>;
+ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+ QORIQ_CLK_PLL_DIV(4)>,
+diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-n801x-s.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-n801x-s.dts
+index e99e7644ff392..49d7470812eef 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-n801x-s.dts
++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-n801x-s.dts
+@@ -123,8 +123,8 @@
+
+ ethphy: ethernet-phy@0 {
+ reg = <0>;
+- reset-assert-us = <100>;
+- reset-deassert-us = <100>;
++ reset-assert-us = <1>;
++ reset-deassert-us = <15000>;
+ reset-gpios = <&gpio4 27 GPIO_ACTIVE_LOW>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+index 4066b16126552..2bc57d8f29c7f 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
++++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+@@ -524,8 +524,6 @@
+ <&clk IMX8MQ_VIDEO_PLL1>,
+ <&clk IMX8MQ_VIDEO_PLL1_OUT>;
+ assigned-clock-rates = <0>, <0>, <0>, <594000000>;
+- interconnects = <&noc IMX8MQ_ICM_LCDIF &noc IMX8MQ_ICS_DRAM>;
+- interconnect-names = "dram";
+ status = "disabled";
+
+ port@0 {
+diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
+index 2d5c1a348716a..6eabec2602e23 100644
+--- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
++++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi
+@@ -1087,7 +1087,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>,
+@@ -1096,7 +1096,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>,
+diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+index dde9371dc5451..e4860b8a638ec 100644
+--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
++++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+@@ -840,7 +840,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>,
+diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+index d2fe58e0eb7aa..7b6205c180df1 100644
+--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+@@ -200,7 +200,7 @@
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <1>;
+- qcom,controlled-remotely = <1>;
++ qcom,controlled-remotely;
+ qcom,config-pipe-trust-reg = <0>;
+ };
+
+diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+index db333001df4d6..97f99663c132e 100644
+--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+@@ -220,7 +220,7 @@
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <1>;
+- qcom,controlled-remotely = <1>;
++ qcom,controlled-remotely;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
+index 3f85e34a8ce6f..427bb20626549 100644
+--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
+@@ -445,7 +445,7 @@
+ };
+ };
+
+- rpm_msg_ram: memory@60000 {
++ rpm_msg_ram: sram@60000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00060000 0x8000>;
+ };
+@@ -1384,11 +1384,17 @@
+ lpass: audio-controller@7708000 {
+ status = "disabled";
+ compatible = "qcom,lpass-cpu-apq8016";
++
++ /*
++ * Note: Unlike the name would suggest, the SEC_I2S_CLK
++ * is actually only used by Tertiary MI2S while
++ * Primary/Secondary MI2S both use the PRI_I2S_CLK.
++ */
+ clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>,
+ <&gcc GCC_ULTAUDIO_PCNOC_MPORT_CLK>,
+ <&gcc GCC_ULTAUDIO_PCNOC_SWAY_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_PRI_I2S_CLK>,
+- <&gcc GCC_ULTAUDIO_LPAIF_SEC_I2S_CLK>,
++ <&gcc GCC_ULTAUDIO_LPAIF_PRI_I2S_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_SEC_I2S_CLK>,
+ <&gcc GCC_ULTAUDIO_LPAIF_AUX_I2S_CLK>;
+
+diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi
+index 986fe60dec5fb..5a9a5ed0565f6 100644
+--- a/arch/arm64/boot/dts/qcom/msm8994.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi
+@@ -715,7 +715,7 @@
+ reg = <0xfc400000 0x2000>;
+ };
+
+- rpm_msg_ram: memory@fc428000 {
++ rpm_msg_ram: sram@fc428000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0xfc428000 0x4000>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
+index 52df22ab3f6ae..f8d28dd76cfa8 100644
+--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
+@@ -638,7 +638,7 @@
+ };
+ };
+
+- rpm_msg_ram: memory@68000 {
++ rpm_msg_ram: sram@68000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00068000 0x6000>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
+index 34039b5c80175..228339f81c327 100644
+--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
+@@ -308,38 +308,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;
+ };
+ };
+@@ -857,7 +861,7 @@
+ reg = <0x00100000 0xb0000>;
+ };
+
+- rpm_msg_ram: memory@778000 {
++ rpm_msg_ram: sram@778000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00778000 0x7000>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
+index f931cb0de231f..42180f1b5dbbb 100644
+--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
++++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
+@@ -86,7 +86,6 @@
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000>;
+- reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ };
+
+diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
+index b4ac900ab115f..a06ea9adae810 100644
+--- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi
++++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
+@@ -42,7 +42,7 @@
+ /* Yes, all four strings *have to* be defined or things won't work. */
+ qcom,enabled-strings = <0 1 2 3>;
+ qcom,cabc;
+- qcom,eternal-pfet;
++ qcom,external-pfet;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
+index 339790ba585de..ca5be16479809 100644
+--- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
++++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
+@@ -318,7 +318,7 @@
+ status = "disabled";
+ };
+
+- rpm_msg_ram: memory@60000 {
++ rpm_msg_ram: sram@60000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00060000 0x6000>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
+index a758e4d226122..81098aa9687ba 100644
+--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
++++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
+@@ -33,7 +33,7 @@ ap_h1_spi: &spi0 {};
+ polling-delay = <0>;
+
+ thermal-sensors = <&pm6150_adc_tm 1>;
+- sustainable-power = <814>;
++ sustainable-power = <965>;
+
+ trips {
+ skin_temp_alert0: trip-point0 {
+diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
+index a246dbd74cc11..b7b5264888b7c 100644
+--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
++++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
+@@ -44,7 +44,7 @@ ap_h1_spi: &spi0 {};
+ };
+
+ &cpu6_thermal {
+- sustainable-power = <948>;
++ sustainable-power = <1124>;
+ };
+
+ &cpu7_alert0 {
+@@ -56,7 +56,7 @@ ap_h1_spi: &spi0 {};
+ };
+
+ &cpu7_thermal {
+- sustainable-power = <948>;
++ sustainable-power = <1124>;
+ };
+
+ &cpu8_alert0 {
+@@ -68,7 +68,7 @@ ap_h1_spi: &spi0 {};
+ };
+
+ &cpu8_thermal {
+- sustainable-power = <948>;
++ sustainable-power = <1124>;
+ };
+
+ &cpu9_alert0 {
+@@ -80,7 +80,7 @@ ap_h1_spi: &spi0 {};
+ };
+
+ &cpu9_thermal {
+- sustainable-power = <948>;
++ sustainable-power = <1124>;
+ };
+
+ &gpio_keys {
+diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi
+index c8921e2d6480f..495c15deacb7d 100644
+--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
++++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
+@@ -137,8 +137,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+ <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+@@ -162,8 +162,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ next-level-cache = <&L2_100>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -184,8 +184,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ next-level-cache = <&L2_200>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -206,8 +206,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ next-level-cache = <&L2_300>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -228,8 +228,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ next-level-cache = <&L2_400>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -250,8 +250,8 @@
+ cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+ &LITTLE_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1024>;
+- dynamic-power-coefficient = <100>;
++ capacity-dmips-mhz = <415>;
++ dynamic-power-coefficient = <137>;
+ next-level-cache = <&L2_500>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -272,8 +272,8 @@
+ cpu-idle-states = <&BIG_CPU_SLEEP_0
+ &BIG_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1740>;
+- dynamic-power-coefficient = <405>;
++ capacity-dmips-mhz = <1024>;
++ dynamic-power-coefficient = <480>;
+ next-level-cache = <&L2_600>;
+ operating-points-v2 = <&cpu6_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -294,8 +294,8 @@
+ cpu-idle-states = <&BIG_CPU_SLEEP_0
+ &BIG_CPU_SLEEP_1
+ &CLUSTER_SLEEP_0>;
+- capacity-dmips-mhz = <1740>;
+- dynamic-power-coefficient = <405>;
++ capacity-dmips-mhz = <1024>;
++ dynamic-power-coefficient = <480>;
+ next-level-cache = <&L2_700>;
+ operating-points-v2 = <&cpu6_opp_table>;
+ interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
+@@ -3616,7 +3616,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 1>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu0_alert0: trip-point0 {
+@@ -3665,7 +3665,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 2>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu1_alert0: trip-point0 {
+@@ -3714,7 +3714,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 3>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu2_alert0: trip-point0 {
+@@ -3763,7 +3763,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 4>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu3_alert0: trip-point0 {
+@@ -3812,7 +3812,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 5>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu4_alert0: trip-point0 {
+@@ -3861,7 +3861,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 6>;
+- sustainable-power = <768>;
++ sustainable-power = <1052>;
+
+ trips {
+ cpu5_alert0: trip-point0 {
+@@ -3910,7 +3910,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 9>;
+- sustainable-power = <1202>;
++ sustainable-power = <1425>;
+
+ trips {
+ cpu6_alert0: trip-point0 {
+@@ -3951,7 +3951,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 10>;
+- sustainable-power = <1202>;
++ sustainable-power = <1425>;
+
+ trips {
+ cpu7_alert0: trip-point0 {
+@@ -3992,7 +3992,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 11>;
+- sustainable-power = <1202>;
++ sustainable-power = <1425>;
+
+ trips {
+ cpu8_alert0: trip-point0 {
+@@ -4033,7 +4033,7 @@
+ polling-delay = <0>;
+
+ thermal-sensors = <&tsens0 12>;
+- sustainable-power = <1202>;
++ sustainable-power = <1425>;
+
+ trips {
+ cpu9_alert0: trip-point0 {
+diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
+index fd78f16181ddd..f58336536a92a 100644
+--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
++++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
+@@ -1258,15 +1258,11 @@
+ dp_phy: dp-phy@88ea200 {
+ reg = <0 0x088ea200 0 0x200>,
+ <0 0x088ea400 0 0x200>,
+- <0 0x088eac00 0 0x400>,
++ <0 0x088eaa00 0 0x200>,
+ <0 0x088ea600 0 0x200>,
+- <0 0x088ea800 0 0x200>,
+- <0 0x088eaa00 0 0x100>;
++ <0 0x088ea800 0 0x200>;
+ #phy-cells = <0>;
+ #clock-cells = <1>;
+- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+- clock-names = "pipe0";
+- clock-output-names = "usb3_phy_pipe_clk_src";
+ };
+ };
+
+diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi
+index 9c7f87e42fccd..a8724fd60645f 100644
+--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi
++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi
+@@ -541,7 +541,7 @@
+ <&sleep_clk>;
+ };
+
+- rpm_msg_ram: memory@778000 {
++ rpm_msg_ram: sram@778000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x00778000 0x7000>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
+index b3b9119261844..519ca9a705b4f 100644
+--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
+@@ -2316,11 +2316,11 @@
+ compatible = "qcom,bam-v1.7.0";
+ reg = <0 0x01dc4000 0 0x24000>;
+ interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&rpmhcc 15>;
++ clocks = <&rpmhcc RPMH_CE_CLK>;
+ clock-names = "bam_clk";
+ #dma-cells = <1>;
+ qcom,ee = <0>;
+- qcom,controlled-remotely = <1>;
++ qcom,controlled-remotely;
+ iommus = <&apps_smmu 0x704 0x1>,
+ <&apps_smmu 0x706 0x1>,
+ <&apps_smmu 0x714 0x1>,
+@@ -2331,8 +2331,8 @@
+ compatible = "qcom,crypto-v5.4";
+ reg = <0 0x01dfa000 0 0x6000>;
+ clocks = <&gcc GCC_CE1_AHB_CLK>,
+- <&gcc GCC_CE1_AHB_CLK>,
+- <&rpmhcc 15>;
++ <&gcc GCC_CE1_AXI_CLK>,
++ <&rpmhcc RPMH_CE_CLK>;
+ clock-names = "iface", "bus", "core";
+ dmas = <&cryptobam 6>, <&cryptobam 7>;
+ dma-names = "rx", "tx";
+diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi
+index 2b37ce6a9f9c5..9f476e3d0720b 100644
+--- a/arch/arm64/boot/dts/qcom/sm6125.dtsi
++++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi
+@@ -380,7 +380,7 @@
+ status = "disabled";
+ };
+
+- rpm_msg_ram: memory@45f0000 {
++ rpm_msg_ram: sram@45f0000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0x045f0000 0x7000>;
+ };
+diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi
+index 090dc9c4f57b5..937d17a426b66 100644
+--- a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi
++++ b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi
+@@ -50,6 +50,7 @@
+ &avb {
+ pinctrl-0 = <&avb_pins>;
+ pinctrl-names = "default";
++ phy-mode = "rgmii-rxid";
+ phy-handle = <&phy0>;
+ rx-internal-delay-ps = <1800>;
+ tx-internal-delay-ps = <2000>;
+diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
+index 665b2e69455dd..ea6820902ede0 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
+@@ -97,7 +97,7 @@
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+- vim-supply = <&vcc_io>;
++ vin-supply = <&vcc_io>;
+ };
+
+ vdd_core: vdd-core {
+diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+index 8c821acb21ffb..da84be6f4715e 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+@@ -599,7 +599,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>,
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
+index d5c7648c841dc..f1fcc6b5b402c 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
+@@ -705,7 +705,6 @@
+ &sdhci {
+ bus-width = <8>;
+ mmc-hs400-1_8v;
+- mmc-hs400-enhanced-strobe;
+ non-removable;
+ status = "okay";
+ };
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts
+index 738cfd21df3ef..354f54767bad8 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts
+@@ -269,6 +269,7 @@
+ clock-output-names = "xin32k", "rk808-clkout2";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l>;
++ rockchip,system-power-controller;
+ vcc1-supply = <&vcc5v0_sys>;
+ vcc2-supply = <&vcc5v0_sys>;
+ vcc3-supply = <&vcc5v0_sys>;
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
+index 7c93f840bc64f..e890166e7fd43 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
+@@ -55,7 +55,7 @@
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+- vim-supply = <&vcc3v3_sys>;
++ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc3v3_sys: vcc3v3-sys {
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+index 2b5f001ff4a61..9e5d07f5712e6 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+@@ -385,10 +385,6 @@
+ };
+ };
+
+-&cdn_dp {
+- status = "okay";
+-};
+-
+ &cpu_b0 {
+ cpu-supply = <&vdd_cpu_b>;
+ };
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
+index b28888ea9262e..100a769165ef9 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
+@@ -457,7 +457,7 @@
+ status = "okay";
+
+ bt656-supply = <&vcc_3v0>;
+- audio-supply = <&vcc_3v0>;
++ audio-supply = <&vcc1v8_codec>;
+ sdmmc-supply = <&vcc_sdio>;
+ gpio1830-supply = <&vcc_3v0>;
+ };
+diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
+index e8a41d09b45f2..874cba75e9a5a 100644
+--- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
++++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
+@@ -606,10 +606,10 @@
+ clock-names = "fck";
+ #address-cells = <3>;
+ #size-cells = <2>;
+- bus-range = <0x0 0xf>;
++ bus-range = <0x0 0xff>;
+ cdns,no-bar-match-nbits = <64>;
+- vendor-id = /bits/ 16 <0x104c>;
+- device-id = /bits/ 16 <0xb00f>;
++ vendor-id = <0x104c>;
++ device-id = <0xb00f>;
+ msi-map = <0x0 &gic_its 0x0 0x10000>;
+ dma-coherent;
+ ranges = <0x01000000 0x0 0x18001000 0x00 0x18001000 0x0 0x0010000>,
+diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
+index cf3482376c1e6..08c8d1b47dcd9 100644
+--- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
++++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
+@@ -610,7 +610,7 @@
+ clock-names = "fck";
+ #address-cells = <3>;
+ #size-cells = <2>;
+- bus-range = <0x0 0xf>;
++ bus-range = <0x0 0xff>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x0 0x10000>;
+@@ -636,7 +636,7 @@
+ clocks = <&k3_clks 239 1>;
+ clock-names = "fck";
+ max-functions = /bits/ 8 <6>;
+- max-virtual-functions = /bits/ 16 <4 4 4 4 0 0>;
++ max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>;
+ dma-coherent;
+ };
+
+@@ -658,7 +658,7 @@
+ clock-names = "fck";
+ #address-cells = <3>;
+ #size-cells = <2>;
+- bus-range = <0x0 0xf>;
++ bus-range = <0x0 0xff>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x10000 0x10000>;
+@@ -684,7 +684,7 @@
+ clocks = <&k3_clks 240 1>;
+ clock-names = "fck";
+ max-functions = /bits/ 8 <6>;
+- max-virtual-functions = /bits/ 16 <4 4 4 4 0 0>;
++ max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>;
+ dma-coherent;
+ };
+
+@@ -706,7 +706,7 @@
+ clock-names = "fck";
+ #address-cells = <3>;
+ #size-cells = <2>;
+- bus-range = <0x0 0xf>;
++ bus-range = <0x0 0xff>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x20000 0x10000>;
+@@ -732,7 +732,7 @@
+ clocks = <&k3_clks 241 1>;
+ clock-names = "fck";
+ max-functions = /bits/ 8 <6>;
+- max-virtual-functions = /bits/ 16 <4 4 4 4 0 0>;
++ max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>;
+ dma-coherent;
+ };
+
+@@ -754,7 +754,7 @@
+ clock-names = "fck";
+ #address-cells = <3>;
+ #size-cells = <2>;
+- bus-range = <0x0 0xf>;
++ bus-range = <0x0 0xff>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x30000 0x10000>;
+@@ -780,7 +780,7 @@
+ clocks = <&k3_clks 242 1>;
+ clock-names = "fck";
+ max-functions = /bits/ 8 <6>;
+- max-virtual-functions = /bits/ 16 <4 4 4 4 0 0>;
++ max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>;
+ dma-coherent;
+ #address-cells = <2>;
+ #size-cells = <2>;
+diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
+index 4a86efa32d687..f7124e15f0ff6 100644
+--- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
++++ b/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>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+index 28dccb891a535..8278876ad33fa 100644
+--- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
++++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+@@ -792,7 +792,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>;
+@@ -802,7 +802,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>;
+diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
+index 29f97eb3dad41..8f59bbeba7a7e 100644
+--- a/arch/arm64/include/asm/esr.h
++++ b/arch/arm64/include/asm/esr.h
+@@ -68,6 +68,7 @@
+ #define ESR_ELx_EC_MAX (0x3F)
+
+ #define ESR_ELx_EC_SHIFT (26)
++#define ESR_ELx_EC_WIDTH (6)
+ #define ESR_ELx_EC_MASK (UL(0x3F) << ESR_ELx_EC_SHIFT)
+ #define ESR_ELx_EC(esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)
+
+diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
+index 327120c0089fe..f67a561e0935e 100644
+--- a/arch/arm64/include/asm/kvm_arm.h
++++ b/arch/arm64/include/asm/kvm_arm.h
+@@ -91,7 +91,7 @@
+ #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
+
+ /* TCR_EL2 Registers bits */
+-#define TCR_EL2_RES1 ((1 << 31) | (1 << 23))
++#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
+ #define TCR_EL2_TBI (1 << 20)
+ #define TCR_EL2_PS_SHIFT 16
+ #define TCR_EL2_PS_MASK (7 << TCR_EL2_PS_SHIFT)
+@@ -276,7 +276,7 @@
+ #define CPTR_EL2_TFP_SHIFT 10
+
+ /* Hyp Coprocessor Trap Register */
+-#define CPTR_EL2_TCPAC (1 << 31)
++#define CPTR_EL2_TCPAC (1U << 31)
+ #define CPTR_EL2_TAM (1 << 30)
+ #define CPTR_EL2_TTA (1 << 20)
+ #define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT)
+diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
+index 8433a2058eb15..237224484d0f6 100644
+--- a/arch/arm64/include/asm/pgalloc.h
++++ b/arch/arm64/include/asm/pgalloc.h
+@@ -76,7 +76,7 @@ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
+ static inline void
+ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
+ {
+- VM_BUG_ON(mm != &init_mm);
++ VM_BUG_ON(mm && mm != &init_mm);
+ __pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE | PMD_TABLE_UXN);
+ }
+
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index dfa76afa0ccff..72f95c6a70519 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -67,9 +67,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+ * 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)
+diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
+index 190b494e22ab9..0fd6056ba412b 100644
+--- a/arch/arm64/include/asm/uaccess.h
++++ b/arch/arm64/include/asm/uaccess.h
+@@ -292,12 +292,22 @@ do { \
+ (x) = (__force __typeof__(*(ptr)))__gu_val; \
+ } while (0)
+
++/*
++ * We must not call into the scheduler between uaccess_ttbr0_enable() and
++ * uaccess_ttbr0_disable(). As `x` and `ptr` could contain blocking functions,
++ * we must evaluate these outside of the critical section.
++ */
+ #define __raw_get_user(x, ptr, err) \
+ do { \
++ __typeof__(*(ptr)) __user *__rgu_ptr = (ptr); \
++ __typeof__(x) __rgu_val; \
+ __chk_user_ptr(ptr); \
++ \
+ uaccess_ttbr0_enable(); \
+- __raw_get_mem("ldtr", x, ptr, err); \
++ __raw_get_mem("ldtr", __rgu_val, __rgu_ptr, err); \
+ uaccess_ttbr0_disable(); \
++ \
++ (x) = __rgu_val; \
+ } while (0)
+
+ #define __get_user_error(x, ptr, err) \
+@@ -321,14 +331,22 @@ do { \
+
+ #define get_user __get_user
+
++/*
++ * We must not call into the scheduler between __uaccess_enable_tco_async() and
++ * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking
++ * functions, we must evaluate these outside of the critical section.
++ */
+ #define __get_kernel_nofault(dst, src, type, err_label) \
+ do { \
++ __typeof__(dst) __gkn_dst = (dst); \
++ __typeof__(src) __gkn_src = (src); \
+ int __gkn_err = 0; \
+ \
+ __uaccess_enable_tco_async(); \
+- __raw_get_mem("ldr", *((type *)(dst)), \
+- (__force type *)(src), __gkn_err); \
++ __raw_get_mem("ldr", *((type *)(__gkn_dst)), \
++ (__force type *)(__gkn_src), __gkn_err); \
+ __uaccess_disable_tco_async(); \
++ \
+ if (unlikely(__gkn_err)) \
+ goto err_label; \
+ } while (0)
+@@ -367,11 +385,19 @@ do { \
+ } \
+ } while (0)
+
++/*
++ * We must not call into the scheduler between uaccess_ttbr0_enable() and
++ * uaccess_ttbr0_disable(). As `x` and `ptr` could contain blocking functions,
++ * we must evaluate these outside of the critical section.
++ */
+ #define __raw_put_user(x, ptr, err) \
+ do { \
+- __chk_user_ptr(ptr); \
++ __typeof__(*(ptr)) __user *__rpu_ptr = (ptr); \
++ __typeof__(*(ptr)) __rpu_val = (x); \
++ __chk_user_ptr(__rpu_ptr); \
++ \
+ uaccess_ttbr0_enable(); \
+- __raw_put_mem("sttr", x, ptr, err); \
++ __raw_put_mem("sttr", __rpu_val, __rpu_ptr, err); \
+ uaccess_ttbr0_disable(); \
+ } while (0)
+
+@@ -396,14 +422,22 @@ do { \
+
+ #define put_user __put_user
+
++/*
++ * We must not call into the scheduler between __uaccess_enable_tco_async() and
++ * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking
++ * functions, we must evaluate these outside of the critical section.
++ */
+ #define __put_kernel_nofault(dst, src, type, err_label) \
+ do { \
++ __typeof__(dst) __pkn_dst = (dst); \
++ __typeof__(src) __pkn_src = (src); \
+ int __pkn_err = 0; \
+ \
+ __uaccess_enable_tco_async(); \
+- __raw_put_mem("str", *((type *)(src)), \
+- (__force type *)(dst), __pkn_err); \
++ __raw_put_mem("str", *((type *)(__pkn_src)), \
++ (__force type *)(__pkn_dst), __pkn_err); \
+ __uaccess_disable_tco_async(); \
++ \
+ if (unlikely(__pkn_err)) \
+ goto err_label; \
+ } while(0)
+diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
+index 6ec7036ef7e18..7553c98f379fc 100644
+--- a/arch/arm64/kernel/cpufeature.c
++++ b/arch/arm64/kernel/cpufeature.c
+@@ -573,15 +573,19 @@ static const struct arm64_ftr_bits ftr_raz[] = {
+ ARM64_FTR_END,
+ };
+
+-#define ARM64_FTR_REG_OVERRIDE(id, table, ovr) { \
++#define __ARM64_FTR_REG_OVERRIDE(id_str, id, table, ovr) { \
+ .sys_id = id, \
+ .reg = &(struct arm64_ftr_reg){ \
+- .name = #id, \
++ .name = id_str, \
+ .override = (ovr), \
+ .ftr_bits = &((table)[0]), \
+ }}
+
+-#define ARM64_FTR_REG(id, table) ARM64_FTR_REG_OVERRIDE(id, table, &no_override)
++#define ARM64_FTR_REG_OVERRIDE(id, table, ovr) \
++ __ARM64_FTR_REG_OVERRIDE(#id, id, table, ovr)
++
++#define ARM64_FTR_REG(id, table) \
++ __ARM64_FTR_REG_OVERRIDE(#id, id, table, &no_override)
+
+ struct arm64_ftr_override __ro_after_init id_aa64mmfr1_override;
+ struct arm64_ftr_override __ro_after_init id_aa64pfr1_override;
+diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
+index b3e4f9a088b1a..8cf970d219f5d 100644
+--- a/arch/arm64/kernel/entry-ftrace.S
++++ b/arch/arm64/kernel/entry-ftrace.S
+@@ -77,11 +77,17 @@
+ .endm
+
+ SYM_CODE_START(ftrace_regs_caller)
++#ifdef BTI_C
++ BTI_C
++#endif
+ ftrace_regs_entry 1
+ b ftrace_common
+ SYM_CODE_END(ftrace_regs_caller)
+
+ SYM_CODE_START(ftrace_caller)
++#ifdef BTI_C
++ BTI_C
++#endif
+ ftrace_regs_entry 0
+ b ftrace_common
+ SYM_CODE_END(ftrace_caller)
+diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
+index 63634b4d72c15..59c648d518488 100644
+--- a/arch/arm64/kernel/machine_kexec_file.c
++++ b/arch/arm64/kernel/machine_kexec_file.c
+@@ -149,6 +149,7 @@ int load_other_segments(struct kimage *image,
+ initrd_len, cmdline, 0);
+ if (!dtb) {
+ pr_err("Preparing for new dtb failed\n");
++ ret = -EINVAL;
+ goto out_err;
+ }
+
+diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
+index 3dba0c4f8f42b..764d1900d5aab 100644
+--- a/arch/arm64/kernel/vdso32/Makefile
++++ b/arch/arm64/kernel/vdso32/Makefile
+@@ -40,7 +40,8 @@ cc32-as-instr = $(call try-run,\
+ # As a result we set our own flags here.
+
+ # KBUILD_CPPFLAGS and NOSTDINC_FLAGS from top-level Makefile
+-VDSO_CPPFLAGS := -DBUILD_VDSO -D__KERNEL__ -nostdinc -isystem $(shell $(CC_COMPAT) -print-file-name=include)
++VDSO_CPPFLAGS := -DBUILD_VDSO -D__KERNEL__ -nostdinc
++VDSO_CPPFLAGS += -isystem $(shell $(CC_COMPAT) -print-file-name=include 2>/dev/null)
+ VDSO_CPPFLAGS += $(LINUXINCLUDE)
+
+ # Common C and assembly flags
+diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
+index fe102cd2e5183..9b328bb05596a 100644
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -1971,9 +1971,25 @@ out_err:
+ return err;
+ }
+
+-static void _kvm_host_prot_finalize(void *discard)
++static void _kvm_host_prot_finalize(void *arg)
+ {
+- WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize));
++ int *err = arg;
++
++ if (WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize)))
++ WRITE_ONCE(*err, -EINVAL);
++}
++
++static int pkvm_drop_host_privileges(void)
++{
++ int ret = 0;
++
++ /*
++ * Flip the static key upfront as that may no longer be possible
++ * once the host stage 2 is installed.
++ */
++ static_branch_enable(&kvm_protected_mode_initialized);
++ on_each_cpu(_kvm_host_prot_finalize, &ret, 1);
++ return ret;
+ }
+
+ static int finalize_hyp_mode(void)
+@@ -1987,15 +2003,7 @@ static int finalize_hyp_mode(void)
+ * None of other sections should ever be introspected.
+ */
+ kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start);
+-
+- /*
+- * Flip the static key upfront as that may no longer be possible
+- * once the host stage 2 is installed.
+- */
+- static_branch_enable(&kvm_protected_mode_initialized);
+- on_each_cpu(_kvm_host_prot_finalize, NULL, 1);
+-
+- return 0;
++ return pkvm_drop_host_privileges();
+ }
+
+ struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr)
+diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
+index 9aa9b73475c95..b6b6801d96d5a 100644
+--- a/arch/arm64/kvm/hyp/hyp-entry.S
++++ b/arch/arm64/kvm/hyp/hyp-entry.S
+@@ -44,7 +44,7 @@
+ el1_sync: // Guest trapped into EL2
+
+ mrs x0, esr_el2
+- lsr x0, x0, #ESR_ELx_EC_SHIFT
++ ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH
+ cmp x0, #ESR_ELx_EC_HVC64
+ ccmp x0, #ESR_ELx_EC_HVC32, #4, ne
+ b.ne el1_trap
+diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
+index a0e78a6027be0..c75e84489f57b 100644
+--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
++++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
+@@ -416,6 +416,12 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
+ */
+ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
+ {
++ /*
++ * Save PSTATE early so that we can evaluate the vcpu mode
++ * early on.
++ */
++ vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
++
+ if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
+ vcpu->arch.fault.esr_el2 = read_sysreg_el2(SYS_ESR);
+
+diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+index de7e14c862e6c..7ecca8b078519 100644
+--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
++++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+@@ -70,7 +70,12 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
+ static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
+ {
+ ctxt->regs.pc = read_sysreg_el2(SYS_ELR);
+- ctxt->regs.pstate = read_sysreg_el2(SYS_SPSR);
++ /*
++ * Guest PSTATE gets saved at guest fixup time in all
++ * cases. We still need to handle the nVHE host side here.
++ */
++ if (!has_vhe() && ctxt->__hyp_running_vcpu)
++ ctxt->regs.pstate = read_sysreg_el2(SYS_SPSR);
+
+ if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN))
+ ctxt_sys_reg(ctxt, DISR_EL1) = read_sysreg_s(SYS_VDISR_EL2);
+diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S
+index 4b652ffb591d4..d310d2b2c8b40 100644
+--- a/arch/arm64/kvm/hyp/nvhe/host.S
++++ b/arch/arm64/kvm/hyp/nvhe/host.S
+@@ -115,7 +115,7 @@ SYM_FUNC_END(__hyp_do_panic)
+ .L__vect_start\@:
+ stp x0, x1, [sp, #-16]!
+ mrs x0, esr_el2
+- lsr x0, x0, #ESR_ELx_EC_SHIFT
++ ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH
+ cmp x0, #ESR_ELx_EC_HVC64
+ b.ne __host_exit
+
+diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
+index 57c27846320f4..58ad9c5ba3112 100644
+--- a/arch/arm64/kvm/hyp/nvhe/setup.c
++++ b/arch/arm64/kvm/hyp/nvhe/setup.c
+@@ -177,7 +177,7 @@ static int finalize_host_mappings_walker(u64 addr, u64 end, u32 level,
+
+ phys = kvm_pte_to_phys(pte);
+ if (!addr_is_memory(phys))
+- return 0;
++ return -EINVAL;
+
+ /*
+ * Adjust the host stage-2 mappings to match the ownership attributes
+@@ -206,8 +206,18 @@ static int finalize_host_mappings(void)
+ .cb = finalize_host_mappings_walker,
+ .flags = KVM_PGTABLE_WALK_LEAF,
+ };
++ int i, ret;
++
++ for (i = 0; i < hyp_memblock_nr; i++) {
++ struct memblock_region *reg = &hyp_memory[i];
++ u64 start = (u64)hyp_phys_to_virt(reg->base);
++
++ ret = kvm_pgtable_walk(&pkvm_pgtable, start, reg->size, &walker);
++ if (ret)
++ return ret;
++ }
+
+- return kvm_pgtable_walk(&pkvm_pgtable, 0, BIT(pkvm_pgtable.ia_bits), &walker);
++ return 0;
+ }
+
+ void __noreturn __pkvm_init_finalise(void)
+diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
+index cfd9deb347c38..fd85b51b9d50f 100644
+--- a/arch/arm64/mm/mmu.c
++++ b/arch/arm64/mm/mmu.c
+@@ -1499,6 +1499,11 @@ int arch_add_memory(int nid, u64 start, u64 size,
+ if (ret)
+ __remove_pgd_mapping(swapper_pg_dir,
+ __phys_to_virt(start), size);
++ else {
++ max_pfn = PFN_UP(start + size);
++ max_low_pfn = max_pfn;
++ }
++
+ return ret;
+ }
+
+diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c
+index e5fbf8653a215..2020af88b6361 100644
+--- a/arch/csky/kernel/traps.c
++++ b/arch/csky/kernel/traps.c
+@@ -209,7 +209,7 @@ asmlinkage void do_trap_illinsn(struct pt_regs *regs)
+
+ asmlinkage void do_trap_fpe(struct pt_regs *regs)
+ {
+-#ifdef CONFIG_CPU_HAS_FP
++#ifdef CONFIG_CPU_HAS_FPU
+ return fpu_fpe(regs);
+ #else
+ do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc,
+@@ -219,7 +219,7 @@ asmlinkage void do_trap_fpe(struct pt_regs *regs)
+
+ asmlinkage void do_trap_priv(struct pt_regs *regs)
+ {
+-#ifdef CONFIG_CPU_HAS_FP
++#ifdef CONFIG_CPU_HAS_FPU
+ if (user_mode(regs) && fpu_libc_helper(regs))
+ return;
+ #endif
+diff --git a/arch/hexagon/include/asm/timer-regs.h b/arch/hexagon/include/asm/timer-regs.h
+deleted file mode 100644
+index ee6c61423a058..0000000000000
+--- a/arch/hexagon/include/asm/timer-regs.h
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-only */
+-/*
+- * Timer support for Hexagon
+- *
+- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+- */
+-
+-#ifndef _ASM_TIMER_REGS_H
+-#define _ASM_TIMER_REGS_H
+-
+-/* This stuff should go into a platform specific file */
+-#define TCX0_CLK_RATE 19200
+-#define TIMER_ENABLE 0
+-#define TIMER_CLR_ON_MATCH 1
+-
+-/*
+- * 8x50 HDD Specs 5-8. Simulator co-sim not fixed until
+- * release 1.1, and then it's "adjustable" and probably not defaulted.
+- */
+-#define RTOS_TIMER_INT 3
+-#ifdef CONFIG_HEXAGON_COMET
+-#define RTOS_TIMER_REGS_ADDR 0xAB000000UL
+-#endif
+-#define SLEEP_CLK_RATE 32000
+-
+-#endif
+diff --git a/arch/hexagon/include/asm/timex.h b/arch/hexagon/include/asm/timex.h
+index 8d4ec76fceb45..dfe69e118b2be 100644
+--- a/arch/hexagon/include/asm/timex.h
++++ b/arch/hexagon/include/asm/timex.h
+@@ -7,11 +7,10 @@
+ #define _ASM_TIMEX_H
+
+ #include <asm-generic/timex.h>
+-#include <asm/timer-regs.h>
+ #include <asm/hexagon_vm.h>
+
+ /* Using TCX0 as our clock. CLOCK_TICK_RATE scheduled to be removed. */
+-#define CLOCK_TICK_RATE TCX0_CLK_RATE
++#define CLOCK_TICK_RATE 19200
+
+ #define ARCH_HAS_READ_CURRENT_TIMER
+
+diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c
+index feffe527ac929..febc95714d756 100644
+--- a/arch/hexagon/kernel/time.c
++++ b/arch/hexagon/kernel/time.c
+@@ -17,9 +17,10 @@
+ #include <linux/of_irq.h>
+ #include <linux/module.h>
+
+-#include <asm/timer-regs.h>
+ #include <asm/hexagon_vm.h>
+
++#define TIMER_ENABLE BIT(0)
++
+ /*
+ * For the clocksource we need:
+ * pcycle frequency (600MHz)
+@@ -33,6 +34,13 @@ cycles_t pcycle_freq_mhz;
+ cycles_t thread_freq_mhz;
+ cycles_t sleep_clk_freq;
+
++/*
++ * 8x50 HDD Specs 5-8. Simulator co-sim not fixed until
++ * release 1.1, and then it's "adjustable" and probably not defaulted.
++ */
++#define RTOS_TIMER_INT 3
++#define RTOS_TIMER_REGS_ADDR 0xAB000000UL
++
+ static struct resource rtos_timer_resources[] = {
+ {
+ .start = RTOS_TIMER_REGS_ADDR,
+@@ -80,7 +88,7 @@ static int set_next_event(unsigned long delta, struct clock_event_device *evt)
+ iowrite32(0, &rtos_timer->clear);
+
+ iowrite32(delta, &rtos_timer->match);
+- iowrite32(1 << TIMER_ENABLE, &rtos_timer->enable);
++ iowrite32(TIMER_ENABLE, &rtos_timer->enable);
+ return 0;
+ }
+
+diff --git a/arch/hexagon/lib/io.c b/arch/hexagon/lib/io.c
+index d35d69d6588c4..55f75392857b0 100644
+--- a/arch/hexagon/lib/io.c
++++ b/arch/hexagon/lib/io.c
+@@ -27,6 +27,7 @@ void __raw_readsw(const void __iomem *addr, void *data, int len)
+ *dst++ = *src;
+
+ }
++EXPORT_SYMBOL(__raw_readsw);
+
+ /*
+ * __raw_writesw - read words a short at a time
+@@ -47,6 +48,7 @@ void __raw_writesw(void __iomem *addr, const void *data, int len)
+
+
+ }
++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 @@ void __raw_readsl(const void __iomem *addr, void *data, int len)
+
+
+ }
++EXPORT_SYMBOL(__raw_readsl);
+
+ void __raw_writesl(void __iomem *addr, const void *data, int len)
+ {
+@@ -76,3 +79,4 @@ void __raw_writesl(void __iomem *addr, const void *data, int len)
+
+
+ }
++EXPORT_SYMBOL(__raw_writesl);
+diff --git a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug
+index 40ca23bd228d6..2ce008e2d1644 100644
+--- a/arch/ia64/Kconfig.debug
++++ b/arch/ia64/Kconfig.debug
+@@ -39,7 +39,7 @@ config DISABLE_VHPT
+
+ 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
+diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
+index 441ed04b10378..d4048518a1d7d 100644
+--- a/arch/ia64/kernel/kprobes.c
++++ b/arch/ia64/kernel/kprobes.c
+@@ -398,7 +398,8 @@ static void kretprobe_trampoline(void)
+
+ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+ {
+- regs->cr_iip = __kretprobe_trampoline_handler(regs, kretprobe_trampoline, NULL);
++ regs->cr_iip = __kretprobe_trampoline_handler(regs,
++ dereference_function_descriptor(kretprobe_trampoline), NULL);
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+@@ -414,7 +415,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ ri->fp = NULL;
+
+ /* 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 */
+@@ -902,14 +903,14 @@ static struct kprobe trampoline_p = {
+ 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;
+diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine
+index 36fa0c3ef1296..eeab4f3e6c197 100644
+--- a/arch/m68k/Kconfig.machine
++++ b/arch/m68k/Kconfig.machine
+@@ -203,6 +203,7 @@ config INIT_LCD
+ config MEMORY_RESERVE
+ int "Memory reservation (MiB)"
+ depends on (UCSIMM || UCDIMM)
++ default 0
+ help
+ Reserve certain memory regions on 68x328 based boards.
+
+diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
+index 9718ce94cc845..34d6458340b0f 100644
+--- a/arch/m68k/kernel/traps.c
++++ b/arch/m68k/kernel/traps.c
+@@ -1145,7 +1145,7 @@ asmlinkage void set_esp0(unsigned long ssp)
+ */
+ asmlinkage void fpsp040_die(void)
+ {
+- force_sigsegv(SIGSEGV);
++ force_exit_sig(SIGSEGV);
+ }
+
+ #ifdef CONFIG_M68KFPU_EMU
+diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
+index 584081df89c28..6e3f36c841e5d 100644
+--- a/arch/mips/Kbuild.platforms
++++ b/arch/mips/Kbuild.platforms
+@@ -38,4 +38,4 @@ platform-$(CONFIG_MACH_TX49XX) += txx9/
+ platform-$(CONFIG_MACH_VR41XX) += vr41xx/
+
+ # include the platform specific files
+-include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platform-y))
++include $(patsubst %/, $(srctree)/arch/mips/%/Platform, $(platform-y))
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index 6b8f591c5054c..23654ccdbfb12 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -332,6 +332,9 @@ config BCM63XX
+ 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 MIPS_L1_CACHE_SHIFT_4
+@@ -1379,6 +1382,7 @@ config CPU_LOONGSON64
+ select MIPS_ASID_BITS_VARIABLE
+ select MIPS_PGD_C0_CONTEXT
+ select MIPS_L1_CACHE_SHIFT_6
++ select MIPS_FP_SUPPORT
+ select GPIOLIB
+ select SWIOTLB
+ select HAVE_KVM
+@@ -3185,7 +3189,7 @@ config STACKTRACE_SUPPORT
+ 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
+diff --git a/arch/mips/Makefile b/arch/mips/Makefile
+index ea3cd080a1c7d..f7b58da2f3889 100644
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -254,7 +254,9 @@ endif
+ #
+ # Board-dependent options and extra files
+ #
++ifdef need-compiler
+ include $(srctree)/arch/mips/Kbuild.platforms
++endif
+
+ ifdef CONFIG_PHYSICAL_START
+ load-y = $(CONFIG_PHYSICAL_START)
+diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
+index 5a3e325275d0d..1c91064cb448b 100644
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -381,6 +381,12 @@ void clk_disable(struct clk *clk)
+
+ EXPORT_SYMBOL(clk_disable);
+
++struct clk *clk_get_parent(struct clk *clk)
++{
++ return NULL;
++}
++EXPORT_SYMBOL(clk_get_parent);
++
+ unsigned long clk_get_rate(struct clk *clk)
+ {
+ if (!clk)
+diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
+index 3548b3b452699..9112bdb86be45 100644
+--- a/arch/mips/boot/compressed/Makefile
++++ b/arch/mips/boot/compressed/Makefile
+@@ -56,6 +56,8 @@ $(obj)/uart-ath79.c: $(srctree)/arch/mips/ath79/early_printk.c
+
+ vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o
+
++vmlinuzobjs-$(CONFIG_KERNEL_ZSTD) += $(obj)/bswapdi.o
++
+ extra-y += ashldi3.c
+ $(obj)/ashldi3.c: $(obj)/%.c: $(srctree)/lib/%.c FORCE
+ $(call if_changed,shipped)
+@@ -64,6 +66,10 @@ extra-y += bswapsi.c
+ $(obj)/bswapsi.c: $(obj)/%.c: $(srctree)/arch/mips/lib/%.c FORCE
+ $(call if_changed,shipped)
+
++extra-y += bswapdi.c
++$(obj)/bswapdi.c: $(obj)/%.c: $(srctree)/arch/mips/lib/%.c FORCE
++ $(call if_changed,shipped)
++
+ targets := $(notdir $(vmlinuzobjs-y))
+
+ targets += vmlinux.bin
+diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c
+index a3aa22c77cadc..a07a5edbcda78 100644
+--- a/arch/mips/generic/yamon-dt.c
++++ b/arch/mips/generic/yamon-dt.c
+@@ -75,7 +75,7 @@ static unsigned int __init gen_fdt_mem_array(
+ __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;
+diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
+index 0b983800f48b7..66a8b293fd80b 100644
+--- a/arch/mips/include/asm/cmpxchg.h
++++ b/arch/mips/include/asm/cmpxchg.h
+@@ -249,6 +249,7 @@ static inline unsigned long __cmpxchg64(volatile void *ptr,
+ /* Load 64 bits from ptr */
+ " " __SYNC(full, loongson3_war) " \n"
+ "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.
+@@ -276,12 +277,14 @@ static inline unsigned long __cmpxchg64(volatile void *ptr,
+ " 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! */
+ "\t" __SC_BEQZ "%L1, 1b \n"
+- " .set pop \n"
+ "2: " __SYNC(full, loongson3_war) " \n"
++ " .set pop \n"
+ : "=&r"(ret),
+ "=&r"(tmp),
+ "=" GCC_OFF_SMALL_ASM() (*(unsigned long long *)ptr)
+diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
+index aeae2effa123d..23c67c0871b17 100644
+--- a/arch/mips/include/asm/mips-cm.h
++++ b/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 @@ GCR_ACCESSOR_RO(32, 0x030, rev)
+ #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 int mips_cm_revision(void)
+ 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 @@ static inline unsigned int mips_cm_max_vp_width(void)
+ * 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))
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index 630fcb4cb30e7..7c861e6a89529 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -1734,8 +1734,6 @@ static inline void decode_cpucfg(struct cpuinfo_mips *c)
+
+ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
+ {
+- decode_configs(c);
+-
+ /* All Loongson processors covered here define ExcCode 16 as GSExc. */
+ c->options |= MIPS_CPU_GSEXCEX;
+
+@@ -1796,6 +1794,8 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
+ panic("Unknown Loongson Processor ID!");
+ break;
+ }
++
++ decode_configs(c);
+ }
+ #else
+ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { }
+diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
+index 90f1c3df1f0e4..b4f7d950c8468 100644
+--- a/arch/mips/kernel/mips-cm.c
++++ b/arch/mips/kernel/mips-cm.c
+@@ -221,8 +221,7 @@ static void mips_cm_probe_l2sync(void)
+ 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;
+
+@@ -306,13 +305,13 @@ void mips_cm_lock_other(unsigned int cluster, unsigned int core,
+ 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);
+@@ -342,7 +341,7 @@ void mips_cm_lock_other(unsigned int cluster, unsigned int core,
+ 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);
+@@ -386,8 +385,8 @@ void mips_cm_error_report(void)
+ 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;
+@@ -445,8 +444,8 @@ void mips_cm_error_report(void)
+ 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;
+diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S
+index 12e58053544fc..cbf6db98cfb38 100644
+--- a/arch/mips/kernel/r2300_fpu.S
++++ b/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
+diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
+index 2afa3eef486a9..5512cd586e6e8 100644
+--- a/arch/mips/kernel/syscall.c
++++ b/arch/mips/kernel/syscall.c
+@@ -240,12 +240,3 @@ SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
+ {
+ 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);
+-}
+diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
+index dd819e31fcbbf..4916cccf378fd 100644
+--- a/arch/mips/lantiq/clk.c
++++ b/arch/mips/lantiq/clk.c
+@@ -158,6 +158,12 @@ void clk_deactivate(struct clk *clk)
+ }
+ EXPORT_SYMBOL(clk_deactivate);
+
++struct clk *clk_get_parent(struct clk *clk)
++{
++ return NULL;
++}
++EXPORT_SYMBOL(clk_get_parent);
++
+ static inline u32 get_counter_resolution(void)
+ {
+ u32 res;
+diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
+index 63dccb2ed08b2..53fcc672a2944 100644
+--- a/arch/mips/lantiq/xway/dma.c
++++ b/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 <linux/of.h>
+
+@@ -30,6 +31,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,8 +41,11 @@
+ #define DMA_IRQ_ACK 0x7e /* IRQ status register */
+ #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_PCTRL_2W_BURST 0x1 /* 2 word burst length */
++#define DMA_PCTRL_4W_BURST 0x2 /* 4 word burst length */
++#define DMA_PCTRL_8W_BURST 0x3 /* 8 word burst length */
++#define DMA_TX_BURST_SHIFT 4 /* tx burst shift */
++#define DMA_RX_BURST_SHIFT 2 /* rx burst shift */
+ #define DMA_ETOP_ENDIANNESS (0xf << 8) /* endianness swap etop channels */
+ #define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
+
+@@ -191,7 +196,8 @@ ltq_dma_init_port(int p)
+ break;
+
+ case DMA_PORT_DEU:
+- ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
++ ltq_dma_w32((DMA_PCTRL_2W_BURST << DMA_TX_BURST_SHIFT) |
++ (DMA_PCTRL_2W_BURST << DMA_RX_BURST_SHIFT),
+ LTQ_DMA_PCTRL);
+ break;
+
+@@ -206,7 +212,7 @@ ltq_dma_init(struct platform_device *pdev)
+ {
+ struct clk *clk;
+ struct resource *res;
+- unsigned id;
++ unsigned int id, nchannels;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -222,21 +228,24 @@ ltq_dma_init(struct platform_device *pdev)
+ 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;
+ }
+diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c
+index 240bb68ec2478..ff3ba7e778901 100644
+--- a/arch/mips/sni/time.c
++++ b/arch/mips/sni/time.c
+@@ -18,14 +18,14 @@ static int a20r_set_periodic(struct clock_event_device *evt)
+ {
+ *(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();
+diff --git a/arch/openrisc/kernel/dma.c b/arch/openrisc/kernel/dma.c
+index 1b16d97e7da7f..a82b2caaa560d 100644
+--- a/arch/openrisc/kernel/dma.c
++++ b/arch/openrisc/kernel/dma.c
+@@ -33,7 +33,7 @@ page_set_nocache(pte_t *pte, unsigned long addr,
+ * Flush the page out of the TLB so that the new page flags get
+ * picked up next time there's an access
+ */
+- flush_tlb_page(NULL, addr);
++ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ /* Flush page out of dcache */
+ for (cl = __pa(addr); cl < __pa(next); cl += cpuinfo->dcache_block_size)
+@@ -56,7 +56,7 @@ page_clear_nocache(pte_t *pte, unsigned long addr,
+ * Flush the page out of the TLB so that the new page flags get
+ * picked up next time there's an access
+ */
+- flush_tlb_page(NULL, addr);
++ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ return 0;
+ }
+diff --git a/arch/openrisc/kernel/smp.c b/arch/openrisc/kernel/smp.c
+index 415e209732a3d..ba78766cf00b5 100644
+--- a/arch/openrisc/kernel/smp.c
++++ b/arch/openrisc/kernel/smp.c
+@@ -272,7 +272,7 @@ static inline void ipi_flush_tlb_range(void *info)
+ local_flush_tlb_range(NULL, fd->addr1, fd->addr2);
+ }
+
+-static void smp_flush_tlb_range(struct cpumask *cmask, unsigned long start,
++static void smp_flush_tlb_range(const struct cpumask *cmask, unsigned long start,
+ unsigned long end)
+ {
+ unsigned int cpuid;
+@@ -320,7 +320,9 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+ void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+ {
+- smp_flush_tlb_range(mm_cpumask(vma->vm_mm), start, end);
++ const struct cpumask *cmask = vma ? mm_cpumask(vma->vm_mm)
++ : cpu_online_mask;
++ smp_flush_tlb_range(cmask, start, end);
+ }
+
+ /* Instruction cache invalidate - performed on each cpu */
+diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
+index fcde3ffa02213..fadb098de1545 100644
+--- a/arch/parisc/Makefile
++++ b/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
+diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
+index 7badd872f05ac..3e7cf882639fb 100644
+--- a/arch/parisc/include/asm/pgtable.h
++++ b/arch/parisc/include/asm/pgtable.h
+@@ -76,6 +76,8 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+ purge_tlb_end(flags);
+ }
+
++extern void __update_cache(pte_t pte);
++
+ /* Certain architectures need to do special things when PTEs
+ * within a page table are directly modified. Thus, the following
+ * hook is made available.
+@@ -83,11 +85,14 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+ #define set_pte(pteptr, pteval) \
+ do { \
+ *(pteptr) = (pteval); \
+- barrier(); \
++ mb(); \
+ } while(0)
+
+ #define set_pte_at(mm, addr, pteptr, pteval) \
+ do { \
++ if (pte_present(pteval) && \
++ pte_user(pteval)) \
++ __update_cache(pteval); \
+ *(pteptr) = (pteval); \
+ purge_tlb_entries(mm, addr); \
+ } while (0)
+@@ -303,6 +308,7 @@ extern unsigned long *empty_zero_page;
+
+ #define pte_none(x) (pte_val(x) == 0)
+ #define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
++#define pte_user(x) (pte_val(x) & _PAGE_USER)
+ #define pte_clear(mm, addr, xp) set_pte_at(mm, addr, xp, __pte(0))
+
+ #define pmd_flag(x) (pmd_val(x) & PxD_FLAG_MASK)
+@@ -410,7 +416,7 @@ extern void paging_init (void);
+
+ #define PG_dcache_dirty PG_arch_1
+
+-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
++#define update_mmu_cache(vms,addr,ptep) __update_cache(*ptep)
+
+ /* Encode and de-code a swap entry */
+
+diff --git a/arch/parisc/include/asm/rt_sigframe.h b/arch/parisc/include/asm/rt_sigframe.h
+index 4b9e3d707571b..2b3010ade00e7 100644
+--- a/arch/parisc/include/asm/rt_sigframe.h
++++ b/arch/parisc/include/asm/rt_sigframe.h
+@@ -2,7 +2,7 @@
+ #ifndef _ASM_PARISC_RT_SIGFRAME_H
+ #define _ASM_PARISC_RT_SIGFRAME_H
+
+-#define SIGRETURN_TRAMP 3
++#define SIGRETURN_TRAMP 4
+ #define SIGRESTARTBLOCK_TRAMP 5
+ #define TRAMP_SIZE (SIGRETURN_TRAMP + SIGRESTARTBLOCK_TRAMP)
+
+diff --git a/arch/parisc/install.sh b/arch/parisc/install.sh
+index 056d588befdd6..70d3cffb02515 100644
+--- a/arch/parisc/install.sh
++++ b/arch/parisc/install.sh
+@@ -39,6 +39,7 @@ verify "$3"
+ 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
+diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
+index 39e02227e2310..4ed4942d8312b 100644
+--- a/arch/parisc/kernel/cache.c
++++ b/arch/parisc/kernel/cache.c
+@@ -83,9 +83,9 @@ EXPORT_SYMBOL(flush_cache_all_local);
+ #define pfn_va(pfn) __va(PFN_PHYS(pfn))
+
+ void
+-update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
++__update_cache(pte_t pte)
+ {
+- unsigned long pfn = pte_pfn(*ptep);
++ unsigned long pfn = pte_pfn(pte);
+ struct page *page;
+
+ /* We don't have pte special. As a result, we can be called with
+diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
+index 9f939afe6b88c..437c8d31f3907 100644
+--- a/arch/parisc/kernel/entry.S
++++ b/arch/parisc/kernel/entry.S
+@@ -1834,8 +1834,8 @@ syscall_restore:
+ 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
+
+diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
+index bbfe23c40c016..0fb06d87b3a5c 100644
+--- a/arch/parisc/kernel/signal.c
++++ b/arch/parisc/kernel/signal.c
+@@ -288,21 +288,22 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
+ already in userspace. The first words of tramp are used to
+ save the previous sigrestartblock trampoline that might be
+ on the stack. We start the sigreturn trampoline at
+- SIGRESTARTBLOCK_TRAMP. */
++ SIGRESTARTBLOCK_TRAMP+X. */
+ err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,
+ &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]);
+- err |= __put_user(INSN_BLE_SR2_R0,
+- &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]);
+ err |= __put_user(INSN_LDI_R20,
++ &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]);
++ err |= __put_user(INSN_BLE_SR2_R0,
+ &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]);
++ err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]);
+
+- start = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP+0];
+- end = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP+3];
++ start = (unsigned long) &frame->tramp[0];
++ end = (unsigned long) &frame->tramp[TRAMP_SIZE];
+ flush_user_dcache_range_asm(start, end);
+ flush_user_icache_range_asm(start, end);
+
+ /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP
+- * TRAMP Words 5-7, Length 3 = SIGRETURN_TRAMP
++ * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP
+ * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP
+ */
+ rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP];
+diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
+index a5bdbb5678b72..f166250f2d064 100644
+--- a/arch/parisc/kernel/signal32.h
++++ b/arch/parisc/kernel/signal32.h
+@@ -36,7 +36,7 @@ struct compat_regfile {
+ compat_int_t rf_sar;
+ };
+
+-#define COMPAT_SIGRETURN_TRAMP 3
++#define COMPAT_SIGRETURN_TRAMP 4
+ #define COMPAT_SIGRESTARTBLOCK_TRAMP 5
+ #define COMPAT_TRAMP_SIZE (COMPAT_SIGRETURN_TRAMP + \
+ COMPAT_SIGRESTARTBLOCK_TRAMP)
+diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
+index 1405b603b91b6..cf92ece20b757 100644
+--- a/arch/parisc/kernel/smp.c
++++ b/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>
+@@ -69,7 +70,10 @@ enum ipi_message_type {
+ IPI_CALL_FUNC,
+ IPI_CPU_START,
+ IPI_CPU_STOP,
+- IPI_CPU_TEST
++ IPI_CPU_TEST,
++#ifdef CONFIG_KGDB
++ IPI_ENTER_KGDB,
++#endif
+ };
+
+
+@@ -167,7 +171,12 @@ ipi_interrupt(int irq, void *dev_id)
+ 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);
+@@ -226,6 +235,12 @@ send_IPI_allbutself(enum ipi_message_type op)
+ }
+ }
+
++#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); }
+diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
+index 9fb1e794831b0..061119a56fbe8 100644
+--- a/arch/parisc/kernel/time.c
++++ b/arch/parisc/kernel/time.c
+@@ -249,30 +249,16 @@ void __init time_init(void)
+ 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;
+-
+- /* mark sched_clock unstable */
+- clear_sched_clock_stable();
+-
+- clocksource_cr16.name = "cr16_unstable";
+- clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
+- clocksource_cr16.rating = 0;
+- break;
+- }
++ /* mark sched_clock unstable */
++ clear_sched_clock_stable();
++
++ clocksource_cr16.name = "cr16_unstable";
++ clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
++ clocksource_cr16.rating = 0;
+ }
+
+ /* register at clocksource framework */
+diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
+index 87ae476d1c4f5..86a57fb0e6fae 100644
+--- a/arch/parisc/kernel/unwind.c
++++ b/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 @@ int __init unwind_init(void)
+ 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 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
+ 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 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
+ 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 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
+ 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;
+ }
+
+diff --git a/arch/parisc/mm/fixmap.c b/arch/parisc/mm/fixmap.c
+index 24426a7e1a5e5..cc15d737fda64 100644
+--- a/arch/parisc/mm/fixmap.c
++++ b/arch/parisc/mm/fixmap.c
+@@ -20,12 +20,9 @@ void notrace set_fixmap(enum fixed_addresses idx, phys_addr_t phys)
+ pte_t *pte;
+
+ if (pmd_none(*pmd))
+- pmd = pmd_alloc(NULL, pud, 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);
+ }
+diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
+index 3f7d6d5b56ac8..65f50f072a87b 100644
+--- a/arch/parisc/mm/init.c
++++ b/arch/parisc/mm/init.c
+@@ -842,9 +842,9 @@ void flush_tlb_all(void)
+ {
+ 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);
+@@ -863,8 +863,8 @@ void flush_tlb_all(void)
+ #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);
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index ba5b661893588..6b9f523882c58 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -138,7 +138,7 @@ config PPC
+ select ARCH_HAS_PTE_SPECIAL
+ select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
+ select ARCH_HAS_SET_MEMORY
+- select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !HIBERNATION)
++ select ARCH_HAS_STRICT_KERNEL_RWX if (PPC_BOOK3S || PPC_8xx || 40x) && !HIBERNATION
+ select ARCH_HAS_STRICT_MODULE_RWX if ARCH_HAS_STRICT_KERNEL_RWX && !PPC_BOOK3S_32
+ select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+ select ARCH_HAS_UACCESS_FLUSHCACHE
+@@ -150,7 +150,7 @@ config PPC
+ select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
+ select ARCH_STACKWALK
+ select ARCH_SUPPORTS_ATOMIC_RMW
+- select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC32 || PPC_BOOK3S_64
++ select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx || 40x
+ select ARCH_USE_BUILTIN_BSWAP
+ select ARCH_USE_CMPXCHG_LOCKREF if PPC64
+ select ARCH_USE_MEMTEST
+@@ -190,7 +190,7 @@ config PPC
+ select HAVE_ARCH_JUMP_LABEL_RELATIVE
+ select HAVE_ARCH_KASAN if PPC32 && PPC_PAGE_SHIFT <= 14
+ select HAVE_ARCH_KASAN_VMALLOC if PPC32 && PPC_PAGE_SHIFT <= 14
+- select HAVE_ARCH_KFENCE if PPC32
++ select HAVE_ARCH_KFENCE if PPC_BOOK3S_32 || PPC_8xx || 40x
+ select HAVE_ARCH_KGDB
+ select HAVE_ARCH_MMAP_RND_BITS
+ select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
+diff --git a/arch/powerpc/boot/dts/charon.dts b/arch/powerpc/boot/dts/charon.dts
+index 408b486b13dff..cd589539f313f 100644
+--- a/arch/powerpc/boot/dts/charon.dts
++++ b/arch/powerpc/boot/dts/charon.dts
+@@ -35,7 +35,7 @@
+ };
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>; // 128MB
+ };
+diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts
+index 0e5e9d3acf79f..19a14e62e65f4 100644
+--- a/arch/powerpc/boot/dts/digsy_mtc.dts
++++ b/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
+ };
+
+diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
+index cb2782dd6132c..e7b194775d783 100644
+--- a/arch/powerpc/boot/dts/lite5200.dts
++++ b/arch/powerpc/boot/dts/lite5200.dts
+@@ -32,7 +32,7 @@
+ };
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
+index 2b86c81f90485..547cbe726ff23 100644
+--- a/arch/powerpc/boot/dts/lite5200b.dts
++++ b/arch/powerpc/boot/dts/lite5200b.dts
+@@ -31,7 +31,7 @@
+ led4 { gpios = <&gpio_simple 2 1>; };
+ };
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x10000000>; // 256MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/media5200.dts b/arch/powerpc/boot/dts/media5200.dts
+index 61cae9dcddef4..f3188018faceb 100644
+--- a/arch/powerpc/boot/dts/media5200.dts
++++ b/arch/powerpc/boot/dts/media5200.dts
+@@ -32,7 +32,7 @@
+ };
+ };
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x08000000>; // 128MB RAM
+ };
+
+diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi
+index 648fe31795f49..8b796f3b11da7 100644
+--- a/arch/powerpc/boot/dts/mpc5200b.dtsi
++++ b/arch/powerpc/boot/dts/mpc5200b.dtsi
+@@ -33,7 +33,7 @@
+ };
+ };
+
+- memory: memory {
++ memory: memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+diff --git a/arch/powerpc/boot/dts/o2d.dts b/arch/powerpc/boot/dts/o2d.dts
+index 24a46f65e5299..e0a8d3034417f 100644
+--- a/arch/powerpc/boot/dts/o2d.dts
++++ b/arch/powerpc/boot/dts/o2d.dts
+@@ -12,7 +12,7 @@
+ model = "ifm,o2d";
+ compatible = "ifm,o2d";
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x08000000>; // 128MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi
+index 6661955a2be47..b55a9e5bd828c 100644
+--- a/arch/powerpc/boot/dts/o2d.dtsi
++++ b/arch/powerpc/boot/dts/o2d.dtsi
+@@ -19,7 +19,7 @@
+ model = "ifm,o2d";
+ compatible = "ifm,o2d";
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/o2dnt2.dts b/arch/powerpc/boot/dts/o2dnt2.dts
+index eeba7f5507d5d..c2eedbd1f5fcb 100644
+--- a/arch/powerpc/boot/dts/o2dnt2.dts
++++ b/arch/powerpc/boot/dts/o2dnt2.dts
+@@ -12,7 +12,7 @@
+ model = "ifm,o2dnt2";
+ compatible = "ifm,o2d";
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x08000000>; // 128MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/o3dnt.dts b/arch/powerpc/boot/dts/o3dnt.dts
+index fd00396b0593e..e4c1bdd412716 100644
+--- a/arch/powerpc/boot/dts/o3dnt.dts
++++ b/arch/powerpc/boot/dts/o3dnt.dts
+@@ -12,7 +12,7 @@
+ model = "ifm,o3dnt";
+ compatible = "ifm,o2d";
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
+index 780e13d99e7b8..1895bc95900cc 100644
+--- a/arch/powerpc/boot/dts/pcm032.dts
++++ b/arch/powerpc/boot/dts/pcm032.dts
+@@ -20,7 +20,7 @@
+ model = "phytec,pcm032";
+ compatible = "phytec,pcm032";
+
+- memory {
++ memory@0 {
+ reg = <0x00000000 0x08000000>; // 128MB
+ };
+
+diff --git a/arch/powerpc/boot/dts/tqm5200.dts b/arch/powerpc/boot/dts/tqm5200.dts
+index 9ed0bc78967e1..5bb25a9e40a01 100644
+--- a/arch/powerpc/boot/dts/tqm5200.dts
++++ b/arch/powerpc/boot/dts/tqm5200.dts
+@@ -32,7 +32,7 @@
+ };
+ };
+
+- memory {
++ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
+index f06ae00f2a65e..d6ba821a56ced 100644
+--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
++++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
+@@ -193,10 +193,12 @@ static inline pte_t pte_wrprotect(pte_t pte)
+ }
+ #endif
+
++#ifndef pte_mkexec
+ static inline pte_t pte_mkexec(pte_t pte)
+ {
+ return __pte(pte_val(pte) | _PAGE_EXEC);
+ }
++#endif
+
+ #define pmd_none(pmd) (!pmd_val(pmd))
+ #define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
+@@ -306,30 +308,29 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ }
+
+ #define __HAVE_ARCH_PTEP_SET_WRPROTECT
++#ifndef ptep_set_wrprotect
+ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+ {
+- unsigned long clr = ~pte_val(pte_wrprotect(__pte(~0)));
+- unsigned long set = pte_val(pte_wrprotect(__pte(0)));
+-
+- pte_update(mm, addr, ptep, clr, set, 0);
++ pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
+ }
++#endif
+
++#ifndef __ptep_set_access_flags
+ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
+ pte_t *ptep, pte_t entry,
+ unsigned long address,
+ int psize)
+ {
+- pte_t pte_set = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte_mkexec(__pte(0)))));
+- pte_t pte_clr = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte_mkexec(__pte(~0)))));
+- unsigned long set = pte_val(entry) & pte_val(pte_set);
+- unsigned long clr = ~pte_val(entry) & ~pte_val(pte_clr);
++ unsigned long set = pte_val(entry) &
++ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
+ int huge = psize > mmu_virtual_psize ? 1 : 0;
+
+- pte_update(vma->vm_mm, address, ptep, clr, set, huge);
++ pte_update(vma->vm_mm, address, ptep, 0, set, huge);
+
+ flush_tlb_page(vma, address);
+ }
++#endif
+
+ static inline int pte_young(pte_t pte)
+ {
+diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+index fcc48d590d888..1a89ebdc3acc9 100644
+--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
++++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+@@ -136,6 +136,28 @@ static inline pte_t pte_mkhuge(pte_t pte)
+
+ #define pte_mkhuge pte_mkhuge
+
++static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
++ unsigned long clr, unsigned long set, int huge);
++
++static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
++{
++ pte_update(mm, addr, ptep, 0, _PAGE_RO, 0);
++}
++#define ptep_set_wrprotect ptep_set_wrprotect
++
++static inline void __ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
++ pte_t entry, unsigned long address, int psize)
++{
++ unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_EXEC);
++ unsigned long clr = ~pte_val(entry) & _PAGE_RO;
++ int huge = psize > mmu_virtual_psize ? 1 : 0;
++
++ pte_update(vma->vm_mm, address, ptep, clr, set, huge);
++
++ flush_tlb_page(vma, address);
++}
++#define __ptep_set_access_flags __ptep_set_access_flags
++
+ static inline unsigned long pgd_leaf_size(pgd_t pgd)
+ {
+ if (pgd_val(pgd) & _PMD_PAGE_8M)
+diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
+index d081704b13fb9..9d2905a474103 100644
+--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
++++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
+@@ -118,11 +118,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
+ return __pte(pte_val(pte) & ~_PAGE_RW);
+ }
+
+-static inline pte_t pte_mkexec(pte_t pte)
+-{
+- return __pte(pte_val(pte) | _PAGE_EXEC);
+-}
+-
+ #define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
+ #define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
+
+diff --git a/arch/powerpc/include/asm/nohash/pte-book3e.h b/arch/powerpc/include/asm/nohash/pte-book3e.h
+index 813918f407653..f798640422c2d 100644
+--- a/arch/powerpc/include/asm/nohash/pte-book3e.h
++++ b/arch/powerpc/include/asm/nohash/pte-book3e.h
+@@ -48,7 +48,7 @@
+ #define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */
+
+ /* "Higher level" linux bit combinations */
+-#define _PAGE_EXEC _PAGE_BAP_UX /* .. and was cache cleaned */
++#define _PAGE_EXEC (_PAGE_BAP_SX | _PAGE_BAP_UX) /* .. and was cache cleaned */
+ #define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
+ #define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
+ #define _PAGE_KERNEL_RO (_PAGE_BAP_SR)
+@@ -93,11 +93,11 @@
+ /* Permission masks used to generate the __P and __S table */
+ #define PAGE_NONE __pgprot(_PAGE_BASE)
+ #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+-#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
++#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_BAP_UX)
+ #define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
+-#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
++#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
+ #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
+-#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
++#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
+
+ #ifndef __ASSEMBLY__
+ static inline pte_t pte_mkprivileged(pte_t pte)
+@@ -113,6 +113,16 @@ static inline pte_t pte_mkuser(pte_t pte)
+ }
+
+ #define pte_mkuser pte_mkuser
++
++static inline pte_t pte_mkexec(pte_t pte)
++{
++ if (pte_val(pte) & _PAGE_BAP_UR)
++ return __pte((pte_val(pte) & ~_PAGE_BAP_SX) | _PAGE_BAP_UX);
++ else
++ return __pte((pte_val(pte) & ~_PAGE_BAP_UX) | _PAGE_BAP_SX);
++}
++#define pte_mkexec pte_mkexec
++
+ #endif /* __ASSEMBLY__ */
+
+ #endif /* __KERNEL__ */
+diff --git a/arch/powerpc/include/asm/paravirt.h b/arch/powerpc/include/asm/paravirt.h
+index bcb7b5f917be6..b325022ffa2b0 100644
+--- a/arch/powerpc/include/asm/paravirt.h
++++ b/arch/powerpc/include/asm/paravirt.h
+@@ -97,7 +97,23 @@ static inline bool vcpu_is_preempted(int cpu)
+
+ #ifdef CONFIG_PPC_SPLPAR
+ if (!is_kvm_guest()) {
+- int first_cpu = cpu_first_thread_sibling(smp_processor_id());
++ int first_cpu;
++
++ /*
++ * The result of vcpu_is_preempted() is used in a
++ * speculative way, and is always subject to invalidation
++ * by events internal and external to Linux. While we can
++ * be called in preemptable context (in the Linux sense),
++ * we're not accessing per-cpu resources in a way that can
++ * race destructively with Linux scheduler preemption and
++ * migration, and callers can tolerate the potential for
++ * error introduced by sampling the CPU index without
++ * pinning the task to it. So it is permissible to use
++ * raw_smp_processor_id() here to defeat the preempt debug
++ * warnings that can arise from using smp_processor_id()
++ * in arbitrary contexts.
++ */
++ first_cpu = cpu_first_thread_sibling(raw_smp_processor_id());
+
+ /*
+ * Preemption can only happen at core granularity. This CPU
+diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
+index 7be36c1e1db6d..86e40db2dec56 100644
+--- a/arch/powerpc/kernel/Makefile
++++ b/arch/powerpc/kernel/Makefile
+@@ -196,3 +196,6 @@ clean-files := vmlinux.lds
+ # Force dependency (incbin is bad)
+ $(obj)/vdso32_wrapper.o : $(obj)/vdso32/vdso32.so.dbg
+ $(obj)/vdso64_wrapper.o : $(obj)/vdso64/vdso64.so.dbg
++
++# for cleaning
++subdir- += vdso32 vdso64
+diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c
+index c7022c41cc314..20328f72f9f2b 100644
+--- a/arch/powerpc/kernel/firmware.c
++++ b/arch/powerpc/kernel/firmware.c
+@@ -31,11 +31,10 @@ int __init check_kvm_guest(void)
+ if (!hyper_node)
+ return 0;
+
+- if (!of_device_is_compatible(hyper_node, "linux,kvm"))
+- return 0;
+-
+- static_branch_enable(&kvm_guest);
++ if (of_device_is_compatible(hyper_node, "linux,kvm"))
++ static_branch_enable(&kvm_guest);
+
++ of_node_put(hyper_node);
+ return 0;
+ }
+ core_initcall(check_kvm_guest); // before kvm_guest_init()
+diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h
+index 6b1ec9e3541b9..349c4a820231b 100644
+--- a/arch/powerpc/kernel/head_32.h
++++ b/arch/powerpc/kernel/head_32.h
+@@ -202,11 +202,11 @@ vmap_stack_overflow:
+ mfspr r1, SPRN_SPRG_THREAD
+ lwz r1, TASK_CPU - THREAD(r1)
+ slwi r1, r1, 3
+- addis r1, r1, emergency_ctx@ha
++ addis r1, r1, emergency_ctx-PAGE_OFFSET@ha
+ #else
+- lis r1, emergency_ctx@ha
++ lis r1, emergency_ctx-PAGE_OFFSET@ha
+ #endif
+- lwz r1, emergency_ctx@l(r1)
++ lwz r1, emergency_ctx-PAGE_OFFSET@l(r1)
+ addi r1, r1, THREAD_SIZE - INT_FRAME_SIZE
+ EXCEPTION_PROLOG_2 0 vmap_stack_overflow
+ prepare_transfer_to_handler
+diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
+index 9bdb95f5694f7..0d073b9fd52c5 100644
+--- a/arch/powerpc/kernel/head_8xx.S
++++ b/arch/powerpc/kernel/head_8xx.S
+@@ -733,6 +733,7 @@ _GLOBAL(mmu_pin_tlb)
+ #ifdef CONFIG_PIN_TLB_DATA
+ LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET)
+ LOAD_REG_IMMEDIATE(r7, MI_SVALID | MI_PS8MEG | _PMD_ACCESSED)
++ li r8, 0
+ #ifdef CONFIG_PIN_TLB_IMMR
+ li r0, 3
+ #else
+@@ -741,26 +742,26 @@ _GLOBAL(mmu_pin_tlb)
+ mtctr r0
+ cmpwi r4, 0
+ beq 4f
+- LOAD_REG_IMMEDIATE(r8, 0xf0 | _PAGE_RO | _PAGE_SPS | _PAGE_SH | _PAGE_PRESENT)
+ LOAD_REG_ADDR(r9, _sinittext)
+
+ 2: ori r0, r6, MD_EVALID
++ ori r12, r8, 0xf0 | _PAGE_RO | _PAGE_SPS | _PAGE_SH | _PAGE_PRESENT
+ mtspr SPRN_MD_CTR, r5
+ mtspr SPRN_MD_EPN, r0
+ mtspr SPRN_MD_TWC, r7
+- mtspr SPRN_MD_RPN, r8
++ mtspr SPRN_MD_RPN, r12
+ addi r5, r5, 0x100
+ addis r6, r6, SZ_8M@h
+ addis r8, r8, SZ_8M@h
+ cmplw r6, r9
+ bdnzt lt, 2b
+-
+-4: LOAD_REG_IMMEDIATE(r8, 0xf0 | _PAGE_SPS | _PAGE_SH | _PAGE_PRESENT)
++4:
+ 2: ori r0, r6, MD_EVALID
++ ori r12, r8, 0xf0 | _PAGE_DIRTY | _PAGE_SPS | _PAGE_SH | _PAGE_PRESENT
+ mtspr SPRN_MD_CTR, r5
+ mtspr SPRN_MD_EPN, r0
+ mtspr SPRN_MD_TWC, r7
+- mtspr SPRN_MD_RPN, r8
++ mtspr SPRN_MD_RPN, r12
+ addi r5, r5, 0x100
+ addis r6, r6, SZ_8M@h
+ addis r8, r8, SZ_8M@h
+@@ -781,7 +782,7 @@ _GLOBAL(mmu_pin_tlb)
+ #endif
+ #if defined(CONFIG_PIN_TLB_IMMR) || defined(CONFIG_PIN_TLB_DATA)
+ lis r0, (MD_RSV4I | MD_TWAM)@h
+- mtspr SPRN_MI_CTR, r0
++ mtspr SPRN_MD_CTR, r0
+ #endif
+ mtspr SPRN_SRR1, r10
+ mtspr SPRN_SRR0, r11
+diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
+index e5503420b6c6d..ef8d1b1c234e7 100644
+--- a/arch/powerpc/kernel/head_booke.h
++++ b/arch/powerpc/kernel/head_booke.h
+@@ -465,12 +465,21 @@ label:
+ bl do_page_fault; \
+ b interrupt_return
+
++/*
++ * Instruction TLB Error interrupt handlers may call InstructionStorage
++ * directly without clearing ESR, so the ESR at this point may be left over
++ * from a prior interrupt.
++ *
++ * In any case, do_page_fault for BOOK3E does not use ESR and always expects
++ * dsisr to be 0. ESR_DST from a prior store in particular would confuse fault
++ * handling.
++ */
+ #define INSTRUCTION_STORAGE_EXCEPTION \
+ START_EXCEPTION(InstructionStorage) \
+- NORMAL_EXCEPTION_PROLOG(0x400, INST_STORAGE); \
+- mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \
++ NORMAL_EXCEPTION_PROLOG(0x400, INST_STORAGE); \
++ li r5,0; /* Store 0 in regs->esr (dsisr) */ \
+ stw r5,_ESR(r11); \
+- stw r12, _DEAR(r11); /* Pass SRR0 as arg2 */ \
++ stw r12, _DEAR(r11); /* Set regs->dear (dar) to SRR0 */ \
+ prepare_transfer_to_handler; \
+ bl do_page_fault; \
+ b interrupt_return
+diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c
+index de10a26972581..835b626cd4760 100644
+--- a/arch/powerpc/kernel/interrupt.c
++++ b/arch/powerpc/kernel/interrupt.c
+@@ -266,7 +266,7 @@ static void check_return_regs_valid(struct pt_regs *regs)
+ if (trap_is_scv(regs))
+ return;
+
+- trap = regs->trap;
++ trap = TRAP(regs);
+ // EE in HV mode sets HSRRs like 0xea0
+ if (cpu_has_feature(CPU_FTR_HVMODE) && trap == INTERRUPT_EXTERNAL)
+ trap = 0xea0;
+diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
+index 6baa676e7cb60..5d77d3f5fbb56 100644
+--- a/arch/powerpc/kernel/module_64.c
++++ b/arch/powerpc/kernel/module_64.c
+@@ -422,11 +422,17 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
+ const char *name)
+ {
+ long reladdr;
++ func_desc_t desc;
++ int i;
+
+ if (is_mprofile_ftrace_call(name))
+ return create_ftrace_stub(entry, addr, me);
+
+- memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
++ for (i = 0; i < sizeof(ppc64_stub_insns) / sizeof(u32); i++) {
++ if (patch_instruction(&entry->jump[i],
++ ppc_inst(ppc64_stub_insns[i])))
++ return 0;
++ }
+
+ /* Stub uses address relative to r2. */
+ reladdr = (unsigned long)entry - my_r2(sechdrs, me);
+@@ -437,10 +443,24 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
+ }
+ pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
+
+- entry->jump[0] |= PPC_HA(reladdr);
+- entry->jump[1] |= PPC_LO(reladdr);
+- entry->funcdata = func_desc(addr);
+- entry->magic = STUB_MAGIC;
++ if (patch_instruction(&entry->jump[0],
++ ppc_inst(entry->jump[0] | PPC_HA(reladdr))))
++ return 0;
++
++ if (patch_instruction(&entry->jump[1],
++ ppc_inst(entry->jump[1] | PPC_LO(reladdr))))
++ return 0;
++
++ // func_desc_t is 8 bytes if ABIv2, else 16 bytes
++ desc = func_desc(addr);
++ for (i = 0; i < sizeof(func_desc_t) / sizeof(u32); i++) {
++ if (patch_instruction(((u32 *)&entry->funcdata) + i,
++ ppc_inst(((u32 *)(&desc))[i])))
++ return 0;
++ }
++
++ if (patch_instruction(&entry->magic, ppc_inst(STUB_MAGIC)))
++ return 0;
+
+ return 1;
+ }
+@@ -495,8 +515,11 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me)
+ me->name, *instruction, instruction);
+ return 0;
+ }
++
+ /* ld r2,R2_STACK_OFFSET(r1) */
+- *instruction = PPC_INST_LD_TOC;
++ if (patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC)))
++ return 0;
++
+ return 1;
+ }
+
+@@ -636,9 +659,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
+ }
+
+ /* Only replace bits 2 through 26 */
+- *(uint32_t *)location
+- = (*(uint32_t *)location & ~0x03fffffc)
++ value = (*(uint32_t *)location & ~0x03fffffc)
+ | (value & 0x03fffffc);
++
++ if (patch_instruction((u32 *)location, ppc_inst(value)))
++ return -EFAULT;
++
+ break;
+
+ case R_PPC64_REL64:
+diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
+index 1f07317964e49..618aeccdf6918 100644
+--- a/arch/powerpc/kernel/signal.h
++++ b/arch/powerpc/kernel/signal.h
+@@ -25,8 +25,14 @@ static inline int __get_user_sigset(sigset_t *dst, const sigset_t __user *src)
+
+ return __get_user(dst->sig[0], (u64 __user *)&src->sig[0]);
+ }
+-#define unsafe_get_user_sigset(dst, src, label) \
+- unsafe_get_user((dst)->sig[0], (u64 __user *)&(src)->sig[0], label)
++#define unsafe_get_user_sigset(dst, src, label) do { \
++ sigset_t *__dst = dst; \
++ const sigset_t __user *__src = src; \
++ int i; \
++ \
++ for (i = 0; i < _NSIG_WORDS; i++) \
++ unsafe_get_user(__dst->sig[i], &__src->sig[i], label); \
++} while (0)
+
+ #ifdef CONFIG_VSX
+ extern unsigned long copy_vsx_to_user(void __user *to,
+diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
+index 0608581967f09..f2da879264bcd 100644
+--- a/arch/powerpc/kernel/signal_32.c
++++ b/arch/powerpc/kernel/signal_32.c
+@@ -1062,8 +1062,10 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
+ * or if another thread unmaps the region containing the context.
+ * We kill the task with a SIGSEGV in this situation.
+ */
+- if (do_setcontext(new_ctx, regs, 0))
+- do_exit(SIGSEGV);
++ if (do_setcontext(new_ctx, regs, 0)) {
++ force_exit_sig(SIGSEGV);
++ return -EFAULT;
++ }
+
+ set_thread_flag(TIF_RESTOREALL);
+ return 0;
+diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
+index 1831bba0582e1..bb9c077ac1322 100644
+--- a/arch/powerpc/kernel/signal_64.c
++++ b/arch/powerpc/kernel/signal_64.c
+@@ -703,15 +703,18 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
+ * We kill the task with a SIGSEGV in this situation.
+ */
+
+- if (__get_user_sigset(&set, &new_ctx->uc_sigmask))
+- do_exit(SIGSEGV);
++ if (__get_user_sigset(&set, &new_ctx->uc_sigmask)) {
++ force_exit_sig(SIGSEGV);
++ return -EFAULT;
++ }
+ set_current_blocked(&set);
+
+ if (!user_read_access_begin(new_ctx, ctx_size))
+ return -EFAULT;
+ if (__unsafe_restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) {
+ user_read_access_end();
+- do_exit(SIGSEGV);
++ force_exit_sig(SIGSEGV);
++ return -EFAULT;
+ }
+ user_read_access_end();
+
+diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
+index f9ea0e5357f92..3fa6d240bade2 100644
+--- a/arch/powerpc/kernel/watchdog.c
++++ b/arch/powerpc/kernel/watchdog.c
+@@ -187,6 +187,12 @@ static void watchdog_smp_panic(int cpu, u64 tb)
+ if (sysctl_hardlockup_all_cpu_backtrace)
+ trigger_allbutself_cpu_backtrace();
+
++ /*
++ * Force flush any remote buffers that might be stuck in IRQ context
++ * and therefore could not run their irq_work.
++ */
++ printk_trigger_flush();
++
+ if (hardlockup_panic)
+ nmi_panic(NULL, "Hard LOCKUP");
+
+diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
+index 2acb1c96cfafd..7b74fc0a986b8 100644
+--- a/arch/powerpc/kvm/book3s_hv.c
++++ b/arch/powerpc/kvm/book3s_hv.c
+@@ -3726,7 +3726,20 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
+
+ kvmppc_set_host_core(pcpu);
+
+- guest_exit_irqoff();
++ context_tracking_guest_exit();
++ if (!vtime_accounting_enabled_this_cpu()) {
++ local_irq_enable();
++ /*
++ * Service IRQs here before vtime_account_guest_exit() so any
++ * ticks that occurred while running the guest are accounted to
++ * the guest. If vtime accounting is enabled, accounting uses
++ * TB rather than ticks, so it can be done without enabling
++ * interrupts here, which has the problem that it accounts
++ * interrupt processing overhead to the host.
++ */
++ local_irq_disable();
++ }
++ vtime_account_guest_exit();
+
+ local_irq_enable();
+
+@@ -4510,7 +4523,20 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
+
+ kvmppc_set_host_core(pcpu);
+
+- guest_exit_irqoff();
++ context_tracking_guest_exit();
++ if (!vtime_accounting_enabled_this_cpu()) {
++ local_irq_enable();
++ /*
++ * Service IRQs here before vtime_account_guest_exit() so any
++ * ticks that occurred while running the guest are accounted to
++ * the guest. If vtime accounting is enabled, accounting uses
++ * TB rather than ticks, so it can be done without enabling
++ * interrupts here, which has the problem that it accounts
++ * interrupt processing overhead to the host.
++ */
++ local_irq_disable();
++ }
++ vtime_account_guest_exit();
+
+ local_irq_enable();
+
+diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
+index fcf4760a3a0ea..70b7a8f971538 100644
+--- a/arch/powerpc/kvm/book3s_hv_builtin.c
++++ b/arch/powerpc/kvm/book3s_hv_builtin.c
+@@ -695,6 +695,7 @@ static void flush_guest_tlb(struct kvm *kvm)
+ "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) {
+@@ -705,7 +706,9 @@ static void flush_guest_tlb(struct kvm *kvm)
+ 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");
+ }
+ }
+
+diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+index eb776d0c5d8e9..32a4b4d412b92 100644
+--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+@@ -2005,7 +2005,7 @@ hcall_real_table:
+ .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
+@@ -2015,7 +2015,7 @@ EXPORT_SYMBOL_GPL(kvmppc_h_set_xdabr)
+ 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:
+diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
+index 977801c83aff8..8c15c90dd3a97 100644
+--- a/arch/powerpc/kvm/booke.c
++++ b/arch/powerpc/kvm/booke.c
+@@ -1042,7 +1042,21 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr)
+ }
+
+ trace_kvm_exit(exit_nr, vcpu);
+- guest_exit_irqoff();
++
++ context_tracking_guest_exit();
++ if (!vtime_accounting_enabled_this_cpu()) {
++ local_irq_enable();
++ /*
++ * Service IRQs here before vtime_account_guest_exit() so any
++ * ticks that occurred while running the guest are accounted to
++ * the guest. If vtime accounting is enabled, accounting uses
++ * TB rather than ticks, so it can be done without enabling
++ * interrupts here, which has the problem that it accounts
++ * interrupt processing overhead to the host.
++ */
++ local_irq_disable();
++ }
++ vtime_account_guest_exit();
+
+ local_irq_enable();
+
+diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
+index cda17bee5afea..c3e06922468b3 100644
+--- a/arch/powerpc/lib/feature-fixups.c
++++ b/arch/powerpc/lib/feature-fixups.c
+@@ -228,6 +228,7 @@ static void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
+
+ static bool stf_exit_reentrant = false;
+ static bool rfi_exit_reentrant = false;
++static DEFINE_MUTEX(exit_flush_lock);
+
+ static int __do_stf_barrier_fixups(void *data)
+ {
+@@ -253,6 +254,9 @@ void do_stf_barrier_fixups(enum stf_barrier_type types)
+ * low level interrupt exit code before patching. After the patching,
+ * if allowed, then flip the branch to allow fast exits.
+ */
++
++ // Prevent static key update races with do_rfi_flush_fixups()
++ mutex_lock(&exit_flush_lock);
+ static_branch_enable(&interrupt_exit_not_reentrant);
+
+ stop_machine(__do_stf_barrier_fixups, &types, NULL);
+@@ -264,6 +268,8 @@ void do_stf_barrier_fixups(enum stf_barrier_type types)
+
+ if (stf_exit_reentrant && rfi_exit_reentrant)
+ static_branch_disable(&interrupt_exit_not_reentrant);
++
++ mutex_unlock(&exit_flush_lock);
+ }
+
+ void do_uaccess_flush_fixups(enum l1d_flush_type types)
+@@ -486,6 +492,9 @@ void do_rfi_flush_fixups(enum l1d_flush_type types)
+ * without stop_machine, so this could be achieved with a broadcast
+ * IPI instead, but this matches the stf sequence.
+ */
++
++ // Prevent static key update races with do_stf_barrier_fixups()
++ mutex_lock(&exit_flush_lock);
+ static_branch_enable(&interrupt_exit_not_reentrant);
+
+ stop_machine(__do_rfi_flush_fixups, &types, NULL);
+@@ -497,6 +506,8 @@ void do_rfi_flush_fixups(enum l1d_flush_type types)
+
+ if (stf_exit_reentrant && rfi_exit_reentrant)
+ static_branch_disable(&interrupt_exit_not_reentrant);
++
++ mutex_unlock(&exit_flush_lock);
+ }
+
+ void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index c3c4e31462eca..05b9c3f31456c 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -20,8 +20,8 @@
+ #include <asm/machdep.h>
+ #include <asm/rtas.h>
+ #include <asm/kasan.h>
+-#include <asm/sparsemem.h>
+ #include <asm/svm.h>
++#include <asm/mmzone.h>
+
+ #include <mm/mmu_decl.h>
+
+diff --git a/arch/powerpc/mm/nohash/tlb_low_64e.S b/arch/powerpc/mm/nohash/tlb_low_64e.S
+index bf24451f3e71f..9235e720e3572 100644
+--- a/arch/powerpc/mm/nohash/tlb_low_64e.S
++++ b/arch/powerpc/mm/nohash/tlb_low_64e.S
+@@ -222,7 +222,7 @@ tlb_miss_kernel_bolted:
+
+ tlb_miss_fault_bolted:
+ /* We need to check if it was an instruction miss */
+- andi. r10,r11,_PAGE_EXEC|_PAGE_BAP_SX
++ andi. r10,r11,_PAGE_BAP_UX|_PAGE_BAP_SX
+ bne itlb_miss_fault_bolted
+ dtlb_miss_fault_bolted:
+ tlb_epilog_bolted
+@@ -239,7 +239,7 @@ itlb_miss_fault_bolted:
+ srdi r15,r16,60 /* get region */
+ bne- itlb_miss_fault_bolted
+
+- li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */
++ li r11,_PAGE_PRESENT|_PAGE_BAP_UX /* Base perm */
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+@@ -614,7 +614,7 @@ itlb_miss_fault_e6500:
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+- li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */
++ li r11,_PAGE_PRESENT|_PAGE_BAP_UX /* Base perm */
+ oris r11,r11,_PAGE_ACCESSED@h
+
+ cmpldi cr0,r15,0 /* Check for user region */
+@@ -734,7 +734,7 @@ normal_tlb_miss_done:
+
+ normal_tlb_miss_access_fault:
+ /* We need to check if it was an instruction miss */
+- andi. r10,r11,_PAGE_EXEC
++ andi. r10,r11,_PAGE_BAP_UX
+ bne 1f
+ ld r14,EX_TLB_DEAR(r12)
+ ld r15,EX_TLB_ESR(r12)
+diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
+index 6f14c8fb6359d..59d3cfcd78879 100644
+--- a/arch/powerpc/mm/numa.c
++++ b/arch/powerpc/mm/numa.c
+@@ -376,9 +376,9 @@ static void initialize_form2_numa_distance_lookup_table(void)
+ {
+ int i, j;
+ struct device_node *root;
+- const __u8 *numa_dist_table;
++ const __u8 *form2_distances;
+ const __be32 *numa_lookup_index;
+- int numa_dist_table_length;
++ int form2_distances_length;
+ int max_numa_index, distance_index;
+
+ if (firmware_has_feature(FW_FEATURE_OPAL))
+@@ -392,45 +392,41 @@ static void initialize_form2_numa_distance_lookup_table(void)
+ max_numa_index = of_read_number(&numa_lookup_index[0], 1);
+
+ /* first element of the array is the size and is encode-int */
+- numa_dist_table = of_get_property(root, "ibm,numa-distance-table", NULL);
+- numa_dist_table_length = of_read_number((const __be32 *)&numa_dist_table[0], 1);
++ form2_distances = of_get_property(root, "ibm,numa-distance-table", NULL);
++ form2_distances_length = of_read_number((const __be32 *)&form2_distances[0], 1);
+ /* Skip the size which is encoded int */
+- numa_dist_table += sizeof(__be32);
++ form2_distances += sizeof(__be32);
+
+- pr_debug("numa_dist_table_len = %d, numa_dist_indexes_len = %d\n",
+- numa_dist_table_length, max_numa_index);
++ pr_debug("form2_distances_len = %d, numa_dist_indexes_len = %d\n",
++ form2_distances_length, max_numa_index);
+
+ for (i = 0; i < max_numa_index; i++)
+ /* +1 skip the max_numa_index in the property */
+ numa_id_index_table[i] = of_read_number(&numa_lookup_index[i + 1], 1);
+
+
+- if (numa_dist_table_length != max_numa_index * max_numa_index) {
++ if (form2_distances_length != max_numa_index * max_numa_index) {
+ WARN(1, "Wrong NUMA distance information\n");
+- /* consider everybody else just remote. */
+- for (i = 0; i < max_numa_index; i++) {
+- for (j = 0; j < max_numa_index; j++) {
+- int nodeA = numa_id_index_table[i];
+- int nodeB = numa_id_index_table[j];
+-
+- if (nodeA == nodeB)
+- numa_distance_table[nodeA][nodeB] = LOCAL_DISTANCE;
+- else
+- numa_distance_table[nodeA][nodeB] = REMOTE_DISTANCE;
+- }
+- }
++ form2_distances = NULL; // don't use it
+ }
+-
+ distance_index = 0;
+ for (i = 0; i < max_numa_index; i++) {
+ for (j = 0; j < max_numa_index; j++) {
+ int nodeA = numa_id_index_table[i];
+ int nodeB = numa_id_index_table[j];
+-
+- numa_distance_table[nodeA][nodeB] = numa_dist_table[distance_index++];
+- pr_debug("dist[%d][%d]=%d ", nodeA, nodeB, numa_distance_table[nodeA][nodeB]);
++ int dist;
++
++ if (form2_distances)
++ dist = form2_distances[distance_index++];
++ else if (nodeA == nodeB)
++ dist = LOCAL_DISTANCE;
++ else
++ dist = REMOTE_DISTANCE;
++ numa_distance_table[nodeA][nodeB] = dist;
++ pr_debug("dist[%d][%d]=%d ", nodeA, nodeB, dist);
+ }
+ }
++
+ of_node_put(root);
+ }
+
+diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
+index dcf5ecca19d99..fde1ed445ca46 100644
+--- a/arch/powerpc/mm/pgtable_32.c
++++ b/arch/powerpc/mm/pgtable_32.c
+@@ -173,7 +173,7 @@ void mark_rodata_ro(void)
+ }
+ #endif
+
+-#ifdef CONFIG_DEBUG_PAGEALLOC
++#if defined(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC) && defined(CONFIG_DEBUG_PAGEALLOC)
+ void __kernel_map_pages(struct page *page, int numpages, int enable)
+ {
+ unsigned long addr = (unsigned long)page_address(page);
+diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
+index fcbf7a917c566..90ce75f0f1e2a 100644
+--- a/arch/powerpc/net/bpf_jit_comp.c
++++ b/arch/powerpc/net/bpf_jit_comp.c
+@@ -241,8 +241,8 @@ skip_codegen_passes:
+ fp->jited_len = alloclen;
+
+ bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE));
+- bpf_jit_binary_lock_ro(bpf_hdr);
+ if (!fp->is_func || extra_pass) {
++ bpf_jit_binary_lock_ro(bpf_hdr);
+ bpf_prog_fill_jited_linfo(fp, addrs);
+ out_addrs:
+ kfree(addrs);
+diff --git a/arch/powerpc/perf/power10-events-list.h b/arch/powerpc/perf/power10-events-list.h
+index 93be7197d2502..564f14097f07b 100644
+--- a/arch/powerpc/perf/power10-events-list.h
++++ b/arch/powerpc/perf/power10-events-list.h
+@@ -9,10 +9,10 @@
+ /*
+ * Power10 event codes.
+ */
+-EVENT(PM_RUN_CYC, 0x600f4);
++EVENT(PM_CYC, 0x600f4);
+ EVENT(PM_DISP_STALL_CYC, 0x100f8);
+ EVENT(PM_EXEC_STALL, 0x30008);
+-EVENT(PM_RUN_INST_CMPL, 0x500fa);
++EVENT(PM_INST_CMPL, 0x500fa);
+ EVENT(PM_BR_CMPL, 0x4d05e);
+ EVENT(PM_BR_MPRED_CMPL, 0x400f6);
+ EVENT(PM_BR_FIN, 0x2f04a);
+@@ -50,8 +50,8 @@ EVENT(PM_DTLB_MISS, 0x300fc);
+ /* ITLB Reloaded */
+ EVENT(PM_ITLB_MISS, 0x400fc);
+
+-EVENT(PM_RUN_CYC_ALT, 0x0001e);
+-EVENT(PM_RUN_INST_CMPL_ALT, 0x00002);
++EVENT(PM_CYC_ALT, 0x0001e);
++EVENT(PM_INST_CMPL_ALT, 0x00002);
+
+ /*
+ * Memory Access Events
+diff --git a/arch/powerpc/perf/power10-pmu.c b/arch/powerpc/perf/power10-pmu.c
+index f9d64c63bb4a7..9dd75f3858372 100644
+--- a/arch/powerpc/perf/power10-pmu.c
++++ b/arch/powerpc/perf/power10-pmu.c
+@@ -91,8 +91,8 @@ extern u64 PERF_REG_EXTENDED_MASK;
+
+ /* Table of alternatives, sorted by column 0 */
+ static const unsigned int power10_event_alternatives[][MAX_ALT] = {
+- { PM_RUN_CYC_ALT, PM_RUN_CYC },
+- { PM_RUN_INST_CMPL_ALT, PM_RUN_INST_CMPL },
++ { PM_CYC_ALT, PM_CYC },
++ { PM_INST_CMPL_ALT, PM_INST_CMPL },
+ };
+
+ static int power10_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+@@ -118,8 +118,8 @@ static int power10_check_attr_config(struct perf_event *ev)
+ return 0;
+ }
+
+-GENERIC_EVENT_ATTR(cpu-cycles, PM_RUN_CYC);
+-GENERIC_EVENT_ATTR(instructions, PM_RUN_INST_CMPL);
++GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC);
++GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL);
+ GENERIC_EVENT_ATTR(branch-instructions, PM_BR_CMPL);
+ GENERIC_EVENT_ATTR(branch-misses, PM_BR_MPRED_CMPL);
+ GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1);
+@@ -148,8 +148,8 @@ CACHE_EVENT_ATTR(dTLB-load-misses, PM_DTLB_MISS);
+ CACHE_EVENT_ATTR(iTLB-load-misses, PM_ITLB_MISS);
+
+ static struct attribute *power10_events_attr_dd1[] = {
+- GENERIC_EVENT_PTR(PM_RUN_CYC),
+- GENERIC_EVENT_PTR(PM_RUN_INST_CMPL),
++ GENERIC_EVENT_PTR(PM_CYC),
++ GENERIC_EVENT_PTR(PM_INST_CMPL),
+ GENERIC_EVENT_PTR(PM_BR_CMPL),
+ GENERIC_EVENT_PTR(PM_BR_MPRED_CMPL),
+ GENERIC_EVENT_PTR(PM_LD_REF_L1),
+@@ -173,8 +173,8 @@ static struct attribute *power10_events_attr_dd1[] = {
+ };
+
+ static struct attribute *power10_events_attr[] = {
+- GENERIC_EVENT_PTR(PM_RUN_CYC),
+- GENERIC_EVENT_PTR(PM_RUN_INST_CMPL),
++ GENERIC_EVENT_PTR(PM_CYC),
++ GENERIC_EVENT_PTR(PM_INST_CMPL),
+ GENERIC_EVENT_PTR(PM_BR_FIN),
+ GENERIC_EVENT_PTR(PM_MPRED_BR_FIN),
+ GENERIC_EVENT_PTR(PM_LD_REF_L1),
+@@ -271,8 +271,8 @@ static const struct attribute_group *power10_pmu_attr_groups[] = {
+ };
+
+ static int power10_generic_events_dd1[] = {
+- [PERF_COUNT_HW_CPU_CYCLES] = PM_RUN_CYC,
+- [PERF_COUNT_HW_INSTRUCTIONS] = PM_RUN_INST_CMPL,
++ [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC,
++ [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BR_CMPL,
+ [PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1,
+@@ -280,8 +280,8 @@ static int power10_generic_events_dd1[] = {
+ };
+
+ static int power10_generic_events[] = {
+- [PERF_COUNT_HW_CPU_CYCLES] = PM_RUN_CYC,
+- [PERF_COUNT_HW_INSTRUCTIONS] = PM_RUN_INST_CMPL,
++ [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC,
++ [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BR_FIN,
+ [PERF_COUNT_HW_BRANCH_MISSES] = PM_MPRED_BR_FIN,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1,
+@@ -548,6 +548,24 @@ static u64 power10_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+
+ #undef C
+
++/*
++ * Set the MMCR0[CC56RUN] bit to enable counting for
++ * PMC5 and PMC6 regardless of the state of CTRL[RUN],
++ * so that we can use counters 5 and 6 as PM_INST_CMPL and
++ * PM_CYC.
++ */
++static int power10_compute_mmcr(u64 event[], int n_ev,
++ unsigned int hwc[], struct mmcr_regs *mmcr,
++ struct perf_event *pevents[], u32 flags)
++{
++ int ret;
++
++ ret = isa207_compute_mmcr(event, n_ev, hwc, mmcr, pevents, flags);
++ if (!ret)
++ mmcr->mmcr0 |= MMCR0_C56RUN;
++ return ret;
++}
++
+ static struct power_pmu power10_pmu = {
+ .name = "POWER10",
+ .n_counter = MAX_PMU_COUNTERS,
+@@ -555,7 +573,7 @@ static struct power_pmu power10_pmu = {
+ .test_adder = ISA207_TEST_ADDER,
+ .group_constraint_mask = CNST_CACHE_PMC4_MASK,
+ .group_constraint_val = CNST_CACHE_PMC4_VAL,
+- .compute_mmcr = isa207_compute_mmcr,
++ .compute_mmcr = power10_compute_mmcr,
+ .config_bhrb = power10_config_bhrb,
+ .bhrb_filter_map = power10_bhrb_filter_map,
+ .get_constraint = isa207_get_constraint,
+diff --git a/arch/powerpc/platforms/44x/fsp2.c b/arch/powerpc/platforms/44x/fsp2.c
+index b299e43f5ef94..823397c802def 100644
+--- a/arch/powerpc/platforms/44x/fsp2.c
++++ b/arch/powerpc/platforms/44x/fsp2.c
+@@ -208,6 +208,7 @@ static void node_irq_request(const char *compat, irq_handler_t errirq_handler)
+ if (irq == NO_IRQ) {
+ pr_err("device tree node %pOFn is missing a interrupt",
+ np);
++ of_node_put(np);
+ return;
+ }
+
+@@ -215,6 +216,7 @@ static void node_irq_request(const char *compat, irq_handler_t errirq_handler)
+ if (rc) {
+ pr_err("fsp_of_probe: request_irq failed: np=%pOF rc=%d",
+ np, rc);
++ of_node_put(np);
+ return;
+ }
+ }
+diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
+index 60e4e97a929db..260fbad7967b2 100644
+--- a/arch/powerpc/platforms/85xx/Makefile
++++ b/arch/powerpc/platforms/85xx/Makefile
+@@ -3,7 +3,9 @@
+ # Makefile for the PowerPC 85xx linux kernel.
+ #
+ obj-$(CONFIG_SMP) += smp.o
+-obj-$(CONFIG_FSL_PMC) += mpc85xx_pm_ops.o
++ifneq ($(CONFIG_FSL_CORENET_RCPM),y)
++obj-$(CONFIG_SMP) += mpc85xx_pm_ops.o
++endif
+
+ obj-y += common.o
+
+diff --git a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c
+index 7c0133f558d02..4a8af80011a6f 100644
+--- a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c
++++ b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c
+@@ -17,6 +17,7 @@
+
+ static struct ccsr_guts __iomem *guts;
+
++#ifdef CONFIG_FSL_PMC
+ static void mpc85xx_irq_mask(int cpu)
+ {
+
+@@ -49,6 +50,7 @@ static void mpc85xx_cpu_up_prepare(int cpu)
+ {
+
+ }
++#endif
+
+ static void mpc85xx_freeze_time_base(bool freeze)
+ {
+@@ -76,10 +78,12 @@ static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+
+ static const struct fsl_pm_ops mpc85xx_pm_ops = {
+ .freeze_time_base = mpc85xx_freeze_time_base,
++#ifdef CONFIG_FSL_PMC
+ .irq_mask = mpc85xx_irq_mask,
+ .irq_unmask = mpc85xx_irq_unmask,
+ .cpu_die = mpc85xx_cpu_die,
+ .cpu_up_prepare = mpc85xx_cpu_up_prepare,
++#endif
+ };
+
+ int __init mpc85xx_setup_pmc(void)
+@@ -94,9 +98,8 @@ int __init mpc85xx_setup_pmc(void)
+ 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;
+ }
+diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
+index c6df294054fe9..d7081e9af65c7 100644
+--- a/arch/powerpc/platforms/85xx/smp.c
++++ b/arch/powerpc/platforms/85xx/smp.c
+@@ -40,7 +40,6 @@ struct epapr_spin_table {
+ u32 pir;
+ };
+
+-#ifdef CONFIG_HOTPLUG_CPU
+ static u64 timebase;
+ static int tb_req;
+ static int tb_valid;
+@@ -112,6 +111,7 @@ static void mpc85xx_take_timebase(void)
+ local_irq_restore(flags);
+ }
+
++#ifdef CONFIG_HOTPLUG_CPU
+ static void smp_85xx_cpu_offline_self(void)
+ {
+ unsigned int cpu = smp_processor_id();
+@@ -220,7 +220,7 @@ static int smp_85xx_start_cpu(int cpu)
+ local_irq_save(flags);
+ hard_irq_disable();
+
+- if (qoriq_pm_ops)
++ if (qoriq_pm_ops && qoriq_pm_ops->cpu_up_prepare)
+ qoriq_pm_ops->cpu_up_prepare(cpu);
+
+ /* if cpu is not spinning, reset it */
+@@ -292,7 +292,7 @@ static int smp_85xx_kick_cpu(int nr)
+ booting_thread_hwid = cpu_thread_in_core(nr);
+ primary = cpu_first_thread_sibling(nr);
+
+- if (qoriq_pm_ops)
++ if (qoriq_pm_ops && qoriq_pm_ops->cpu_up_prepare)
+ qoriq_pm_ops->cpu_up_prepare(nr);
+
+ /*
+@@ -495,21 +495,21 @@ void __init mpc85xx_smp_init(void)
+ smp_85xx_ops.probe = NULL;
+ }
+
+-#ifdef CONFIG_HOTPLUG_CPU
+ #ifdef CONFIG_FSL_CORENET_RCPM
++ /* Assign a value to qoriq_pm_ops on PPC_E500MC */
+ fsl_rcpm_init();
+-#endif
+-
+-#ifdef CONFIG_FSL_PMC
++#else
++ /* Assign a value to qoriq_pm_ops on !PPC_E500MC */
+ mpc85xx_setup_pmc();
+ #endif
+ if (qoriq_pm_ops) {
+ smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+ smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
++#ifdef CONFIG_HOTPLUG_CPU
+ smp_85xx_ops.cpu_offline_self = smp_85xx_cpu_offline_self;
+ smp_85xx_ops.cpu_die = qoriq_cpu_kill;
+- }
+ #endif
++ }
+ smp_ops = &smp_85xx_ops;
+
+ #ifdef CONFIG_KEXEC_CORE
+diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c
+index 30172e52e16b7..4d82c92ddd523 100644
+--- a/arch/powerpc/platforms/book3s/vas-api.c
++++ b/arch/powerpc/platforms/book3s/vas-api.c
+@@ -303,7 +303,7 @@ static int coproc_ioc_tx_win_open(struct file *fp, unsigned long arg)
+ return -EINVAL;
+ }
+
+- if (!cp_inst->coproc->vops && !cp_inst->coproc->vops->open_win) {
++ if (!cp_inst->coproc->vops || !cp_inst->coproc->vops->open_win) {
+ pr_err("VAS API is not registered\n");
+ return -EACCES;
+ }
+@@ -373,7 +373,7 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma)
+ return -EINVAL;
+ }
+
+- if (!cp_inst->coproc->vops && !cp_inst->coproc->vops->paste_addr) {
++ if (!cp_inst->coproc->vops || !cp_inst->coproc->vops->paste_addr) {
+ pr_err("%s(): VAS API is not registered\n", __func__);
+ return -EACCES;
+ }
+diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c
+index a191f4c60ce71..113bdb151f687 100644
+--- a/arch/powerpc/platforms/powernv/opal-prd.c
++++ b/arch/powerpc/platforms/powernv/opal-prd.c
+@@ -369,6 +369,12 @@ static struct notifier_block opal_prd_event_nb = {
+ .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;
+@@ -390,9 +396,10 @@ static int opal_prd_probe(struct platform_device *pdev)
+ 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;
+ }
+
+@@ -401,6 +408,8 @@ static int opal_prd_probe(struct platform_device *pdev)
+ 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;
+ }
+
+@@ -411,6 +420,7 @@ static int opal_prd_remove(struct platform_device *pdev)
+ {
+ 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;
+ }
+
+diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
+index a52af8fbf5711..8322ca86d5acf 100644
+--- a/arch/powerpc/platforms/pseries/iommu.c
++++ b/arch/powerpc/platforms/pseries/iommu.c
+@@ -1092,15 +1092,6 @@ static phys_addr_t ddw_memory_hotplug_max(void)
+ phys_addr_t max_addr = memory_hotplug_max();
+ struct device_node *memory;
+
+- /*
+- * The "ibm,pmemory" can appear anywhere in the address space.
+- * Assuming it is still backed by page structs, set the upper limit
+- * for the huge DMA window as MAX_PHYSMEM_BITS.
+- */
+- if (of_find_node_by_type(NULL, "ibm,pmemory"))
+- return (sizeof(phys_addr_t) * 8 <= MAX_PHYSMEM_BITS) ?
+- (phys_addr_t) -1 : (1ULL << MAX_PHYSMEM_BITS);
+-
+ for_each_node_by_type(memory, "memory") {
+ unsigned long start, size;
+ int n_mem_addr_cells, n_mem_size_cells, len;
+@@ -1365,8 +1356,10 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+ len = order_base_2(query.largest_available_block << page_shift);
+ win_name = DMA64_PROPNAME;
+ } else {
+- direct_mapping = true;
+- win_name = DIRECT64_PROPNAME;
++ direct_mapping = !default_win_removed ||
++ (len == MAX_PHYSMEM_BITS) ||
++ (!pmem_present && (len == max_ram_len));
++ win_name = direct_mapping ? DIRECT64_PROPNAME : DMA64_PROPNAME;
+ }
+
+ ret = create_ddw(dev, ddw_avail, &create, page_shift, len);
+diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
+index e83e0891272d3..210a37a065fb7 100644
+--- a/arch/powerpc/platforms/pseries/mobility.c
++++ b/arch/powerpc/platforms/pseries/mobility.c
+@@ -63,6 +63,27 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
+
+ static int delete_dt_node(struct device_node *dn)
+ {
++ struct device_node *pdn;
++ bool is_platfac;
++
++ pdn = of_get_parent(dn);
++ is_platfac = of_node_is_type(dn, "ibm,platform-facilities") ||
++ of_node_is_type(pdn, "ibm,platform-facilities");
++ of_node_put(pdn);
++
++ /*
++ * The drivers that bind to nodes in the platform-facilities
++ * hierarchy don't support node removal, and the removal directive
++ * from firmware is always followed by an add of an equivalent
++ * node. The capability (e.g. RNG, encryption, compression)
++ * represented by the node is never interrupted by the migration.
++ * So ignore changes to this part of the tree.
++ */
++ if (is_platfac) {
++ pr_notice("ignoring remove operation for %pOFfp\n", dn);
++ return 0;
++ }
++
+ pr_debug("removing node %pOFfp\n", dn);
+ dlpar_detach_node(dn);
+ return 0;
+@@ -222,6 +243,19 @@ static int add_dt_node(struct device_node *parent_dn, __be32 drc_index)
+ if (!dn)
+ return -ENOENT;
+
++ /*
++ * Since delete_dt_node() ignores this node type, this is the
++ * necessary counterpart. We also know that a platform-facilities
++ * node returned from dlpar_configure_connector() has children
++ * attached, and dlpar_attach_node() only adds the parent, leaking
++ * the children. So ignore these on the add side for now.
++ */
++ if (of_node_is_type(dn, "ibm,platform-facilities")) {
++ pr_notice("ignoring add operation for %pOF\n", dn);
++ dlpar_free_cc_nodes(dn);
++ return 0;
++ }
++
+ rc = dlpar_attach_node(dn, parent_dn);
+ if (rc)
+ dlpar_free_cc_nodes(dn);
+diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S
+index efeeb1b885a17..329b9c4ae5429 100644
+--- a/arch/powerpc/sysdev/dcr-low.S
++++ b/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; \
+diff --git a/arch/powerpc/sysdev/xive/Kconfig b/arch/powerpc/sysdev/xive/Kconfig
+index 97796c6b63f04..785c292d104b7 100644
+--- a/arch/powerpc/sysdev/xive/Kconfig
++++ b/arch/powerpc/sysdev/xive/Kconfig
+@@ -3,7 +3,6 @@ config PPC_XIVE
+ bool
+ select PPC_SMP_MUXED_IPI
+ select HARDIRQS_SW_RESEND
+- select IRQ_DOMAIN_NOMAP
+
+ config PPC_XIVE_NATIVE
+ bool
+diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
+index c5d75c02ad8b5..7b69299c29123 100644
+--- a/arch/powerpc/sysdev/xive/common.c
++++ b/arch/powerpc/sysdev/xive/common.c
+@@ -1443,8 +1443,7 @@ static const struct irq_domain_ops xive_irq_domain_ops = {
+
+ static void __init xive_init_host(struct device_node *np)
+ {
+- xive_irq_domain = irq_domain_add_nomap(np, XIVE_MAX_IRQ,
+- &xive_irq_domain_ops, NULL);
++ xive_irq_domain = irq_domain_add_tree(np, &xive_irq_domain_ops, NULL);
+ if (WARN_ON(xive_irq_domain == NULL))
+ return;
+ irq_set_default_host(xive_irq_domain);
+diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
+index dd8241c009e53..8b28ff9d98d16 100644
+--- a/arch/powerpc/xmon/xmon.c
++++ b/arch/powerpc/xmon/xmon.c
+@@ -3264,8 +3264,7 @@ static void show_task(struct task_struct *volatile tsk)
+ * appropriate for calling from xmon. This could be moved
+ * to a common, generic, routine used by both.
+ */
+- state = (p_state == 0) ? 'R' :
+- (p_state < 0) ? 'U' :
++ state = (p_state == TASK_RUNNING) ? 'R' :
+ (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
+ (p_state & TASK_STOPPED) ? 'T' :
+ (p_state & TASK_TRACED) ? 'C' :
+diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
+index 0eb4568fbd290..41f3a75fe2ec8 100644
+--- a/arch/riscv/Makefile
++++ b/arch/riscv/Makefile
+@@ -108,11 +108,13 @@ PHONY += vdso_install
+ vdso_install:
+ $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
+
++ifeq ($(KBUILD_EXTMOD),)
+ ifeq ($(CONFIG_MMU),y)
+ prepare: vdso_prepare
+ vdso_prepare: prepare0
+ $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h
+ endif
++endif
+
+ ifneq ($(CONFIG_XIP_KERNEL),y)
+ ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy)
+diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts
+index b254c60589a1c..cce5eca31f257 100644
+--- a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts
++++ b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts
+@@ -12,7 +12,7 @@
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "Microchip PolarFire-SoC Icicle Kit";
+- compatible = "microchip,mpfs-icicle-kit";
++ compatible = "microchip,mpfs-icicle-kit", "microchip,mpfs";
+
+ aliases {
+ ethernet0 = &emac1;
+@@ -56,8 +56,17 @@
+ status = "okay";
+ };
+
+-&sdcard {
++&mmc {
+ status = "okay";
++
++ bus-width = <4>;
++ disable-wp;
++ cap-sd-highspeed;
++ card-detect-delay = <200>;
++ sd-uhs-sdr12;
++ sd-uhs-sdr25;
++ sd-uhs-sdr50;
++ sd-uhs-sdr104;
+ };
+
+ &emac0 {
+diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi
+index 9d2fbbc1f7778..b12fd594e7172 100644
+--- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi
++++ b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi
+@@ -6,8 +6,8 @@
+ / {
+ #address-cells = <2>;
+ #size-cells = <2>;
+- model = "Microchip MPFS Icicle Kit";
+- compatible = "microchip,mpfs-icicle-kit";
++ model = "Microchip PolarFire SoC";
++ compatible = "microchip,mpfs";
+
+ chosen {
+ };
+@@ -262,39 +262,14 @@
+ status = "disabled";
+ };
+
+- emmc: mmc@20008000 {
++ /* Common node entry for emmc/sd */
++ mmc: mmc@20008000 {
+ compatible = "cdns,sd4hc";
+ reg = <0x0 0x20008000 0x0 0x1000>;
+ interrupt-parent = <&plic>;
+ interrupts = <88 89>;
+ pinctrl-names = "default";
+ clocks = <&clkcfg 6>;
+- bus-width = <4>;
+- cap-mmc-highspeed;
+- mmc-ddr-3_3v;
+- max-frequency = <200000000>;
+- non-removable;
+- no-sd;
+- no-sdio;
+- voltage-ranges = <3300 3300>;
+- status = "disabled";
+- };
+-
+- sdcard: sdhc@20008000 {
+- compatible = "cdns,sd4hc";
+- reg = <0x0 0x20008000 0x0 0x1000>;
+- interrupt-parent = <&plic>;
+- interrupts = <88>;
+- pinctrl-names = "default";
+- clocks = <&clkcfg 6>;
+- bus-width = <4>;
+- disable-wp;
+- cap-sd-highspeed;
+- card-detect-delay = <200>;
+- sd-uhs-sdr12;
+- sd-uhs-sdr25;
+- sd-uhs-sdr50;
+- sd-uhs-sdr104;
+ max-frequency = <200000000>;
+ status = "disabled";
+ };
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+index 60846e88ae4b1..22f971e971614 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+@@ -80,6 +80,7 @@
+ spi-max-frequency = <20000000>;
+ voltage-ranges = <3300 3300>;
+ disable-wp;
++ gpios = <&gpio 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index 2e4ea84f27e77..b40990210fb50 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -2,6 +2,7 @@
+ /* Copyright (c) 2020 SiFive, Inc */
+
+ #include "fu740-c000.dtsi"
++#include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+@@ -228,6 +229,7 @@
+ spi-max-frequency = <20000000>;
+ voltage-ranges = <3300 3300>;
+ disable-wp;
++ gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index b86de61b8caa2..797041b5109a2 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -47,7 +47,7 @@ config ARCH_SUPPORTS_UPROBES
+ config KASAN_SHADOW_OFFSET
+ hex
+ depends on KASAN
+- default 0x18000000000000
++ default 0x1C000000000000
+
+ config S390
+ def_bool y
+diff --git a/arch/s390/Makefile b/arch/s390/Makefile
+index 450b351dfa8ef..d4fd1426a8226 100644
+--- a/arch/s390/Makefile
++++ b/arch/s390/Makefile
+@@ -79,10 +79,12 @@ KBUILD_AFLAGS_DECOMPRESSOR += $(aflags-y)
+ KBUILD_CFLAGS_DECOMPRESSOR += $(cflags-y)
+
+ ifneq ($(call cc-option,-mstack-size=8192 -mstack-guard=128),)
+-cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE)
+-ifeq ($(call cc-option,-mstack-size=8192),)
+-cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD)
+-endif
++ CC_FLAGS_CHECK_STACK := -mstack-size=$(STACK_SIZE)
++ ifeq ($(call cc-option,-mstack-size=8192),)
++ CC_FLAGS_CHECK_STACK += -mstack-guard=$(CONFIG_STACK_GUARD)
++ endif
++ export CC_FLAGS_CHECK_STACK
++ cflags-$(CONFIG_CHECK_STACK) += $(CC_FLAGS_CHECK_STACK)
+ endif
+
+ ifdef CONFIG_EXPOLINE
+diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
+index 6dc8d0a538640..b13352dd1e1cf 100644
+--- a/arch/s390/boot/startup.c
++++ b/arch/s390/boot/startup.c
+@@ -148,82 +148,56 @@ static void setup_ident_map_size(unsigned long max_physmem_end)
+
+ static void setup_kernel_memory_layout(void)
+ {
+- bool vmalloc_size_verified = false;
+- unsigned long vmemmap_off;
+- unsigned long vspace_left;
++ unsigned long vmemmap_start;
+ unsigned long rte_size;
+ unsigned long pages;
+- unsigned long vmax;
+
+ pages = ident_map_size / PAGE_SIZE;
+ /* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */
+ vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page);
+
+ /* choose kernel address space layout: 4 or 3 levels. */
+- vmemmap_off = round_up(ident_map_size, _REGION3_SIZE);
++ vmemmap_start = round_up(ident_map_size, _REGION3_SIZE);
+ if (IS_ENABLED(CONFIG_KASAN) ||
+ vmalloc_size > _REGION2_SIZE ||
+- vmemmap_off + vmemmap_size + vmalloc_size + MODULES_LEN > _REGION2_SIZE)
+- vmax = _REGION1_SIZE;
+- else
+- vmax = _REGION2_SIZE;
+-
+- /* keep vmemmap_off aligned to a top level region table entry */
+- rte_size = vmax == _REGION1_SIZE ? _REGION2_SIZE : _REGION3_SIZE;
+- MODULES_END = vmax;
+- if (is_prot_virt_host()) {
+- /*
+- * forcing modules and vmalloc area under the ultravisor
+- * secure storage limit, so that any vmalloc allocation
+- * we do could be used to back secure guest storage.
+- */
+- adjust_to_uv_max(&MODULES_END);
+- }
+-
+-#ifdef CONFIG_KASAN
+- if (MODULES_END < vmax) {
+- /* force vmalloc and modules below kasan shadow */
+- MODULES_END = min(MODULES_END, KASAN_SHADOW_START);
++ vmemmap_start + vmemmap_size + vmalloc_size + MODULES_LEN >
++ _REGION2_SIZE) {
++ MODULES_END = _REGION1_SIZE;
++ rte_size = _REGION2_SIZE;
+ } else {
+- /*
+- * leave vmalloc and modules above kasan shadow but make
+- * sure they don't overlap with it
+- */
+- vmalloc_size = min(vmalloc_size, vmax - KASAN_SHADOW_END - MODULES_LEN);
+- vmalloc_size_verified = true;
+- vspace_left = KASAN_SHADOW_START;
++ MODULES_END = _REGION2_SIZE;
++ rte_size = _REGION3_SIZE;
+ }
++ /*
++ * forcing modules and vmalloc area under the ultravisor
++ * secure storage limit, so that any vmalloc allocation
++ * we do could be used to back secure guest storage.
++ */
++ adjust_to_uv_max(&MODULES_END);
++#ifdef CONFIG_KASAN
++ /* force vmalloc and modules below kasan shadow */
++ MODULES_END = min(MODULES_END, KASAN_SHADOW_START);
+ #endif
+ MODULES_VADDR = MODULES_END - MODULES_LEN;
+ VMALLOC_END = MODULES_VADDR;
+
+- if (vmalloc_size_verified) {
+- VMALLOC_START = VMALLOC_END - vmalloc_size;
+- } else {
+- vmemmap_off = round_up(ident_map_size, rte_size);
+-
+- if (vmemmap_off + vmemmap_size > VMALLOC_END ||
+- vmalloc_size > VMALLOC_END - vmemmap_off - vmemmap_size) {
+- /*
+- * allow vmalloc area to occupy up to 1/2 of
+- * the rest virtual space left.
+- */
+- vmalloc_size = min(vmalloc_size, VMALLOC_END / 2);
+- }
+- VMALLOC_START = VMALLOC_END - vmalloc_size;
+- vspace_left = VMALLOC_START;
+- }
++ /* allow vmalloc area to occupy up to about 1/2 of the rest virtual space left */
++ vmalloc_size = min(vmalloc_size, round_down(VMALLOC_END / 2, _REGION3_SIZE));
++ VMALLOC_START = VMALLOC_END - vmalloc_size;
+
+- pages = vspace_left / (PAGE_SIZE + sizeof(struct page));
++ /* split remaining virtual space between 1:1 mapping & vmemmap array */
++ pages = VMALLOC_START / (PAGE_SIZE + sizeof(struct page));
+ pages = SECTION_ALIGN_UP(pages);
+- vmemmap_off = round_up(vspace_left - pages * sizeof(struct page), rte_size);
+- /* keep vmemmap left most starting from a fresh region table entry */
+- vmemmap_off = min(vmemmap_off, round_up(ident_map_size, rte_size));
+- /* take care that identity map is lower then vmemmap */
+- ident_map_size = min(ident_map_size, vmemmap_off);
++ /* keep vmemmap_start aligned to a top level region table entry */
++ vmemmap_start = round_down(VMALLOC_START - pages * sizeof(struct page), rte_size);
++ /* vmemmap_start is the future VMEM_MAX_PHYS, make sure it is within MAX_PHYSMEM */
++ vmemmap_start = min(vmemmap_start, 1UL << MAX_PHYSMEM_BITS);
++ /* make sure identity map doesn't overlay with vmemmap */
++ ident_map_size = min(ident_map_size, vmemmap_start);
+ vmemmap_size = SECTION_ALIGN_UP(ident_map_size / PAGE_SIZE) * sizeof(struct page);
+- VMALLOC_START = max(vmemmap_off + vmemmap_size, VMALLOC_START);
+- vmemmap = (struct page *)vmemmap_off;
++ /* make sure vmemmap doesn't overlay with vmalloc area */
++ VMALLOC_START = max(vmemmap_start + vmemmap_size, VMALLOC_START);
++ vmemmap = (struct page *)vmemmap_start;
+ }
+
+ /*
+diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h
+index ea398a05f6432..7f3c9ac34bd8d 100644
+--- a/arch/s390/include/asm/kexec.h
++++ b/arch/s390/include/asm/kexec.h
+@@ -74,6 +74,12 @@ void *kexec_file_add_components(struct kimage *image,
+ 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;
+
+diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h
+index e4dc64cc9c555..287bb88f76986 100644
+--- a/arch/s390/include/asm/pci_io.h
++++ b/arch/s390/include/asm/pci_io.h
+@@ -14,12 +14,13 @@
+
+ /* 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;
+diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
+index d72a6df058d79..785d54c9350c4 100644
+--- a/arch/s390/kernel/crash_dump.c
++++ b/arch/s390/kernel/crash_dump.c
+@@ -191,8 +191,8 @@ static int copy_oldmem_user(void __user *dst, void *src, size_t count)
+ return rc;
+ } else {
+ /* Check for swapped kdump oldmem areas */
+- if (oldmem_data.start && from - oldmem_data.size < oldmem_data.size) {
+- from -= oldmem_data.size;
++ if (oldmem_data.start && from - oldmem_data.start < oldmem_data.size) {
++ from -= oldmem_data.start;
+ len = min(count, oldmem_data.size - from);
+ } else if (oldmem_data.start && from < oldmem_data.size) {
+ len = min(count, oldmem_data.size - from);
+diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
+index e2cc35775b996..5ad1dde23dc59 100644
+--- a/arch/s390/kernel/ipl.c
++++ b/arch/s390/kernel/ipl.c
+@@ -2156,7 +2156,7 @@ void *ipl_report_finish(struct ipl_report *report)
+
+ buf = vzalloc(report->size);
+ if (!buf)
+- return ERR_PTR(-ENOMEM);
++ goto out;
+ ptr = buf;
+
+ memcpy(ptr, report->ipib, report->ipib->hdr.len);
+@@ -2195,6 +2195,7 @@ void *ipl_report_finish(struct ipl_report *report)
+ }
+
+ BUG_ON(ptr > buf + report->size);
++out:
+ return buf;
+ }
+
+diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
+index 3a3145c4a3ba4..be5d432b902e0 100644
+--- a/arch/s390/kernel/irq.c
++++ b/arch/s390/kernel/irq.c
+@@ -138,7 +138,7 @@ void noinstr do_io_irq(struct pt_regs *regs)
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ int from_idle;
+
+- irq_enter();
++ irq_enter_rcu();
+
+ if (user_mode(regs))
+ update_timer_sys();
+@@ -155,7 +155,8 @@ void noinstr do_io_irq(struct pt_regs *regs)
+ do_irq_async(regs, IO_INTERRUPT);
+ } while (MACHINE_IS_LPAR && irq_pending(regs));
+
+- irq_exit();
++ irq_exit_rcu();
++
+ set_irq_regs(old_regs);
+ irqentry_exit(regs, state);
+
+@@ -169,7 +170,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ int from_idle;
+
+- irq_enter();
++ irq_enter_rcu();
+
+ if (user_mode(regs))
+ update_timer_sys();
+@@ -184,7 +185,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
+
+ do_irq_async(regs, EXT_INTERRUPT);
+
+- irq_exit();
++ irq_exit_rcu();
+ set_irq_regs(old_regs);
+ irqentry_exit(regs, state);
+
+diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
+index f9e4baa64b675..76cd09879eaf4 100644
+--- a/arch/s390/kernel/machine_kexec_file.c
++++ b/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>
+@@ -170,6 +171,7 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ struct kexec_buf buf;
+ unsigned long addr;
+ void *ptr, *end;
++ int ret;
+
+ buf.image = image;
+
+@@ -199,9 +201,13 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ 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 +215,9 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
+ *lc_ipl_parmblock_ptr = (__u32)buf.mem;
+
+- return kexec_add_buffer(&buf);
++ ret = kexec_add_buffer(&buf);
++out:
++ return ret;
+ }
+
+ void *kexec_file_add_components(struct kimage *image,
+@@ -269,6 +277,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
+ {
+ Elf_Rela *relas;
+ int i, r_type;
++ int ret;
+
+ relas = (void *)pi->ehdr + relsec->sh_offset;
+
+@@ -303,7 +312,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
+ 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 +334,11 @@ int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
+
+ 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);
++}
+diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
+index 4a99154fe6514..cceb8ec707e4b 100644
+--- a/arch/s390/kernel/perf_cpum_cf.c
++++ b/arch/s390/kernel/perf_cpum_cf.c
+@@ -687,8 +687,10 @@ static void cpumf_pmu_stop(struct perf_event *event, int flags)
+ false);
+ if (cfdiag_diffctr(cpuhw, event->hw.config_base))
+ cfdiag_push_sample(event, cpuhw);
+- } else
++ } else if (cpuhw->flags & PMU_F_RESERVED) {
++ /* Only update when PMU not hotplugged off */
+ hw_perf_event_update(event);
++ }
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+ }
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index 67e5fff96ee06..ee67215a678a5 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -633,14 +633,6 @@ static struct notifier_block kdump_mem_nb = {
+
+ #endif
+
+-/*
+- * Make sure that the area above identity mapping is protected
+- */
+-static void __init reserve_above_ident_map(void)
+-{
+- memblock_reserve(ident_map_size, ULONG_MAX);
+-}
+-
+ /*
+ * Reserve memory for kdump kernel to be loaded with kexec
+ */
+@@ -824,9 +816,6 @@ static void __init setup_memory(void)
+ storage_key_init_range(start, end);
+
+ psw_set_key(PAGE_DEFAULT_KEY);
+-
+- /* Only cosmetics */
+- memblock_enforce_memory_limit(memblock_end_of_DRAM());
+ }
+
+ static void __init relocate_amode31_section(void)
+@@ -1005,11 +994,11 @@ void __init setup_arch(char **cmdline_p)
+ setup_control_program_code();
+
+ /* Do some memory reservations *before* memory is added to memblock */
+- reserve_above_ident_map();
+ reserve_kernel();
+ reserve_initrd();
+ reserve_certificate_list();
+ reserve_mem_detect_info();
++ memblock_set_current_limit(ident_map_size);
+ memblock_allow_resize();
+
+ /* Get information about *all* installed memory */
+diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
+index bcefc2173de45..12d28ff5281fa 100644
+--- a/arch/s390/kernel/traps.c
++++ b/arch/s390/kernel/traps.c
+@@ -84,7 +84,7 @@ static void default_trap_handler(struct pt_regs *regs)
+ {
+ if (user_mode(regs)) {
+ report_user_fault(regs, SIGSEGV, 0);
+- do_exit(SIGSEGV);
++ force_exit_sig(SIGSEGV);
+ } else
+ die(regs, "Unknown program exception");
+ }
+diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c
+index 5a656c7b7a67a..f95ccbd396925 100644
+--- a/arch/s390/kernel/uv.c
++++ b/arch/s390/kernel/uv.c
+@@ -212,7 +212,7 @@ again:
+ uaddr = __gmap_translate(gmap, gaddr);
+ if (IS_ERR_VALUE(uaddr))
+ goto out;
+- vma = find_vma(gmap->mm, uaddr);
++ vma = vma_lookup(gmap->mm, uaddr);
+ if (!vma)
+ goto out;
+ /*
+diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
+index 6568de2367010..0dea82b87e54b 100644
+--- a/arch/s390/kernel/vdso64/Makefile
++++ b/arch/s390/kernel/vdso64/Makefile
+@@ -8,8 +8,9 @@ ARCH_REL_TYPE_ABS += R_390_GOT|R_390_PLT
+ include $(srctree)/lib/vdso/Makefile
+ obj-vdso64 = vdso_user_wrapper.o note.o
+ obj-cvdso64 = vdso64_generic.o getcpu.o
+-CFLAGS_REMOVE_getcpu.o = -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE)
+-CFLAGS_REMOVE_vdso64_generic.o = -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE)
++VDSO_CFLAGS_REMOVE := -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE) $(CC_FLAGS_CHECK_STACK)
++CFLAGS_REMOVE_getcpu.o = $(VDSO_CFLAGS_REMOVE)
++CFLAGS_REMOVE_vdso64_generic.o = $(VDSO_CFLAGS_REMOVE)
+
+ # Build rules
+
+diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
+index 53da4ceb16a3a..417154b314a64 100644
+--- a/arch/s390/kvm/priv.c
++++ b/arch/s390/kvm/priv.c
+@@ -397,6 +397,8 @@ static int handle_sske(struct kvm_vcpu *vcpu)
+ mmap_read_unlock(current->mm);
+ if (rc == -EFAULT)
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
++ if (rc == -EAGAIN)
++ continue;
+ if (rc < 0)
+ return rc;
+ start += PAGE_SIZE;
+diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
+index c8841f476e913..00d272d134c24 100644
+--- a/arch/s390/kvm/pv.c
++++ b/arch/s390/kvm/pv.c
+@@ -16,18 +16,17 @@
+
+ int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
+ {
+- int cc = 0;
++ int cc;
+
+- 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);
++ if (!kvm_s390_pv_cpu_get_handle(vcpu))
++ return 0;
++
++ 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);
+
+- 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,
+@@ -196,7 +195,7 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
+ 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(0, (u64)&uvcb);
++ 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",
+diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c
+index ecf327d743a03..c0635cf787e31 100644
+--- a/arch/s390/lib/test_unwind.c
++++ b/arch/s390/lib/test_unwind.c
+@@ -171,10 +171,11 @@ static noinline int unwindme_func4(struct unwindme *u)
+ }
+
+ /*
+- * trigger specification exception
++ * Trigger operation exception; use insn notation to bypass
++ * llvm's integrated assembler sanity checks.
+ */
+ asm volatile(
+- " mvcl %%r1,%%r1\n"
++ " .insn e,0x0000\n" /* illegal opcode */
+ "0: nopr %%r7\n"
+ EX_TABLE(0b, 0b)
+ :);
+diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
+index 4d3b33ce81c62..d63c0ccc5ccda 100644
+--- a/arch/s390/mm/gmap.c
++++ b/arch/s390/mm/gmap.c
+@@ -672,6 +672,7 @@ EXPORT_SYMBOL_GPL(gmap_fault);
+ */
+ void __gmap_zap(struct gmap *gmap, unsigned long gaddr)
+ {
++ struct vm_area_struct *vma;
+ unsigned long vmaddr;
+ spinlock_t *ptl;
+ pte_t *ptep;
+@@ -681,11 +682,17 @@ void __gmap_zap(struct gmap *gmap, unsigned long gaddr)
+ gaddr >> PMD_SHIFT);
+ if (vmaddr) {
+ vmaddr |= gaddr & ~PMD_MASK;
++
++ vma = vma_lookup(gmap->mm, vmaddr);
++ if (!vma || is_vm_hugetlb_page(vma))
++ return;
++
+ /* 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);
+diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
+index 034721a68d8fd..6ad634a27d5b9 100644
+--- a/arch/s390/mm/pgtable.c
++++ b/arch/s390/mm/pgtable.c
+@@ -429,22 +429,36 @@ static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm,
+ }
+
+ #ifdef CONFIG_PGSTE
+-static pmd_t *pmd_alloc_map(struct mm_struct *mm, unsigned long addr)
++static int pmd_lookup(struct mm_struct *mm, unsigned long addr, pmd_t **pmdp)
+ {
++ struct vm_area_struct *vma;
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+- pmd_t *pmd;
++
++ /* We need a valid VMA, otherwise this is clearly a fault. */
++ vma = vma_lookup(mm, addr);
++ if (!vma)
++ return -EFAULT;
+
+ pgd = pgd_offset(mm, addr);
+- p4d = p4d_alloc(mm, pgd, addr);
+- if (!p4d)
+- return NULL;
+- pud = pud_alloc(mm, p4d, addr);
+- if (!pud)
+- return NULL;
+- pmd = pmd_alloc(mm, pud, addr);
+- return pmd;
++ if (!pgd_present(*pgd))
++ return -ENOENT;
++
++ p4d = p4d_offset(pgd, addr);
++ if (!p4d_present(*p4d))
++ return -ENOENT;
++
++ pud = pud_offset(p4d, addr);
++ if (!pud_present(*pud))
++ return -ENOENT;
++
++ /* Large PUDs are not supported yet. */
++ if (pud_large(*pud))
++ return -EFAULT;
++
++ *pmdp = pmd_offset(pud, addr);
++ return 0;
+ }
+ #endif
+
+@@ -778,8 +792,7 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+- pmdp = pmd_alloc_map(mm, addr);
+- if (unlikely(!pmdp))
++ if (pmd_lookup(mm, addr, &pmdp))
+ return -EFAULT;
+
+ ptl = pmd_lock(mm, pmdp);
+@@ -881,8 +894,7 @@ int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr)
+ pte_t *ptep;
+ int cc = 0;
+
+- pmdp = pmd_alloc_map(mm, addr);
+- if (unlikely(!pmdp))
++ if (pmd_lookup(mm, addr, &pmdp))
+ return -EFAULT;
+
+ ptl = pmd_lock(mm, pmdp);
+@@ -935,15 +947,24 @@ int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+- pmdp = pmd_alloc_map(mm, addr);
+- if (unlikely(!pmdp))
++ /*
++ * If we don't have a PTE table and if there is no huge page mapped,
++ * the storage key is 0.
++ */
++ *key = 0;
++
++ switch (pmd_lookup(mm, addr, &pmdp)) {
++ case -ENOENT:
++ return 0;
++ case 0:
++ break;
++ default:
+ return -EFAULT;
++ }
+
+ ptl = pmd_lock(mm, pmdp);
+ if (!pmd_present(*pmdp)) {
+- /* Not yet mapped memory has a zero key */
+ spin_unlock(ptl);
+- *key = 0;
+ return 0;
+ }
+
+@@ -988,6 +1009,7 @@ EXPORT_SYMBOL(get_guest_storage_key);
+ 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;
+@@ -997,6 +1019,10 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
+ WARN_ON_ONCE(orc > ESSA_MAX);
+ if (unlikely(orc > ESSA_MAX))
+ return -EINVAL;
++
++ vma = vma_lookup(mm, hva);
++ if (!vma || is_vm_hugetlb_page(vma))
++ return -EFAULT;
+ ptep = get_locked_pte(mm, hva, &ptl);
+ if (unlikely(!ptep))
+ return -EFAULT;
+@@ -1089,10 +1115,14 @@ EXPORT_SYMBOL(pgste_perform_essa);
+ 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 = vma_lookup(mm, hva);
++ if (!vma || is_vm_hugetlb_page(vma))
++ return -EFAULT;
+ ptep = get_locked_pte(mm, hva, &ptl);
+ if (unlikely(!ptep))
+ return -EFAULT;
+@@ -1117,9 +1147,13 @@ EXPORT_SYMBOL(set_pgste_bits);
+ */
+ 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 = vma_lookup(mm, hva);
++ if (!vma || is_vm_hugetlb_page(vma))
++ return -EFAULT;
+ ptep = get_locked_pte(mm, hva, &ptl);
+ if (unlikely(!ptep))
+ return -EFAULT;
+diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
+index 958f790273ab9..10290e5c1f438 100644
+--- a/arch/sh/Kconfig.debug
++++ b/arch/sh/Kconfig.debug
+@@ -54,6 +54,7 @@ config DUMP_CODE
+
+ config DWARF_UNWINDER
+ bool "Enable the DWARF unwinder for stacktraces"
++ depends on DEBUG_KERNEL
+ select FRAME_POINTER
+ default n
+ help
+diff --git a/arch/sh/include/asm/sfp-machine.h b/arch/sh/include/asm/sfp-machine.h
+index cbc7cf8c97ce6..2d2423478b71d 100644
+--- a/arch/sh/include/asm/sfp-machine.h
++++ b/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
+diff --git a/arch/sh/kernel/cpu/fpu.c b/arch/sh/kernel/cpu/fpu.c
+index ae354a2931e7e..fd6db0ab19288 100644
+--- a/arch/sh/kernel/cpu/fpu.c
++++ b/arch/sh/kernel/cpu/fpu.c
+@@ -62,18 +62,20 @@ void fpu_state_restore(struct pt_regs *regs)
+ }
+
+ 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);
+diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+index f8a2bec0f260b..1261dc7b84e8b 100644
+--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
++++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+@@ -73,8 +73,9 @@ static void shx3_prepare_cpus(unsigned int max_cpus)
+ 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);
+diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
+index e8be0eca0444a..615ba932c398e 100644
+--- a/arch/sh/math-emu/math.c
++++ b/arch/sh/math-emu/math.c
+@@ -467,109 +467,6 @@ static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_reg
+ return id_sys(fregs, regs, code);
+ }
+
+-/**
+- * 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.
+diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
+index 849236d4eca48..45e5c76d449ea 100644
+--- a/arch/sparc/boot/Makefile
++++ b/arch/sparc/boot/Makefile
+@@ -22,7 +22,7 @@ ifeq ($(CONFIG_SPARC64),y)
+
+ # Actual linking
+
+-$(obj)/zImage: $(obj)/image
++$(obj)/zImage: $(obj)/image FORCE
+ $(call if_changed,gzip)
+ @echo ' kernel: $@ is ready'
+
+@@ -31,7 +31,7 @@ $(obj)/vmlinux.aout: vmlinux FORCE
+ @echo ' kernel: $@ is ready'
+ else
+
+-$(obj)/zImage: $(obj)/image
++$(obj)/zImage: $(obj)/image FORCE
+ $(call if_changed,strip)
+ @echo ' kernel: $@ is ready'
+
+@@ -44,7 +44,7 @@ OBJCOPYFLAGS_image.bin := -S -O binary -R .note -R .comment
+ $(obj)/image.bin: $(obj)/image FORCE
+ $(call if_changed,objcopy)
+
+-$(obj)/image.gz: $(obj)/image.bin
++$(obj)/image.gz: $(obj)/image.bin FORCE
+ $(call if_changed,gzip)
+
+ UIMAGE_LOADADDR = $(CONFIG_UBOOT_LOAD_ADDR)
+@@ -56,7 +56,7 @@ quiet_cmd_uimage.o = UIMAGE.O $@
+ -r -b binary $@ -o $@.o
+
+ targets += uImage
+-$(obj)/uImage: $(obj)/image.gz
++$(obj)/uImage: $(obj)/image.gz FORCE
+ $(call if_changed,uimage)
+ $(call if_changed,uimage.o)
+ @echo ' Image $@ is ready'
+diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
+index 02f3ad55dfe31..ffab16369beac 100644
+--- a/arch/sparc/kernel/signal_32.c
++++ b/arch/sparc/kernel/signal_32.c
+@@ -244,7 +244,7 @@ static int setup_frame(struct ksignal *ksig, struct pt_regs *regs,
+ get_sigframe(ksig, regs, sigframe_size);
+
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+- do_exit(SIGILL);
++ force_exit_sig(SIGILL);
+ return -EINVAL;
+ }
+
+@@ -336,7 +336,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
+ sf = (struct rt_signal_frame __user *)
+ get_sigframe(ksig, regs, sigframe_size);
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+- do_exit(SIGILL);
++ force_exit_sig(SIGILL);
+ return -EINVAL;
+ }
+
+diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c
+index 69a6ba6e92937..8f20862ccc83e 100644
+--- a/arch/sparc/kernel/windows.c
++++ b/arch/sparc/kernel/windows.c
+@@ -121,8 +121,10 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who)
+
+ if ((sp & 7) ||
+ copy_to_user((char __user *) sp, &tp->reg_window[window],
+- sizeof(struct reg_window32)))
+- do_exit(SIGILL);
++ sizeof(struct reg_window32))) {
++ force_exit_sig(SIGILL);
++ return;
++ }
+ }
+ tp->w_saved = 0;
+ }
+diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
+index 3198c47673879..c32efb09db214 100644
+--- a/arch/um/kernel/trap.c
++++ b/arch/um/kernel/trap.c
+@@ -158,7 +158,7 @@ static void bad_segv(struct faultinfo fi, unsigned long ip)
+
+ void fatal_sigsegv(void)
+ {
+- force_sigsegv(SIGSEGV);
++ force_fatal_sig(SIGSEGV);
+ do_signal(&current->thread.regs);
+ /*
+ * This is to tell gcc that we're not returning - do_signal
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index d9830e7e1060f..1f96809606ac5 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -1256,7 +1256,8 @@ config TOSHIBA
+
+ config I8K
+ tristate "Dell i8k legacy laptop support"
+- select HWMON
++ depends on HWMON
++ depends on PROC_FS
+ select SENSORS_DELL_SMM
+ help
+ This option enables legacy /proc/i8k userspace interface in hwmon
+@@ -1518,6 +1519,7 @@ config AMD_MEM_ENCRYPT
+ select ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ select INSTRUCTION_DECODER
+ select ARCH_HAS_RESTRICTED_VIRTIO_MEMORY_ACCESS
++ select ARCH_HAS_CC_PLATFORM
+ help
+ Say yes to enable support for the encryption of system memory.
+ This requires an AMD processor that supports Secure Memory
+@@ -1917,6 +1919,7 @@ config EFI
+ 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).
+diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
+index 0fc961bef299c..e09f4672dd382 100644
+--- a/arch/x86/crypto/aesni-intel_glue.c
++++ b/arch/x86/crypto/aesni-intel_glue.c
+@@ -866,7 +866,7 @@ static int xts_crypt(struct skcipher_request *req, bool encrypt)
+ req = &subreq;
+
+ err = skcipher_walk_virt(&walk, req, false);
+- if (err)
++ if (!walk.nbytes)
+ return err;
+ } else {
+ tail = 0;
+diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
+index e38a4cf795d96..97b1f84bb53f8 100644
+--- a/arch/x86/entry/entry_64.S
++++ b/arch/x86/entry/entry_64.S
+@@ -574,6 +574,10 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
+ ud2
+ 1:
+ #endif
++#ifdef CONFIG_XEN_PV
++ ALTERNATIVE "", "jmp xenpv_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
++#endif
++
+ POP_REGS pop_rdi=0
+
+ /*
+@@ -890,6 +894,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
+ .Lparanoid_entry_checkgs:
+ /* EBX = 1 -> kernel GSBASE active, no restore required */
+ movl $1, %ebx
++
+ /*
+ * The kernel-enforced convention is a negative GSBASE indicates
+ * a kernel value. No SWAPGS needed on entry and exit.
+@@ -897,21 +902,14 @@ SYM_CODE_START_LOCAL(paranoid_entry)
+ movl $MSR_GS_BASE, %ecx
+ rdmsr
+ testl %edx, %edx
+- jns .Lparanoid_entry_swapgs
+- ret
++ js .Lparanoid_kernel_gsbase
+
+-.Lparanoid_entry_swapgs:
++ /* EBX = 0 -> SWAPGS required on exit */
++ xorl %ebx, %ebx
+ swapgs
++.Lparanoid_kernel_gsbase:
+
+- /*
+- * The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an
+- * unconditional CR3 write, even in the PTI case. So do an lfence
+- * to prevent GS speculation, regardless of whether PTI is enabled.
+- */
+ FENCE_SWAPGS_KERNEL_ENTRY
+-
+- /* EBX = 0 -> SWAPGS required on exit */
+- xorl %ebx, %ebx
+ ret
+ SYM_CODE_END(paranoid_entry)
+
+@@ -993,11 +991,6 @@ SYM_CODE_START_LOCAL(error_entry)
+ pushq %r12
+ ret
+
+-.Lerror_entry_done_lfence:
+- FENCE_SWAPGS_KERNEL_ENTRY
+-.Lerror_entry_done:
+- ret
+-
+ /*
+ * There are two places in the kernel that can potentially fault with
+ * usergs. Handle them here. B stepping K8s sometimes report a
+@@ -1020,8 +1013,14 @@ SYM_CODE_START_LOCAL(error_entry)
+ * .Lgs_change's error handler with kernel gsbase.
+ */
+ SWAPGS
+- FENCE_SWAPGS_USER_ENTRY
+- jmp .Lerror_entry_done
++
++ /*
++ * Issue an LFENCE to prevent GS speculation, regardless of whether it is a
++ * kernel or user gsbase.
++ */
++.Lerror_entry_done_lfence:
++ FENCE_SWAPGS_KERNEL_ENTRY
++ ret
+
+ .Lbstep_iret:
+ /* Fix truncated RIP */
+diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
+index 1b40b92970831..fd2ee9408e914 100644
+--- a/arch/x86/entry/vsyscall/vsyscall_64.c
++++ b/arch/x86/entry/vsyscall/vsyscall_64.c
+@@ -226,7 +226,8 @@ bool emulate_vsyscall(unsigned long error_code,
+ if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
+ warn_bad_vsyscall(KERN_DEBUG, regs,
+ "seccomp tried to change syscall nr or ip");
+- do_exit(SIGSYS);
++ force_exit_sig(SIGSYS);
++ return true;
+ }
+ regs->orig_ax = -1;
+ if (tmp)
+diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
+index 9a044438072ba..c7f1cc433a6aa 100644
+--- a/arch/x86/events/intel/core.c
++++ b/arch/x86/events/intel/core.c
+@@ -243,7 +243,8 @@ static struct extra_reg intel_skl_extra_regs[] __read_mostly = {
+
+ static struct event_constraint intel_icl_event_constraints[] = {
+ FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+- FIXED_EVENT_CONSTRAINT(0x01c0, 0), /* INST_RETIRED.PREC_DIST */
++ FIXED_EVENT_CONSTRAINT(0x01c0, 0), /* old INST_RETIRED.PREC_DIST */
++ FIXED_EVENT_CONSTRAINT(0x0100, 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 */
+@@ -288,7 +289,7 @@ static struct extra_reg intel_spr_extra_regs[] __read_mostly = {
+
+ static struct event_constraint intel_spr_event_constraints[] = {
+ FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+- FIXED_EVENT_CONSTRAINT(0x01c0, 0), /* INST_RETIRED.PREC_DIST */
++ FIXED_EVENT_CONSTRAINT(0x0100, 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 */
+@@ -2998,8 +2999,10 @@ intel_vlbr_constraints(struct perf_event *event)
+ {
+ struct event_constraint *c = &vlbr_constraint;
+
+- if (unlikely(constraint_match(c, event->hw.config)))
++ if (unlikely(constraint_match(c, event->hw.config))) {
++ event->hw.flags |= c->flags;
+ return c;
++ }
+
+ return NULL;
+ }
+diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
+index 8647713276a73..4dbb55a43dad2 100644
+--- a/arch/x86/events/intel/ds.c
++++ b/arch/x86/events/intel/ds.c
+@@ -923,7 +923,8 @@ struct event_constraint intel_skl_pebs_event_constraints[] = {
+ };
+
+ struct event_constraint intel_icl_pebs_event_constraints[] = {
+- INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */
++ INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x100000000ULL), /* old INST_RETIRED.PREC_DIST */
++ INTEL_FLAGS_UEVENT_CONSTRAINT(0x0100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL), /* SLOTS */
+
+ INTEL_PLD_CONSTRAINT(0x1cd, 0xff), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+@@ -943,7 +944,7 @@ struct event_constraint intel_icl_pebs_event_constraints[] = {
+ };
+
+ struct event_constraint intel_spr_pebs_event_constraints[] = {
+- INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x100000000ULL),
++ INTEL_FLAGS_UEVENT_CONSTRAINT(0x100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL),
+
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xfe),
+diff --git a/arch/x86/events/intel/uncore_discovery.h b/arch/x86/events/intel/uncore_discovery.h
+index 7280c8a3c8310..6d735611c281c 100644
+--- a/arch/x86/events/intel/uncore_discovery.h
++++ b/arch/x86/events/intel/uncore_discovery.h
+@@ -30,7 +30,7 @@
+
+
+ #define uncore_discovery_invalid_unit(unit) \
+- (!unit.table1 || !unit.ctl || !unit.table3 || \
++ (!unit.table1 || !unit.ctl || \
+ unit.table1 == -1ULL || unit.ctl == -1ULL || \
+ unit.table3 == -1ULL)
+
+diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
+index 5ddc0f30db6fc..3660f698fb2aa 100644
+--- a/arch/x86/events/intel/uncore_snbep.c
++++ b/arch/x86/events/intel/uncore_snbep.c
+@@ -452,7 +452,7 @@
+ #define ICX_M3UPI_PCI_PMON_BOX_CTL 0xa0
+
+ /* ICX IMC */
+-#define ICX_NUMBER_IMC_CHN 2
++#define ICX_NUMBER_IMC_CHN 3
+ #define ICX_IMC_MEM_STRIDE 0x4
+
+ /* SPR */
+@@ -3608,6 +3608,9 @@ static int skx_cha_hw_config(struct intel_uncore_box *box, struct perf_event *ev
+ 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))
+@@ -3675,6 +3678,7 @@ static struct event_constraint skx_uncore_iio_constraints[] = {
+ UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
+ UNCORE_EVENT_CONSTRAINT(0xc5, 0xc),
+ UNCORE_EVENT_CONSTRAINT(0xd4, 0xc),
++ UNCORE_EVENT_CONSTRAINT(0xd5, 0xc),
+ EVENT_CONSTRAINT_END
+ };
+
+@@ -4525,6 +4529,13 @@ static void snr_iio_cleanup_mapping(struct intel_uncore_type *type)
+ pmu_iio_cleanup_mapping(type, &snr_iio_mapping_group);
+ }
+
++static struct event_constraint snr_uncore_iio_constraints[] = {
++ UNCORE_EVENT_CONSTRAINT(0x83, 0x3),
++ UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
++ UNCORE_EVENT_CONSTRAINT(0xd5, 0xc),
++ EVENT_CONSTRAINT_END
++};
++
+ static struct intel_uncore_type snr_uncore_iio = {
+ .name = "iio",
+ .num_counters = 4,
+@@ -4536,6 +4547,7 @@ static struct intel_uncore_type snr_uncore_iio = {
+ .event_mask_ext = SNR_IIO_PMON_RAW_EVENT_MASK_EXT,
+ .box_ctl = SNR_IIO_MSR_PMON_BOX_CTL,
+ .msr_offset = SNR_IIO_MSR_OFFSET,
++ .constraints = snr_uncore_iio_constraints,
+ .ops = &ivbep_uncore_msr_ops,
+ .format_group = &snr_uncore_iio_format_group,
+ .attr_update = snr_iio_attr_update,
+@@ -5076,8 +5088,10 @@ static struct event_constraint icx_uncore_iio_constraints[] = {
+ UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x03, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x83, 0x3),
++ UNCORE_EVENT_CONSTRAINT(0x88, 0xc),
+ UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
+ UNCORE_EVENT_CONSTRAINT(0xc5, 0xc),
++ UNCORE_EVENT_CONSTRAINT(0xd5, 0xc),
+ EVENT_CONSTRAINT_END
+ };
+
+@@ -5463,7 +5477,7 @@ static struct intel_uncore_ops icx_uncore_mmio_ops = {
+ static struct intel_uncore_type icx_uncore_imc = {
+ .name = "imc",
+ .num_counters = 4,
+- .num_boxes = 8,
++ .num_boxes = 12,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .fixed_ctr = SNR_IMC_MMIO_PMON_FIXED_CTR,
+@@ -5647,6 +5661,7 @@ static struct intel_uncore_type spr_uncore_chabox = {
+ .event_mask = SPR_CHA_PMON_EVENT_MASK,
+ .event_mask_ext = SPR_RAW_EVENT_MASK_EXT,
+ .num_shared_regs = 1,
++ .constraints = skx_uncore_chabox_constraints,
+ .ops = &spr_uncore_chabox_ops,
+ .format_group = &spr_uncore_chabox_format_group,
+ .attr_update = uncore_alias_groups,
+@@ -5658,6 +5673,7 @@ static struct intel_uncore_type spr_uncore_iio = {
+ .event_mask_ext = SNR_IIO_PMON_RAW_EVENT_MASK_EXT,
+ .format_group = &snr_uncore_iio_format_group,
+ .attr_update = uncore_alias_groups,
++ .constraints = icx_uncore_iio_constraints,
+ };
+
+ static struct attribute *spr_uncore_raw_formats_attr[] = {
+@@ -5686,9 +5702,16 @@ static struct intel_uncore_type spr_uncore_irp = {
+
+ };
+
++static struct event_constraint spr_uncore_m2pcie_constraints[] = {
++ UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
++ UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
++ EVENT_CONSTRAINT_END
++};
++
+ static struct intel_uncore_type spr_uncore_m2pcie = {
+ SPR_UNCORE_COMMON_FORMAT(),
+ .name = "m2pcie",
++ .constraints = spr_uncore_m2pcie_constraints,
+ };
+
+ static struct intel_uncore_type spr_uncore_pcu = {
+@@ -5765,6 +5788,7 @@ static struct intel_uncore_type spr_uncore_upi = {
+ static struct intel_uncore_type spr_uncore_m3upi = {
+ SPR_UNCORE_PCI_COMMON_FORMAT(),
+ .name = "m3upi",
++ .constraints = icx_uncore_m3upi_constraints,
+ };
+
+ static struct intel_uncore_type spr_uncore_mdf = {
+diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
+index 708a2712a516d..b6d48ca5b0f17 100644
+--- a/arch/x86/hyperv/hv_init.c
++++ b/arch/x86/hyperv/hv_init.c
+@@ -139,7 +139,6 @@ void set_hv_tscchange_cb(void (*cb)(void))
+ 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};
+
+@@ -148,13 +147,20 @@ void set_hv_tscchange_cb(void (*cb)(void))
+ 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);
+
+@@ -342,20 +348,13 @@ static void __init hv_get_partition_id(void)
+ */
+ void __init hyperv_init(void)
+ {
+- u64 guest_id, required_msrs;
++ u64 guest_id;
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+ int cpuhp;
+
+ if (x86_hyper_type != X86_HYPER_MS_HYPERV)
+ return;
+
+- /* Absolutely required MSRs */
+- required_msrs = HV_MSR_HYPERCALL_AVAILABLE |
+- HV_MSR_VP_INDEX_AVAILABLE;
+-
+- if ((ms_hyperv.features & required_msrs) != required_msrs)
+- return;
+-
+ if (hv_common_init())
+ return;
+
+diff --git a/arch/x86/include/asm/cpu_entry_area.h b/arch/x86/include/asm/cpu_entry_area.h
+index 3d52b094850a9..dd5ea1bdf04c5 100644
+--- a/arch/x86/include/asm/cpu_entry_area.h
++++ b/arch/x86/include/asm/cpu_entry_area.h
+@@ -10,6 +10,12 @@
+
+ #ifdef CONFIG_X86_64
+
++#ifdef CONFIG_AMD_MEM_ENCRYPT
++#define VC_EXCEPTION_STKSZ EXCEPTION_STKSZ
++#else
++#define VC_EXCEPTION_STKSZ 0
++#endif
++
+ /* Macro to enforce the same ordering and stack sizes */
+ #define ESTACKS_MEMBERS(guardsize, optional_stack_size) \
+ char DF_stack_guard[guardsize]; \
+@@ -28,7 +34,7 @@
+
+ /* The exception stacks' physical storage. No guard pages required */
+ struct exception_stacks {
+- ESTACKS_MEMBERS(0, 0)
++ ESTACKS_MEMBERS(0, VC_EXCEPTION_STKSZ)
+ };
+
+ /* The effective cpu entry area mapping with guard pages. */
+diff --git a/arch/x86/include/asm/insn-eval.h b/arch/x86/include/asm/insn-eval.h
+index 91d7182ad2d6e..4ec3613551e3b 100644
+--- a/arch/x86/include/asm/insn-eval.h
++++ b/arch/x86/include/asm/insn-eval.h
+@@ -21,6 +21,7 @@ int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs);
+ int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs);
+ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
+ int insn_get_code_seg_params(struct pt_regs *regs);
++int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip);
+ int insn_fetch_from_user(struct pt_regs *regs,
+ unsigned char buf[MAX_INSN_SIZE]);
+ int insn_fetch_from_user_inatomic(struct pt_regs *regs,
+diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h
+index 562854c608082..8d55bd11848cb 100644
+--- a/arch/x86/include/asm/irq_stack.h
++++ b/arch/x86/include/asm/irq_stack.h
+@@ -77,11 +77,11 @@
+ * Function calls can clobber anything except the callee-saved
+ * registers. Tell the compiler.
+ */
+-#define call_on_irqstack(func, asm_call, argconstr...) \
++#define call_on_stack(stack, func, asm_call, argconstr...) \
+ { \
+ register void *tos asm("r11"); \
+ \
+- tos = ((void *)__this_cpu_read(hardirq_stack_ptr)); \
++ tos = ((void *)(stack)); \
+ \
+ asm_inline volatile( \
+ "movq %%rsp, (%[tos]) \n" \
+@@ -98,6 +98,25 @@
+ ); \
+ }
+
++#define ASM_CALL_ARG0 \
++ "call %P[__func] \n"
++
++#define ASM_CALL_ARG1 \
++ "movq %[arg1], %%rdi \n" \
++ ASM_CALL_ARG0
++
++#define ASM_CALL_ARG2 \
++ "movq %[arg2], %%rsi \n" \
++ ASM_CALL_ARG1
++
++#define ASM_CALL_ARG3 \
++ "movq %[arg3], %%rdx \n" \
++ ASM_CALL_ARG2
++
++#define call_on_irqstack(func, asm_call, argconstr...) \
++ call_on_stack(__this_cpu_read(hardirq_stack_ptr), \
++ func, asm_call, argconstr)
++
+ /* Macros to assert type correctness for run_*_on_irqstack macros */
+ #define assert_function_type(func, proto) \
+ static_assert(__builtin_types_compatible_p(typeof(&func), proto))
+@@ -147,8 +166,7 @@
+ */
+ #define ASM_CALL_SYSVEC \
+ "call irq_enter_rcu \n" \
+- "movq %[arg1], %%rdi \n" \
+- "call %P[__func] \n" \
++ ASM_CALL_ARG1 \
+ "call irq_exit_rcu \n"
+
+ #define SYSVEC_CONSTRAINTS , [arg1] "r" (regs)
+@@ -168,12 +186,10 @@
+ */
+ #define ASM_CALL_IRQ \
+ "call irq_enter_rcu \n" \
+- "movq %[arg1], %%rdi \n" \
+- "movl %[arg2], %%esi \n" \
+- "call %P[__func] \n" \
++ ASM_CALL_ARG2 \
+ "call irq_exit_rcu \n"
+
+-#define IRQ_CONSTRAINTS , [arg1] "r" (regs), [arg2] "r" (vector)
++#define IRQ_CONSTRAINTS , [arg1] "r" (regs), [arg2] "r" ((unsigned long)vector)
+
+ #define run_irq_on_irqstack_cond(func, regs, vector) \
+ { \
+@@ -185,9 +201,6 @@
+ IRQ_CONSTRAINTS, regs, vector); \
+ }
+
+-#define ASM_CALL_SOFTIRQ \
+- "call %P[__func] \n"
+-
+ /*
+ * Macro to invoke __do_softirq on the irq stack. This is only called from
+ * task context when bottom halves are about to be reenabled and soft
+@@ -197,7 +210,7 @@
+ #define do_softirq_own_stack() \
+ { \
+ __this_cpu_write(hardirq_stack_inuse, true); \
+- call_on_irqstack(__do_softirq, ASM_CALL_SOFTIRQ); \
++ call_on_irqstack(__do_softirq, ASM_CALL_ARG0); \
+ __this_cpu_write(hardirq_stack_inuse, false); \
+ }
+
+diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
+index 13f64654dfff8..a11785ebf628b 100644
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -98,7 +98,7 @@
+ KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+ #define KVM_REQ_TLB_FLUSH_CURRENT KVM_ARCH_REQ(26)
+ #define KVM_REQ_TLB_FLUSH_GUEST \
+- KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_NO_WAKEUP)
++ KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+ #define KVM_REQ_APF_READY KVM_ARCH_REQ(28)
+ #define KVM_REQ_MSR_FILTER_CHANGED KVM_ARCH_REQ(29)
+ #define KVM_REQ_UPDATE_CPU_DIRTY_LOGGING \
+@@ -364,6 +364,7 @@ union kvm_mmu_extended_role {
+ unsigned int cr4_smap:1;
+ unsigned int cr4_smep:1;
+ unsigned int cr4_la57:1;
++ unsigned int efer_lma:1;
+ };
+ };
+
+@@ -751,7 +752,7 @@ struct kvm_vcpu_arch {
+ u8 preempted;
+ u64 msr_val;
+ u64 last_steal;
+- struct gfn_to_pfn_cache cache;
++ struct gfn_to_hva_cache cache;
+ } st;
+
+ u64 l1_tsc_offset;
+diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
+index 9c80c68d75b54..3fb9f5ebefa42 100644
+--- a/arch/x86/include/asm/mem_encrypt.h
++++ b/arch/x86/include/asm/mem_encrypt.h
+@@ -13,6 +13,7 @@
+ #ifndef __ASSEMBLY__
+
+ #include <linux/init.h>
++#include <linux/cc_platform.h>
+
+ #include <asm/bootparam.h>
+
+diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
+index a8d4ad8565681..e9e2c3ba59239 100644
+--- a/arch/x86/include/asm/page_64_types.h
++++ b/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)
+diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
+index 9ad2acaaae9b8..577f342dbfb27 100644
+--- a/arch/x86/include/asm/processor.h
++++ b/arch/x86/include/asm/processor.h
+@@ -518,6 +518,7 @@ struct thread_struct {
+ */
+ unsigned long iopl_emul;
+
++ unsigned int iopl_warn:1;
+ unsigned int sig_on_uaccess_err:1;
+
+ /*
+diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
+index f248eb2ac2d4a..3881b5333eb81 100644
+--- a/arch/x86/include/asm/stacktrace.h
++++ b/arch/x86/include/asm/stacktrace.h
+@@ -38,6 +38,16 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
+ bool get_stack_info_noinstr(unsigned long *stack, struct task_struct *task,
+ struct stack_info *info);
+
++static __always_inline
++bool get_stack_guard_info(unsigned long *stack, struct stack_info *info)
++{
++ /* make sure it's not in the stack proper */
++ if (get_stack_info_noinstr(stack, current, info))
++ return false;
++ /* but if it is in the page below it, we hit a guard */
++ return get_stack_info_noinstr((void *)stack + PAGE_SIZE, current, info);
++}
++
+ const char *stack_type_name(enum stack_type type);
+
+ static inline bool on_stack(struct stack_info *info, void *addr, size_t len)
+diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
+index 7f7200021bd13..6221be7cafc3b 100644
+--- a/arch/x86/include/asm/traps.h
++++ b/arch/x86/include/asm/traps.h
+@@ -40,9 +40,9 @@ void math_emulate(struct math_emu_info *);
+ bool fault_in_kernel_space(unsigned long address);
+
+ #ifdef CONFIG_VMAP_STACK
+-void __noreturn handle_stack_overflow(const char *message,
+- struct pt_regs *regs,
+- unsigned long fault_address);
++void __noreturn handle_stack_overflow(struct pt_regs *regs,
++ unsigned long fault_address,
++ struct stack_info *info);
+ #endif
+
+ #endif /* _ASM_X86_TRAPS_H */
+diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h
+index ff4b52e37e60d..5adab895127e1 100644
+--- a/arch/x86/include/asm/xen/hypervisor.h
++++ b/arch/x86/include/asm/xen/hypervisor.h
+@@ -62,4 +62,9 @@ void xen_arch_register_cpu(int num);
+ void xen_arch_unregister_cpu(int num);
+ #endif
+
++#ifdef CONFIG_PVH
++void __init xen_pvh_init(struct boot_params *boot_params);
++void __init mem_map_via_hcall(struct boot_params *boot_params_p);
++#endif
++
+ #endif /* _ASM_X86_XEN_HYPERVISOR_H */
+diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
+index 8f4e8fa6ed759..2ff3e600f4269 100644
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -21,6 +21,7 @@ CFLAGS_REMOVE_ftrace.o = -pg
+ CFLAGS_REMOVE_early_printk.o = -pg
+ CFLAGS_REMOVE_head64.o = -pg
+ CFLAGS_REMOVE_sev.o = -pg
++CFLAGS_REMOVE_cc_platform.o = -pg
+ endif
+
+ KASAN_SANITIZE_head$(BITS).o := n
+@@ -29,6 +30,7 @@ KASAN_SANITIZE_dumpstack_$(BITS).o := n
+ KASAN_SANITIZE_stacktrace.o := n
+ KASAN_SANITIZE_paravirt.o := n
+ KASAN_SANITIZE_sev.o := n
++KASAN_SANITIZE_cc_platform.o := n
+
+ # With some compiler versions the generated code results in boot hangs, caused
+ # by several compilation units. To be safe, disable all instrumentation.
+@@ -47,6 +49,7 @@ endif
+ KCOV_INSTRUMENT := n
+
+ CFLAGS_head$(BITS).o += -fno-stack-protector
++CFLAGS_cc_platform.o += -fno-stack-protector
+
+ CFLAGS_irq.o := -I $(srctree)/$(src)/../include/asm/trace
+
+@@ -147,6 +150,9 @@ obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o
+ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
+
+ obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev.o
++
++obj-$(CONFIG_ARCH_HAS_CC_PLATFORM) += cc_platform.o
++
+ ###
+ # 64 bit specific files
+ ifeq ($(CONFIG_X86_64),y)
+diff --git a/arch/x86/kernel/cc_platform.c b/arch/x86/kernel/cc_platform.c
+new file mode 100644
+index 0000000000000..03bb2f343ddb7
+--- /dev/null
++++ b/arch/x86/kernel/cc_platform.c
+@@ -0,0 +1,69 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Confidential Computing Platform Capability checks
++ *
++ * Copyright (C) 2021 Advanced Micro Devices, Inc.
++ *
++ * Author: Tom Lendacky <thomas.lendacky@amd.com>
++ */
++
++#include <linux/export.h>
++#include <linux/cc_platform.h>
++#include <linux/mem_encrypt.h>
++
++#include <asm/processor.h>
++
++static bool __maybe_unused intel_cc_platform_has(enum cc_attr attr)
++{
++#ifdef CONFIG_INTEL_TDX_GUEST
++ return false;
++#else
++ return false;
++#endif
++}
++
++/*
++ * SME and SEV are very similar but they are not the same, so there are
++ * times that the kernel will need to distinguish between SME and SEV. The
++ * cc_platform_has() function is used for this. When a distinction isn't
++ * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used.
++ *
++ * The trampoline code is a good example for this requirement. Before
++ * paging is activated, SME will access all memory as decrypted, but SEV
++ * will access all memory as encrypted. So, when APs are being brought
++ * up under SME the trampoline area cannot be encrypted, whereas under SEV
++ * the trampoline area must be encrypted.
++ */
++static bool amd_cc_platform_has(enum cc_attr attr)
++{
++#ifdef CONFIG_AMD_MEM_ENCRYPT
++ switch (attr) {
++ case CC_ATTR_MEM_ENCRYPT:
++ return sme_me_mask;
++
++ case CC_ATTR_HOST_MEM_ENCRYPT:
++ return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED);
++
++ case CC_ATTR_GUEST_MEM_ENCRYPT:
++ return sev_status & MSR_AMD64_SEV_ENABLED;
++
++ case CC_ATTR_GUEST_STATE_ENCRYPT:
++ return sev_status & MSR_AMD64_SEV_ES_ENABLED;
++
++ default:
++ return false;
++ }
++#else
++ return false;
++#endif
++}
++
++
++bool cc_platform_has(enum cc_attr attr)
++{
++ if (sme_me_mask)
++ return amd_cc_platform_has(attr);
++
++ return false;
++}
++EXPORT_SYMBOL_GPL(cc_platform_has);
+diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
+index 2131af9f2fa23..4edb6f0f628c2 100644
+--- a/arch/x86/kernel/cpu/amd.c
++++ b/arch/x86/kernel/cpu/amd.c
+@@ -989,6 +989,8 @@ static void init_amd(struct cpuinfo_x86 *c)
+ 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);
+ }
+
+ #ifdef CONFIG_X86_32
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index b3410f1ac2175..58b1416c05da4 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -1396,9 +1396,8 @@ void __init early_cpu_init(void)
+ 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
+@@ -1419,10 +1418,43 @@ static void detect_null_seg_behavior(struct cpuinfo_x86 *c)
+ 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)
+@@ -1458,8 +1490,6 @@ static void generic_identify(struct cpuinfo_x86 *c)
+
+ 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
+diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
+index 95521302630d4..ee6f23f7587d4 100644
+--- a/arch/x86/kernel/cpu/cpu.h
++++ b/arch/x86/kernel/cpu/cpu.h
+@@ -75,6 +75,7 @@ extern int detect_extended_topology_early(struct cpuinfo_x86 *c);
+ extern int detect_extended_topology(struct cpuinfo_x86 *c);
+ extern int detect_ht_early(struct cpuinfo_x86 *c);
+ extern void detect_ht(struct cpuinfo_x86 *c);
++extern void check_null_seg_clears_base(struct cpuinfo_x86 *c);
+
+ unsigned int aperfmperf_get_khz(int cpu);
+
+diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c
+index 6d50136f7ab98..3fcdda4c1e114 100644
+--- a/arch/x86/kernel/cpu/hygon.c
++++ b/arch/x86/kernel/cpu/hygon.c
+@@ -335,6 +335,8 @@ static void init_hygon(struct cpuinfo_x86 *c)
+ /* 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)
+diff --git a/arch/x86/kernel/cpu/mce/intel.c b/arch/x86/kernel/cpu/mce/intel.c
+index acfd5d9f93c68..bb9a46a804bf2 100644
+--- a/arch/x86/kernel/cpu/mce/intel.c
++++ b/arch/x86/kernel/cpu/mce/intel.c
+@@ -547,12 +547,13 @@ bool intel_filter_mce(struct mce *m)
+ {
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+- /* MCE errata HSD131, HSM142, HSW131, BDM48, and HSM142 */
++ /* MCE errata HSD131, HSM142, HSW131, BDM48, HSM142 and SKX37 */
+ if ((c->x86 == 6) &&
+ ((c->x86_model == INTEL_FAM6_HASWELL) ||
+ (c->x86_model == INTEL_FAM6_HASWELL_L) ||
+ (c->x86_model == INTEL_FAM6_BROADWELL) ||
+- (c->x86_model == INTEL_FAM6_HASWELL_G)) &&
++ (c->x86_model == INTEL_FAM6_HASWELL_G) ||
++ (c->x86_model == INTEL_FAM6_SKYLAKE_X)) &&
+ (m->bank == 0) &&
+ ((m->status & 0xa0000000ffffffff) == 0x80000000000f0005))
+ return true;
+diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
+index e095c28d27ae8..ef6316fef99ff 100644
+--- a/arch/x86/kernel/cpu/mshyperv.c
++++ b/arch/x86/kernel/cpu/mshyperv.c
+@@ -163,12 +163,22 @@ static uint32_t __init ms_hyperv_platform(void)
+ cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
+ &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
+
+- if (eax >= HYPERV_CPUID_MIN &&
+- eax <= HYPERV_CPUID_MAX &&
+- !memcmp("Microsoft Hv", hyp_signature, 12))
+- return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
++ if (eax < HYPERV_CPUID_MIN || eax > HYPERV_CPUID_MAX ||
++ memcmp("Microsoft Hv", hyp_signature, 12))
++ return 0;
+
+- return 0;
++ /* HYPERCALL and VP_INDEX MSRs are mandatory for all features. */
++ eax = cpuid_eax(HYPERV_CPUID_FEATURES);
++ if (!(eax & HV_MSR_HYPERCALL_AVAILABLE)) {
++ pr_warn("x86/hyperv: HYPERCALL MSR not available.\n");
++ return 0;
++ }
++ if (!(eax & HV_MSR_VP_INDEX_AVAILABLE)) {
++ pr_warn("x86/hyperv: VP_INDEX MSR not available.\n");
++ return 0;
++ }
++
++ return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
+ }
+
+ static unsigned char hv_get_nmi_reason(void)
+diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
+index 63d3de02bbccb..8471a8b9b48e8 100644
+--- a/arch/x86/kernel/cpu/sgx/main.c
++++ b/arch/x86/kernel/cpu/sgx/main.c
+@@ -28,8 +28,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ksgxd_waitq);
+ static LIST_HEAD(sgx_active_page_list);
+ static DEFINE_SPINLOCK(sgx_reclaimer_lock);
+
+-/* The free page list lock protected variables prepend the lock. */
+-static unsigned long sgx_nr_free_pages;
++static atomic_long_t sgx_nr_free_pages = ATOMIC_LONG_INIT(0);
+
+ /* Nodes with one or more EPC sections. */
+ static nodemask_t sgx_numa_mask;
+@@ -403,14 +402,15 @@ skip:
+
+ spin_lock(&node->lock);
+ list_add_tail(&epc_page->list, &node->free_page_list);
+- sgx_nr_free_pages++;
+ spin_unlock(&node->lock);
++ atomic_long_inc(&sgx_nr_free_pages);
+ }
+ }
+
+ static bool sgx_should_reclaim(unsigned long watermark)
+ {
+- return sgx_nr_free_pages < watermark && !list_empty(&sgx_active_page_list);
++ return atomic_long_read(&sgx_nr_free_pages) < watermark &&
++ !list_empty(&sgx_active_page_list);
+ }
+
+ static int ksgxd(void *p)
+@@ -471,9 +471,9 @@ static struct sgx_epc_page *__sgx_alloc_epc_page_from_node(int nid)
+
+ page = list_first_entry(&node->free_page_list, struct sgx_epc_page, list);
+ list_del_init(&page->list);
+- sgx_nr_free_pages--;
+
+ spin_unlock(&node->lock);
++ atomic_long_dec(&sgx_nr_free_pages);
+
+ return page;
+ }
+@@ -625,9 +625,9 @@ void sgx_free_epc_page(struct sgx_epc_page *page)
+ spin_lock(&node->lock);
+
+ list_add_tail(&page->list, &node->free_page_list);
+- sgx_nr_free_pages++;
+
+ spin_unlock(&node->lock);
++ atomic_long_inc(&sgx_nr_free_pages);
+ }
+
+ static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size,
+diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
+index 5601b95944fae..6c5defd6569a3 100644
+--- a/arch/x86/kernel/dumpstack_64.c
++++ b/arch/x86/kernel/dumpstack_64.c
+@@ -32,9 +32,15 @@ const char *stack_type_name(enum stack_type type)
+ {
+ BUILD_BUG_ON(N_EXCEPTION_STACKS != 6);
+
++ if (type == STACK_TYPE_TASK)
++ return "TASK";
++
+ if (type == STACK_TYPE_IRQ)
+ return "IRQ";
+
++ if (type == STACK_TYPE_SOFTIRQ)
++ return "SOFTIRQ";
++
+ if (type == STACK_TYPE_ENTRY) {
+ /*
+ * On 64-bit, we have a generic entry stack that we
+diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
+index e28f6a5d14f1b..766ffe3ba3137 100644
+--- a/arch/x86/kernel/irq.c
++++ b/arch/x86/kernel/irq.c
+@@ -291,8 +291,10 @@ void kvm_set_posted_intr_wakeup_handler(void (*handler)(void))
+ {
+ 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);
+
+diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
+index 1d9463e3096b6..f2f733bcb2b95 100644
+--- a/arch/x86/kernel/process.c
++++ b/arch/x86/kernel/process.c
+@@ -132,6 +132,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
+ frame->ret_addr = (unsigned long) ret_from_fork;
+ p->thread.sp = (unsigned long) fork_frame;
+ p->thread.io_bitmap = NULL;
++ p->thread.iopl_warn = 0;
+ memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+
+ #ifdef CONFIG_X86_64
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 40ed44ead0631..d71267081153f 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -742,6 +742,28 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
+ return 0;
+ }
+
++static char *prepare_command_line(void)
++{
++#ifdef CONFIG_CMDLINE_BOOL
++#ifdef CONFIG_CMDLINE_OVERRIDE
++ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
++#else
++ if (builtin_cmdline[0]) {
++ /* append boot loader cmdline to builtin */
++ strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
++ strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
++ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
++ }
++#endif
++#endif
++
++ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
++
++ parse_early_param();
++
++ return command_line;
++}
++
+ /*
+ * Determine if we were loaded by an EFI loader. If so, then we have also been
+ * passed the efi memmap, systab, etc., so we should use these data structures
+@@ -830,6 +852,23 @@ void __init setup_arch(char **cmdline_p)
+
+ x86_init.oem.arch_setup();
+
++ /*
++ * x86_configure_nx() is called before parse_early_param() (called by
++ * prepare_command_line()) to detect whether hardware doesn't support
++ * NX (so that the early EHCI debug console setup can safely call
++ * set_fixmap()). It may then be called again from within noexec_setup()
++ * during parsing early parameters to honor the respective command line
++ * option.
++ */
++ x86_configure_nx();
++
++ /*
++ * This parses early params and it needs to run before
++ * early_reserve_memory() because latter relies on such settings
++ * supplied as early params.
++ */
++ *cmdline_p = prepare_command_line();
++
+ /*
+ * Do some memory reservations *before* memory is added to memblock, so
+ * memblock allocations won't overwrite it.
+@@ -863,33 +902,6 @@ void __init setup_arch(char **cmdline_p)
+ bss_resource.start = __pa_symbol(__bss_start);
+ bss_resource.end = __pa_symbol(__bss_stop)-1;
+
+-#ifdef CONFIG_CMDLINE_BOOL
+-#ifdef CONFIG_CMDLINE_OVERRIDE
+- strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+-#else
+- if (builtin_cmdline[0]) {
+- /* append boot loader cmdline to builtin */
+- strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+- strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+- strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+- }
+-#endif
+-#endif
+-
+- strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+- *cmdline_p = command_line;
+-
+- /*
+- * x86_configure_nx() is called before parse_early_param() to detect
+- * whether hardware doesn't support NX (so that the early EHCI debug
+- * console setup can safely call set_fixmap()). It may then be called
+- * again from within noexec_setup() during parsing early parameters
+- * to honor the respective command line option.
+- */
+- x86_configure_nx();
+-
+- parse_early_param();
+-
+ #ifdef CONFIG_MEMORY_HOTPLUG
+ /*
+ * Memory used by the kernel cannot be hot-removed because Linux
+diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
+index a6895e440bc35..a0064cf77e562 100644
+--- a/arch/x86/kernel/sev.c
++++ b/arch/x86/kernel/sev.c
+@@ -46,16 +46,6 @@ static struct ghcb __initdata *boot_ghcb;
+ struct sev_es_runtime_data {
+ struct ghcb ghcb_page;
+
+- /* Physical storage for the per-CPU IST stack of the #VC handler */
+- char ist_stack[EXCEPTION_STKSZ] __aligned(PAGE_SIZE);
+-
+- /*
+- * Physical storage for the per-CPU fall-back stack of the #VC handler.
+- * The fall-back stack is used when it is not safe to switch back to the
+- * interrupted stack in the #VC entry code.
+- */
+- char fallback_stack[EXCEPTION_STKSZ] __aligned(PAGE_SIZE);
+-
+ /*
+ * Reserve one page per CPU as backup storage for the unencrypted GHCB.
+ * It is needed when an NMI happens while the #VC handler uses the real
+@@ -99,27 +89,6 @@ DEFINE_STATIC_KEY_FALSE(sev_es_enable_key);
+ /* Needed in vc_early_forward_exception */
+ void do_early_exception(struct pt_regs *regs, int trapnr);
+
+-static void __init setup_vc_stacks(int cpu)
+-{
+- struct sev_es_runtime_data *data;
+- struct cpu_entry_area *cea;
+- unsigned long vaddr;
+- phys_addr_t pa;
+-
+- data = per_cpu(runtime_data, cpu);
+- cea = get_cpu_entry_area(cpu);
+-
+- /* Map #VC IST stack */
+- vaddr = CEA_ESTACK_BOT(&cea->estacks, VC);
+- pa = __pa(data->ist_stack);
+- cea_set_pte((void *)vaddr, pa, PAGE_KERNEL);
+-
+- /* Map VC fall-back stack */
+- vaddr = CEA_ESTACK_BOT(&cea->estacks, VC2);
+- pa = __pa(data->fallback_stack);
+- cea_set_pte((void *)vaddr, pa, PAGE_KERNEL);
+-}
+-
+ static __always_inline bool on_vc_stack(struct pt_regs *regs)
+ {
+ unsigned long sp = regs->sp;
+@@ -325,11 +294,6 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
+ char *dst, char *buf, size_t size)
+ {
+ unsigned long error_code = X86_PF_PROT | X86_PF_WRITE;
+- char __user *target = (char __user *)dst;
+- u64 d8;
+- u32 d4;
+- u16 d2;
+- u8 d1;
+
+ /*
+ * This function uses __put_user() independent of whether kernel or user
+@@ -351,26 +315,42 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
+ * instructions here would cause infinite nesting.
+ */
+ switch (size) {
+- case 1:
++ case 1: {
++ u8 d1;
++ u8 __user *target = (u8 __user *)dst;
++
+ memcpy(&d1, buf, 1);
+ if (__put_user(d1, target))
+ goto fault;
+ break;
+- case 2:
++ }
++ case 2: {
++ u16 d2;
++ u16 __user *target = (u16 __user *)dst;
++
+ memcpy(&d2, buf, 2);
+ if (__put_user(d2, target))
+ goto fault;
+ break;
+- case 4:
++ }
++ case 4: {
++ u32 d4;
++ u32 __user *target = (u32 __user *)dst;
++
+ memcpy(&d4, buf, 4);
+ if (__put_user(d4, target))
+ goto fault;
+ break;
+- case 8:
++ }
++ case 8: {
++ u64 d8;
++ u64 __user *target = (u64 __user *)dst;
++
+ memcpy(&d8, buf, 8);
+ if (__put_user(d8, target))
+ goto fault;
+ break;
++ }
+ default:
+ WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
+ return ES_UNSUPPORTED;
+@@ -393,11 +373,6 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
+ char *src, char *buf, size_t size)
+ {
+ unsigned long error_code = X86_PF_PROT;
+- char __user *s = (char __user *)src;
+- u64 d8;
+- u32 d4;
+- u16 d2;
+- u8 d1;
+
+ /*
+ * This function uses __get_user() independent of whether kernel or user
+@@ -419,26 +394,41 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
+ * instructions here would cause infinite nesting.
+ */
+ switch (size) {
+- case 1:
++ case 1: {
++ u8 d1;
++ u8 __user *s = (u8 __user *)src;
++
+ if (__get_user(d1, s))
+ goto fault;
+ memcpy(buf, &d1, 1);
+ break;
+- case 2:
++ }
++ case 2: {
++ u16 d2;
++ u16 __user *s = (u16 __user *)src;
++
+ if (__get_user(d2, s))
+ goto fault;
+ memcpy(buf, &d2, 2);
+ break;
+- case 4:
++ }
++ case 4: {
++ u32 d4;
++ u32 __user *s = (u32 __user *)src;
++
+ if (__get_user(d4, s))
+ goto fault;
+ memcpy(buf, &d4, 4);
+ break;
+- case 8:
++ }
++ case 8: {
++ u64 d8;
++ u64 __user *s = (u64 __user *)src;
+ if (__get_user(d8, s))
+ goto fault;
+ memcpy(buf, &d8, 8);
+ break;
++ }
+ default:
+ WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
+ return ES_UNSUPPORTED;
+@@ -787,7 +777,6 @@ void __init sev_es_init_vc_handling(void)
+ for_each_possible_cpu(cpu) {
+ alloc_runtime_data(cpu);
+ init_ghcb(cpu);
+- setup_vc_stacks(cpu);
+ }
+
+ sev_es_setup_play_dead();
+diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
+index a58800973aed3..5b1984d468227 100644
+--- a/arch/x86/kernel/traps.c
++++ b/arch/x86/kernel/traps.c
+@@ -313,17 +313,19 @@ out:
+ }
+
+ #ifdef CONFIG_VMAP_STACK
+-__visible void __noreturn handle_stack_overflow(const char *message,
+- struct pt_regs *regs,
+- unsigned long fault_address)
++__visible void __noreturn handle_stack_overflow(struct pt_regs *regs,
++ unsigned long fault_address,
++ struct stack_info *info)
+ {
+- printk(KERN_EMERG "BUG: stack guard page was hit at %p (stack is %p..%p)\n",
+- (void *)fault_address, current->stack,
+- (char *)current->stack + THREAD_SIZE - 1);
+- die(message, regs, 0);
++ const char *name = stack_type_name(info->type);
++
++ printk(KERN_EMERG "BUG: %s stack guard page was hit at %p (stack is %p..%p)\n",
++ name, (void *)fault_address, info->begin, info->end);
++
++ die("stack guard page", regs, 0);
+
+ /* Be absolutely certain we don't return. */
+- panic("%s", message);
++ panic("%s stack guard hit", name);
+ }
+ #endif
+
+@@ -353,6 +355,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
+
+ #ifdef CONFIG_VMAP_STACK
+ unsigned long address = read_cr2();
++ struct stack_info info;
+ #endif
+
+ #ifdef CONFIG_X86_ESPFIX64
+@@ -455,10 +458,8 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
+ * stack even if the actual trigger for the double fault was
+ * something else.
+ */
+- if ((unsigned long)task_stack_page(tsk) - 1 - address < PAGE_SIZE) {
+- handle_stack_overflow("kernel stack overflow (double-fault)",
+- regs, address);
+- }
++ if (get_stack_guard_info((void *)address, &info))
++ handle_stack_overflow(regs, address, &info);
+ #endif
+
+ pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
+@@ -528,6 +529,36 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
+
+ #define GPFSTR "general protection fault"
+
++static bool fixup_iopl_exception(struct pt_regs *regs)
++{
++ struct thread_struct *t = &current->thread;
++ unsigned char byte;
++ unsigned long ip;
++
++ if (!IS_ENABLED(CONFIG_X86_IOPL_IOPERM) || t->iopl_emul != 3)
++ return false;
++
++ if (insn_get_effective_ip(regs, &ip))
++ return false;
++
++ if (get_user(byte, (const char __user *)ip))
++ return false;
++
++ if (byte != 0xfa && byte != 0xfb)
++ return false;
++
++ if (!t->iopl_warn && printk_ratelimit()) {
++ pr_err("%s[%d] attempts to use CLI/STI, pretending it's a NOP, ip:%lx",
++ current->comm, task_pid_nr(current), ip);
++ print_vma_addr(KERN_CONT " in ", ip);
++ pr_cont("\n");
++ t->iopl_warn = 1;
++ }
++
++ regs->ip += 1;
++ return true;
++}
++
+ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
+ {
+ char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
+@@ -553,6 +584,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
+ tsk = current;
+
+ if (user_mode(regs)) {
++ if (fixup_iopl_exception(regs))
++ goto exit;
++
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_nr = X86_TRAP_GP;
+
+@@ -709,7 +743,7 @@ asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *r
+ stack = (unsigned long *)sp;
+
+ if (!get_stack_info_noinstr(stack, current, &info) || info.type == STACK_TYPE_ENTRY ||
+- info.type >= STACK_TYPE_EXCEPTION_LAST)
++ info.type > STACK_TYPE_EXCEPTION_LAST)
+ sp = __this_cpu_ist_top_va(VC2);
+
+ sync:
+diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
+index 2e076a459a0c0..a698196377be9 100644
+--- a/arch/x86/kernel/tsc.c
++++ b/arch/x86/kernel/tsc.c
+@@ -1180,6 +1180,12 @@ void mark_tsc_unstable(char *reason)
+
+ 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)
+@@ -1196,6 +1202,23 @@ static void __init check_system_tsc_reliable(void)
+ #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();
+ }
+
+ /*
+@@ -1387,9 +1410,6 @@ static int __init init_tsc_clocksource(void)
+ 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;
+
+@@ -1527,7 +1547,7 @@ void __init tsc_init(void)
+ }
+
+ 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();
+diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
+index 50a4515fe0ad1..9452dc9664b51 100644
+--- a/arch/x86/kernel/tsc_sync.c
++++ b/arch/x86/kernel/tsc_sync.c
+@@ -30,6 +30,7 @@ struct tsc_adjust {
+ };
+
+ 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 @@ void tsc_verify_tsc_adjust(bool resume)
+ }
+ }
+
++/*
++ * 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)
+ {
+diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
+index e5a7a10a0164d..17d58740891e2 100644
+--- a/arch/x86/kernel/vm86_32.c
++++ b/arch/x86/kernel/vm86_32.c
+@@ -142,6 +142,7 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
+
+ user_access_end();
+
++exit_vm86:
+ preempt_disable();
+ tsk->thread.sp0 = vm86->saved_sp0;
+ tsk->thread.sysenter_cs = __KERNEL_CS;
+@@ -161,7 +162,8 @@ Efault_end:
+ user_access_end();
+ Efault:
+ pr_alert("could not access userspace vm86 info\n");
+- do_exit(SIGSEGV);
++ force_exit_sig(SIGSEGV);
++ goto exit_vm86;
+ }
+
+ static int do_vm86_irq_handling(int subfunction, int irqnumber);
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 751aa85a30012..f666fd79d8ad6 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -232,6 +232,25 @@ u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu)
+ return rsvd_bits(cpuid_maxphyaddr(vcpu), 63);
+ }
+
++static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
++ int nent)
++{
++ int r;
++
++ r = kvm_check_cpuid(e2, nent);
++ if (r)
++ return r;
++
++ kvfree(vcpu->arch.cpuid_entries);
++ vcpu->arch.cpuid_entries = e2;
++ vcpu->arch.cpuid_nent = nent;
++
++ kvm_update_cpuid_runtime(vcpu);
++ kvm_vcpu_after_set_cpuid(vcpu);
++
++ return 0;
++}
++
+ /* when an old userspace process fills a new kernel module */
+ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
+ struct kvm_cpuid *cpuid,
+@@ -268,18 +287,9 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
+ e2[i].padding[2] = 0;
+ }
+
+- r = kvm_check_cpuid(e2, cpuid->nent);
+- if (r) {
++ r = kvm_set_cpuid(vcpu, e2, cpuid->nent);
++ if (r)
+ kvfree(e2);
+- goto out_free_cpuid;
+- }
+-
+- kvfree(vcpu->arch.cpuid_entries);
+- vcpu->arch.cpuid_entries = e2;
+- vcpu->arch.cpuid_nent = cpuid->nent;
+-
+- kvm_update_cpuid_runtime(vcpu);
+- kvm_vcpu_after_set_cpuid(vcpu);
+
+ out_free_cpuid:
+ kvfree(e);
+@@ -303,20 +313,11 @@ int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
+ return PTR_ERR(e2);
+ }
+
+- r = kvm_check_cpuid(e2, cpuid->nent);
+- if (r) {
++ r = kvm_set_cpuid(vcpu, e2, cpuid->nent);
++ if (r)
+ kvfree(e2);
+- return r;
+- }
+
+- kvfree(vcpu->arch.cpuid_entries);
+- vcpu->arch.cpuid_entries = e2;
+- vcpu->arch.cpuid_nent = cpuid->nent;
+-
+- kvm_update_cpuid_runtime(vcpu);
+- kvm_vcpu_after_set_cpuid(vcpu);
+-
+- return 0;
++ return r;
+ }
+
+ int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
+diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
+index d5124b520f761..2092834efba11 100644
+--- a/arch/x86/kvm/hyperv.c
++++ b/arch/x86/kvm/hyperv.c
+@@ -1922,11 +1922,13 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
+
+ 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,
+ hc->ingpa + offsetof(struct hv_send_ipi_ex,
+ vp_set.bank_contents),
+ sparse_banks,
+@@ -1934,6 +1936,7 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
+ 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;
+
+@@ -2022,7 +2025,7 @@ static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
+ {
+ bool longmode;
+
+- longmode = is_64_bit_mode(vcpu);
++ longmode = is_64_bit_hypercall(vcpu);
+ if (longmode)
+ kvm_rax_write(vcpu, result);
+ else {
+@@ -2171,7 +2174,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
+ }
+
+ #ifdef CONFIG_X86_64
+- if (is_64_bit_mode(vcpu)) {
++ if (is_64_bit_hypercall(vcpu)) {
+ hc.param = kvm_rcx_read(vcpu);
+ hc.ingpa = kvm_rdx_read(vcpu);
+ hc.outgpa = kvm_r8_read(vcpu);
+diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
+index 8c065da73f8e5..4e0f52660842b 100644
+--- a/arch/x86/kvm/ioapic.c
++++ b/arch/x86/kvm/ioapic.c
+@@ -96,7 +96,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
+ static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
+ {
+ ioapic->rtc_status.pending_eoi = 0;
+- bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID + 1);
++ bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID);
+ }
+
+ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
+diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
+index bbd4a5d18b5dc..f1b2b2a6ff4db 100644
+--- a/arch/x86/kvm/ioapic.h
++++ b/arch/x86/kvm/ioapic.h
+@@ -39,13 +39,13 @@ struct kvm_vcpu;
+
+ struct dest_map {
+ /* vcpu bitmap where IRQ has been sent */
+- DECLARE_BITMAP(map, KVM_MAX_VCPU_ID + 1);
++ DECLARE_BITMAP(map, KVM_MAX_VCPU_ID);
+
+ /*
+ * Vector sent to a given vcpu, only valid when
+ * the vcpu's bit in map is set
+ */
+- u8 vectors[KVM_MAX_VCPU_ID + 1];
++ u8 vectors[KVM_MAX_VCPU_ID];
+ };
+
+
+@@ -81,7 +81,6 @@ struct kvm_ioapic {
+ unsigned long irq_states[IOAPIC_NUM_PINS];
+ struct kvm_io_device dev;
+ struct kvm *kvm;
+- void (*ack_notifier)(void *opaque, int irq);
+ spinlock_t lock;
+ struct rtc_status rtc_status;
+ struct delayed_work eoi_inject;
+diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
+index 650642b18d151..c2d7cfe82d004 100644
+--- a/arch/x86/kvm/irq.h
++++ b/arch/x86/kvm/irq.h
+@@ -56,7 +56,6 @@ struct kvm_pic {
+ struct kvm_io_device dev_master;
+ struct kvm_io_device dev_slave;
+ struct kvm_io_device dev_elcr;
+- void (*ack_notifier)(void *opaque, int irq);
+ unsigned long irq_states[PIC_NUM_PINS];
+ };
+
+diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
+index d6ac32f3f650c..95f5527646e4a 100644
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -707,7 +707,7 @@ static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
+ static int apic_has_interrupt_for_ppr(struct kvm_lapic *apic, u32 ppr)
+ {
+ int highest_irr;
+- if (apic->vcpu->arch.apicv_active)
++ if (kvm_x86_ops.sync_pir_to_irr)
+ highest_irr = static_call(kvm_x86_sync_pir_to_irr)(apic->vcpu);
+ else
+ highest_irr = apic_find_highest_irr(apic);
+diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
+index 0cc58901bf7a7..0a88cb4f731f4 100644
+--- a/arch/x86/kvm/mmu/mmu.c
++++ b/arch/x86/kvm/mmu/mmu.c
+@@ -1592,7 +1592,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
+ flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmapp);
+
+ if (is_tdp_mmu_enabled(kvm))
+- flush |= kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush);
++ flush = kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush);
+
+ return flush;
+ }
+@@ -2188,10 +2188,10 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato
+ iterator->shadow_addr = root;
+ iterator->level = vcpu->arch.mmu->shadow_root_level;
+
+- if (iterator->level == PT64_ROOT_4LEVEL &&
++ if (iterator->level >= PT64_ROOT_4LEVEL &&
+ vcpu->arch.mmu->root_level < PT64_ROOT_4LEVEL &&
+ !vcpu->arch.mmu->direct_map)
+- --iterator->level;
++ iterator->level = PT32E_ROOT_LEVEL;
+
+ if (iterator->level == PT32E_ROOT_LEVEL) {
+ /*
+@@ -4679,6 +4679,7 @@ static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu,
+ /* PKEY and LA57 are active iff long mode is active. */
+ ext.cr4_pke = ____is_efer_lma(regs) && ____is_cr4_pke(regs);
+ ext.cr4_la57 = ____is_efer_lma(regs) && ____is_cr4_la57(regs);
++ ext.efer_lma = ____is_efer_lma(regs);
+ }
+
+ ext.valid = 1;
+@@ -4851,7 +4852,7 @@ void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, unsigned long cr0,
+ struct kvm_mmu *context = &vcpu->arch.guest_mmu;
+ struct kvm_mmu_role_regs regs = {
+ .cr0 = cr0,
+- .cr4 = cr4,
++ .cr4 = cr4 & ~X86_CR4_PKE,
+ .efer = efer,
+ };
+ union kvm_mmu_role new_role;
+@@ -4915,7 +4916,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
+ context->direct_map = false;
+
+ update_permission_bitmask(context, true);
+- update_pkru_bitmask(context);
++ context->pkru_mask = 0;
+ reset_rsvds_bits_mask_ept(vcpu, context, execonly);
+ reset_ept_shadow_zero_bits_mask(vcpu, context, execonly);
+ }
+@@ -5368,7 +5369,7 @@ void kvm_mmu_invalidate_gva(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+
+ void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva)
+ {
+- kvm_mmu_invalidate_gva(vcpu, vcpu->arch.mmu, gva, INVALID_PAGE);
++ kvm_mmu_invalidate_gva(vcpu, vcpu->arch.walk_mmu, gva, INVALID_PAGE);
+ ++vcpu->stat.invlpg;
+ }
+ EXPORT_SYMBOL_GPL(kvm_mmu_invlpg);
+@@ -5473,8 +5474,8 @@ slot_handle_level(struct kvm *kvm, const struct kvm_memory_slot *memslot,
+ }
+
+ static __always_inline bool
+-slot_handle_leaf(struct kvm *kvm, const struct kvm_memory_slot *memslot,
+- slot_level_handler fn, bool flush_on_yield)
++slot_handle_level_4k(struct kvm *kvm, const struct kvm_memory_slot *memslot,
++ slot_level_handler fn, bool flush_on_yield)
+ {
+ return slot_handle_level(kvm, memslot, fn, PG_LEVEL_4K,
+ PG_LEVEL_4K, flush_on_yield);
+@@ -5758,13 +5759,11 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
+ flush = kvm_tdp_mmu_zap_gfn_range(kvm, i, gfn_start,
+ gfn_end, flush);
+- if (flush)
+- kvm_flush_remote_tlbs_with_address(kvm, gfn_start,
+- gfn_end - gfn_start);
+ }
+
+ if (flush)
+- kvm_flush_remote_tlbs_with_address(kvm, gfn_start, gfn_end);
++ kvm_flush_remote_tlbs_with_address(kvm, gfn_start,
++ gfn_end - gfn_start);
+
+ kvm_dec_notifier_count(kvm, gfn_start, gfn_end);
+
+@@ -5856,21 +5855,21 @@ restart:
+ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm,
+ const struct kvm_memory_slot *slot)
+ {
+- bool flush = false;
+-
+ if (kvm_memslots_have_rmaps(kvm)) {
+ write_lock(&kvm->mmu_lock);
+- flush = slot_handle_leaf(kvm, slot, kvm_mmu_zap_collapsible_spte, true);
+- if (flush)
++ /*
++ * Zap only 4k SPTEs since the legacy MMU only supports dirty
++ * logging at a 4k granularity and never creates collapsible
++ * 2m SPTEs during dirty logging.
++ */
++ if (slot_handle_level_4k(kvm, slot, kvm_mmu_zap_collapsible_spte, true))
+ kvm_arch_flush_remote_tlbs_memslot(kvm, slot);
+ write_unlock(&kvm->mmu_lock);
+ }
+
+ if (is_tdp_mmu_enabled(kvm)) {
+ read_lock(&kvm->mmu_lock);
+- flush = kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot, flush);
+- if (flush)
+- kvm_arch_flush_remote_tlbs_memslot(kvm, slot);
++ kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot);
+ read_unlock(&kvm->mmu_lock);
+ }
+ }
+@@ -5897,8 +5896,11 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
+
+ if (kvm_memslots_have_rmaps(kvm)) {
+ write_lock(&kvm->mmu_lock);
+- flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty,
+- false);
++ /*
++ * Clear dirty bits only on 4k SPTEs since the legacy MMU only
++ * support dirty logging at a 4k granularity.
++ */
++ flush = slot_handle_level_4k(kvm, memslot, __rmap_clear_dirty, false);
+ write_unlock(&kvm->mmu_lock);
+ }
+
+diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h
+index eb7b227fc6cfe..31d6456d8ac33 100644
+--- a/arch/x86/kvm/mmu/spte.h
++++ b/arch/x86/kvm/mmu/spte.h
+@@ -310,12 +310,7 @@ static inline bool __is_bad_mt_xwr(struct rsvd_bits_validate *rsvd_check,
+ static __always_inline bool is_rsvd_spte(struct rsvd_bits_validate *rsvd_check,
+ u64 spte, int level)
+ {
+- /*
+- * Use a bitwise-OR instead of a logical-OR to aggregate the reserved
+- * bits and EPT's invalid memtype/XWR checks to avoid an extra Jcc
+- * (this is extremely unlikely to be short-circuited as true).
+- */
+- return __is_bad_mt_xwr(rsvd_check, spte) |
++ return __is_bad_mt_xwr(rsvd_check, spte) ||
+ __is_rsvd_bits_set(rsvd_check, spte, level);
+ }
+
+diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
+index 64ccfc1fa5535..0e4227b59d7bb 100644
+--- a/arch/x86/kvm/mmu/tdp_mmu.c
++++ b/arch/x86/kvm/mmu/tdp_mmu.c
+@@ -316,9 +316,6 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
+ struct kvm_mmu_page *sp = sptep_to_sp(rcu_dereference(pt));
+ int level = sp->role.level;
+ gfn_t base_gfn = sp->gfn;
+- u64 old_child_spte;
+- u64 *sptep;
+- gfn_t gfn;
+ int i;
+
+ trace_kvm_mmu_prepare_zap_page(sp);
+@@ -326,8 +323,9 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
+ tdp_mmu_unlink_page(kvm, sp, shared);
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
+- sptep = rcu_dereference(pt) + i;
+- gfn = base_gfn + i * KVM_PAGES_PER_HPAGE(level);
++ u64 *sptep = rcu_dereference(pt) + i;
++ gfn_t gfn = base_gfn + i * KVM_PAGES_PER_HPAGE(level);
++ u64 old_child_spte;
+
+ if (shared) {
+ /*
+@@ -373,7 +371,7 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
+ shared);
+ }
+
+- kvm_flush_remote_tlbs_with_address(kvm, gfn,
++ kvm_flush_remote_tlbs_with_address(kvm, base_gfn,
+ KVM_PAGES_PER_HPAGE(level + 1));
+
+ call_rcu(&sp->rcu_head, tdp_mmu_free_sp_rcu_callback);
+@@ -1083,8 +1081,8 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
+ struct kvm_mmu_page *root;
+
+ for_each_tdp_mmu_root(kvm, root, range->slot->as_id)
+- flush |= zap_gfn_range(kvm, root, range->start, range->end,
+- range->may_block, flush, false);
++ flush = zap_gfn_range(kvm, root, range->start, range->end,
++ range->may_block, flush, false);
+
+ return flush;
+ }
+@@ -1415,10 +1413,9 @@ void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm,
+ * Clear leaf entries which could be replaced by large mappings, for
+ * GFNs within the slot.
+ */
+-static bool zap_collapsible_spte_range(struct kvm *kvm,
++static void zap_collapsible_spte_range(struct kvm *kvm,
+ struct kvm_mmu_page *root,
+- const struct kvm_memory_slot *slot,
+- bool flush)
++ const struct kvm_memory_slot *slot)
+ {
+ gfn_t start = slot->base_gfn;
+ gfn_t end = start + slot->npages;
+@@ -1429,10 +1426,8 @@ static bool zap_collapsible_spte_range(struct kvm *kvm,
+
+ tdp_root_for_each_pte(iter, root, start, end) {
+ retry:
+- if (tdp_mmu_iter_cond_resched(kvm, &iter, flush, true)) {
+- flush = false;
++ if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true))
+ continue;
+- }
+
+ if (!is_shadow_present_pte(iter.old_spte) ||
+ !is_last_spte(iter.old_spte, iter.level))
+@@ -1444,6 +1439,7 @@ retry:
+ pfn, PG_LEVEL_NUM))
+ continue;
+
++ /* Note, a successful atomic zap also does a remote TLB flush. */
+ if (!tdp_mmu_zap_spte_atomic(kvm, &iter)) {
+ /*
+ * The iter must explicitly re-read the SPTE because
+@@ -1452,30 +1448,24 @@ retry:
+ iter.old_spte = READ_ONCE(*rcu_dereference(iter.sptep));
+ goto retry;
+ }
+- flush = true;
+ }
+
+ rcu_read_unlock();
+-
+- return flush;
+ }
+
+ /*
+ * Clear non-leaf entries (and free associated page tables) which could
+ * be replaced by large mappings, for GFNs within the slot.
+ */
+-bool kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
+- const struct kvm_memory_slot *slot,
+- bool flush)
++void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
++ const struct kvm_memory_slot *slot)
+ {
+ struct kvm_mmu_page *root;
+
+ lockdep_assert_held_read(&kvm->mmu_lock);
+
+ for_each_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true)
+- flush = zap_collapsible_spte_range(kvm, root, slot, flush);
+-
+- return flush;
++ zap_collapsible_spte_range(kvm, root, slot);
+ }
+
+ /*
+diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h
+index 358f447d40120..ba3681cd38ab4 100644
+--- a/arch/x86/kvm/mmu/tdp_mmu.h
++++ b/arch/x86/kvm/mmu/tdp_mmu.h
+@@ -66,9 +66,8 @@ void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ gfn_t gfn, unsigned long mask,
+ bool wrprot);
+-bool kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
+- const struct kvm_memory_slot *slot,
+- bool flush);
++void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
++ const struct kvm_memory_slot *slot);
+
+ bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm,
+ struct kvm_memory_slot *slot, gfn_t gfn,
+diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
+index 8052d92069e01..2fb6a6f00290d 100644
+--- a/arch/x86/kvm/svm/avic.c
++++ b/arch/x86/kvm/svm/avic.c
+@@ -988,16 +988,18 @@ void avic_vcpu_put(struct kvm_vcpu *vcpu)
+ static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
+ {
+ struct vcpu_svm *svm = to_svm(vcpu);
++ int cpu = get_cpu();
+
++ WARN_ON(cpu != vcpu->cpu);
+ svm->avic_is_running = is_run;
+
+- if (!kvm_vcpu_apicv_active(vcpu))
+- return;
+-
+- if (is_run)
+- avic_vcpu_load(vcpu, vcpu->cpu);
+- else
+- avic_vcpu_put(vcpu);
++ if (kvm_vcpu_apicv_active(vcpu)) {
++ if (is_run)
++ avic_vcpu_load(vcpu, cpu);
++ else
++ avic_vcpu_put(vcpu);
++ }
++ put_cpu();
+ }
+
+ void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
+diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
+index fdf587f19c5fb..e152241d1d709 100644
+--- a/arch/x86/kvm/svm/pmu.c
++++ b/arch/x86/kvm/svm/pmu.c
+@@ -282,7 +282,7 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
+ 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;
+diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
+index 7e34d7163adab..134c4ea5e6ad8 100644
+--- a/arch/x86/kvm/svm/sev.c
++++ b/arch/x86/kvm/svm/sev.c
+@@ -1787,7 +1787,12 @@ int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd)
+ mutex_unlock(&source_kvm->lock);
+ mutex_lock(&kvm->lock);
+
+- if (sev_guest(kvm)) {
++ /*
++ * Disallow out-of-band SEV/SEV-ES init if the target is already an
++ * SEV guest, or if vCPUs have been created. KVM relies on vCPUs being
++ * created after SEV/SEV-ES initialization, e.g. to init intercepts.
++ */
++ if (sev_guest(kvm) || kvm->created_vcpus) {
+ ret = -EINVAL;
+ goto e_mirror_unlock;
+ }
+@@ -1800,6 +1805,7 @@ int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd)
+ mirror_sev->fd = source_sev.fd;
+ mirror_sev->es_active = source_sev.es_active;
+ mirror_sev->handle = source_sev.handle;
++ INIT_LIST_HEAD(&mirror_sev->regions_list);
+ /*
+ * Do not copy ap_jump_table. Since the mirror does not share the same
+ * KVM contexts as the original, and they may have different
+@@ -2311,7 +2317,7 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu)
+ }
+
+ #define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE)
+-static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
++static int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
+ {
+ struct vmcb_control_area *control = &svm->vmcb->control;
+ struct ghcb *ghcb = svm->ghcb;
+@@ -2322,14 +2328,14 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
+ scratch_gpa_beg = ghcb_get_sw_scratch(ghcb);
+ if (!scratch_gpa_beg) {
+ pr_err("vmgexit: scratch gpa not provided\n");
+- return false;
++ return -EINVAL;
+ }
+
+ scratch_gpa_end = scratch_gpa_beg + len;
+ if (scratch_gpa_end < scratch_gpa_beg) {
+ pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n",
+ len, scratch_gpa_beg);
+- return false;
++ return -EINVAL;
+ }
+
+ if ((scratch_gpa_beg & PAGE_MASK) == control->ghcb_gpa) {
+@@ -2347,7 +2353,7 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
+ scratch_gpa_end > ghcb_scratch_end) {
+ pr_err("vmgexit: scratch area is outside of GHCB shared buffer area (%#llx - %#llx)\n",
+ scratch_gpa_beg, scratch_gpa_end);
+- return false;
++ return -EINVAL;
+ }
+
+ scratch_va = (void *)svm->ghcb;
+@@ -2360,18 +2366,18 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
+ if (len > GHCB_SCRATCH_AREA_LIMIT) {
+ pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n",
+ len, GHCB_SCRATCH_AREA_LIMIT);
+- return false;
++ return -EINVAL;
+ }
+ scratch_va = kzalloc(len, GFP_KERNEL_ACCOUNT);
+ if (!scratch_va)
+- return false;
++ return -ENOMEM;
+
+ if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
+ /* Unable to copy scratch area from guest */
+ pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
+
+ kfree(scratch_va);
+- return false;
++ return -EFAULT;
+ }
+
+ /*
+@@ -2387,7 +2393,7 @@ static bool setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
+ svm->ghcb_sa = scratch_va;
+ svm->ghcb_sa_len = len;
+
+- return true;
++ return 0;
+ }
+
+ static void set_ghcb_msr_bits(struct vcpu_svm *svm, u64 value, u64 mask,
+@@ -2526,10 +2532,10 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
+ ghcb_set_sw_exit_info_1(ghcb, 0);
+ ghcb_set_sw_exit_info_2(ghcb, 0);
+
+- ret = -EINVAL;
+ switch (exit_code) {
+ case SVM_VMGEXIT_MMIO_READ:
+- if (!setup_vmgexit_scratch(svm, true, control->exit_info_2))
++ ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
++ if (ret)
+ break;
+
+ ret = kvm_sev_es_mmio_read(vcpu,
+@@ -2538,7 +2544,8 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
+ svm->ghcb_sa);
+ break;
+ case SVM_VMGEXIT_MMIO_WRITE:
+- if (!setup_vmgexit_scratch(svm, false, control->exit_info_2))
++ ret = setup_vmgexit_scratch(svm, false, control->exit_info_2);
++ if (ret)
+ break;
+
+ ret = kvm_sev_es_mmio_write(vcpu,
+@@ -2581,6 +2588,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
+ vcpu_unimpl(vcpu,
+ "vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
+ control->exit_info_1, control->exit_info_2);
++ ret = -EINVAL;
+ break;
+ default:
+ ret = svm_invoke_exit_handler(vcpu, exit_code);
+@@ -2593,6 +2601,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
+ {
+ int count;
+ int bytes;
++ int r;
+
+ if (svm->vmcb->control.exit_info_2 > INT_MAX)
+ return -EINVAL;
+@@ -2601,8 +2610,9 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
+ if (unlikely(check_mul_overflow(count, size, &bytes)))
+ return -EINVAL;
+
+- if (!setup_vmgexit_scratch(svm, in, bytes))
+- return -EINVAL;
++ r = setup_vmgexit_scratch(svm, in, bytes);
++ if (r)
++ return r;
+
+ return kvm_sev_es_string_io(&svm->vcpu, size, port, svm->ghcb_sa, count, in);
+ }
+diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
+index 989685098b3ea..1fce044beebea 100644
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -4592,7 +4592,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
+ .load_eoi_exitmap = svm_load_eoi_exitmap,
+ .hwapic_irr_update = svm_hwapic_irr_update,
+ .hwapic_isr_update = svm_hwapic_isr_update,
+- .sync_pir_to_irr = kvm_lapic_find_highest_irr,
+ .apicv_post_state_restore = avic_post_state_restore,
+
+ .set_tss_addr = svm_set_tss_addr,
+diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
+index eedcebf580041..e97a11abc1d85 100644
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -523,29 +523,6 @@ static int nested_vmx_check_tpr_shadow_controls(struct kvm_vcpu *vcpu,
+ return 0;
+ }
+
+-/*
+- * Check if MSR is intercepted for L01 MSR bitmap.
+- */
+-static bool msr_write_intercepted_l01(struct kvm_vcpu *vcpu, u32 msr)
+-{
+- unsigned long *msr_bitmap;
+- int f = sizeof(unsigned long);
+-
+- if (!cpu_has_vmx_msr_bitmap())
+- return true;
+-
+- msr_bitmap = to_vmx(vcpu)->vmcs01.msr_bitmap;
+-
+- if (msr <= 0x1fff) {
+- return !!test_bit(msr, msr_bitmap + 0x800 / f);
+- } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+- msr &= 0x1fff;
+- return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+- }
+-
+- return true;
+-}
+-
+ /*
+ * If a msr is allowed by L0, we should check whether it is allowed by L1.
+ * The corresponding bit will be cleared unless both of L0 and L1 allow it.
+@@ -599,6 +576,34 @@ static inline void enable_x2apic_msr_intercepts(unsigned long *msr_bitmap)
+ }
+ }
+
++#define BUILD_NVMX_MSR_INTERCEPT_HELPER(rw) \
++static inline \
++void nested_vmx_set_msr_##rw##_intercept(struct vcpu_vmx *vmx, \
++ unsigned long *msr_bitmap_l1, \
++ unsigned long *msr_bitmap_l0, u32 msr) \
++{ \
++ if (vmx_test_msr_bitmap_##rw(vmx->vmcs01.msr_bitmap, msr) || \
++ vmx_test_msr_bitmap_##rw(msr_bitmap_l1, msr)) \
++ vmx_set_msr_bitmap_##rw(msr_bitmap_l0, msr); \
++ else \
++ vmx_clear_msr_bitmap_##rw(msr_bitmap_l0, msr); \
++}
++BUILD_NVMX_MSR_INTERCEPT_HELPER(read)
++BUILD_NVMX_MSR_INTERCEPT_HELPER(write)
++
++static inline void nested_vmx_set_intercept_for_msr(struct vcpu_vmx *vmx,
++ unsigned long *msr_bitmap_l1,
++ unsigned long *msr_bitmap_l0,
++ u32 msr, int types)
++{
++ if (types & MSR_TYPE_R)
++ nested_vmx_set_msr_read_intercept(vmx, msr_bitmap_l1,
++ msr_bitmap_l0, msr);
++ if (types & MSR_TYPE_W)
++ nested_vmx_set_msr_write_intercept(vmx, msr_bitmap_l1,
++ msr_bitmap_l0, msr);
++}
++
+ /*
+ * Merge L0's and L1's MSR bitmap, return false to indicate that
+ * we do not use the hardware.
+@@ -606,10 +611,11 @@ static inline void enable_x2apic_msr_intercepts(unsigned long *msr_bitmap)
+ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
+ struct vmcs12 *vmcs12)
+ {
++ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ int msr;
+ unsigned long *msr_bitmap_l1;
+- unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
+- struct kvm_host_map *map = &to_vmx(vcpu)->nested.msr_bitmap_map;
++ unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap;
++ struct kvm_host_map *map = &vmx->nested.msr_bitmap_map;
+
+ /* Nothing to do if the MSR bitmap is not in use. */
+ if (!cpu_has_vmx_msr_bitmap() ||
+@@ -660,44 +666,27 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
+ }
+ }
+
+- /* KVM unconditionally exposes the FS/GS base MSRs to L1. */
++ /*
++ * Always check vmcs01's bitmap to honor userspace MSR filters and any
++ * other runtime changes to vmcs01's bitmap, e.g. dynamic pass-through.
++ */
+ #ifdef CONFIG_X86_64
+- nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+- MSR_FS_BASE, MSR_TYPE_RW);
++ nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
++ MSR_FS_BASE, MSR_TYPE_RW);
+
+- nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+- MSR_GS_BASE, MSR_TYPE_RW);
++ nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
++ MSR_GS_BASE, MSR_TYPE_RW);
+
+- nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+- MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
++ nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
++ MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+ #endif
++ nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
++ MSR_IA32_SPEC_CTRL, MSR_TYPE_RW);
+
+- /*
+- * Checking the L0->L1 bitmap is trying to verify two things:
+- *
+- * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
+- * ensures that we do not accidentally generate an L02 MSR bitmap
+- * from the L12 MSR bitmap that is too permissive.
+- * 2. That L1 or L2s have actually used the MSR. This avoids
+- * unnecessarily merging of the bitmap if the MSR is unused. This
+- * works properly because we only update the L01 MSR bitmap lazily.
+- * So even if L0 should pass L1 these MSRs, the L01 bitmap is only
+- * updated to reflect this when L1 (or its L2s) actually write to
+- * the MSR.
+- */
+- if (!msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL))
+- nested_vmx_disable_intercept_for_msr(
+- msr_bitmap_l1, msr_bitmap_l0,
+- MSR_IA32_SPEC_CTRL,
+- MSR_TYPE_R | MSR_TYPE_W);
+-
+- if (!msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD))
+- nested_vmx_disable_intercept_for_msr(
+- msr_bitmap_l1, msr_bitmap_l0,
+- MSR_IA32_PRED_CMD,
+- MSR_TYPE_W);
++ nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
++ MSR_IA32_PRED_CMD, MSR_TYPE_W);
+
+- kvm_vcpu_unmap(vcpu, &to_vmx(vcpu)->nested.msr_bitmap_map, false);
++ kvm_vcpu_unmap(vcpu, &vmx->nested.msr_bitmap_map, false);
+
+ return true;
+ }
+@@ -1191,29 +1180,26 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
+ WARN_ON(!enable_vpid);
+
+ /*
+- * If VPID is enabled and used by vmc12, but L2 does not have a unique
+- * TLB tag (ASID), i.e. EPT is disabled and KVM was unable to allocate
+- * a VPID for L2, flush the current context as the effective ASID is
+- * common to both L1 and L2.
+- *
+- * Defer the flush so that it runs after vmcs02.EPTP has been set by
+- * KVM_REQ_LOAD_MMU_PGD (if nested EPT is enabled) and to avoid
+- * redundant flushes further down the nested pipeline.
+- *
+- * If a TLB flush isn't required due to any of the above, and vpid12 is
+- * changing then the new "virtual" VPID (vpid12) will reuse the same
+- * "real" VPID (vpid02), and so needs to be flushed. There's no direct
+- * mapping between vpid02 and vpid12, vpid02 is per-vCPU and reused for
+- * all nested vCPUs. Remember, a flush on VM-Enter does not invalidate
+- * guest-physical mappings, so there is no need to sync the nEPT MMU.
++ * VPID is enabled and in use by vmcs12. If vpid12 is changing, then
++ * emulate a guest TLB flush as KVM does not track vpid12 history nor
++ * is the VPID incorporated into the MMU context. I.e. KVM must assume
++ * that the new vpid12 has never been used and thus represents a new
++ * guest ASID that cannot have entries in the TLB.
+ */
+- if (!nested_has_guest_tlb_tag(vcpu)) {
+- kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+- } else if (is_vmenter &&
+- vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
++ if (is_vmenter && vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
+ vmx->nested.last_vpid = vmcs12->virtual_processor_id;
+- vpid_sync_context(nested_get_vpid02(vcpu));
++ kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
++ return;
+ }
++
++ /*
++ * If VPID is enabled, used by vmc12, and vpid12 is not changing but
++ * does not have a unique TLB tag (ASID), i.e. EPT is disabled and
++ * KVM was unable to allocate a VPID for L2, flush the current context
++ * as the effective ASID is common to both L1 and L2.
++ */
++ if (!nested_has_guest_tlb_tag(vcpu))
++ kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+ }
+
+ static bool is_bitwise_subset(u64 superset, u64 subset, u64 mask)
+@@ -2623,8 +2609,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
+
+ if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) &&
+ WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL,
+- vmcs12->guest_ia32_perf_global_ctrl)))
++ vmcs12->guest_ia32_perf_global_ctrl))) {
++ *entry_failure_code = ENTRY_FAIL_DEFAULT;
+ return -EINVAL;
++ }
+
+ kvm_rsp_write(vcpu, vmcs12->guest_rsp);
+ kvm_rip_write(vcpu, vmcs12->guest_rip);
+@@ -2865,6 +2853,17 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
+ return 0;
+ }
+
++static int nested_vmx_check_address_space_size(struct kvm_vcpu *vcpu,
++ struct vmcs12 *vmcs12)
++{
++#ifdef CONFIG_X86_64
++ if (CC(!!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) !=
++ !!(vcpu->arch.efer & EFER_LMA)))
++ return -EINVAL;
++#endif
++ return 0;
++}
++
+ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
+ struct vmcs12 *vmcs12)
+ {
+@@ -2889,18 +2888,16 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
+ return -EINVAL;
+
+ #ifdef CONFIG_X86_64
+- ia32e = !!(vcpu->arch.efer & EFER_LMA);
++ ia32e = !!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE);
+ #else
+ ia32e = false;
+ #endif
+
+ if (ia32e) {
+- if (CC(!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)) ||
+- CC(!(vmcs12->host_cr4 & X86_CR4_PAE)))
++ if (CC(!(vmcs12->host_cr4 & X86_CR4_PAE)))
+ return -EINVAL;
+ } else {
+- if (CC(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) ||
+- CC(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) ||
++ if (CC(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) ||
+ CC(vmcs12->host_cr4 & X86_CR4_PCIDE) ||
+ CC((vmcs12->host_rip) >> 32))
+ return -EINVAL;
+@@ -3360,8 +3357,7 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
+ };
+ u32 failed_index;
+
+- if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
+- kvm_vcpu_flush_tlb_current(vcpu);
++ kvm_service_local_tlb_flush_requests(vcpu);
+
+ evaluate_pending_interrupts = exec_controls_get(vmx) &
+ (CPU_BASED_INTR_WINDOW_EXITING | CPU_BASED_NMI_WINDOW_EXITING);
+@@ -3570,6 +3566,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
+ if (nested_vmx_check_controls(vcpu, vmcs12))
+ return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
+
++ if (nested_vmx_check_address_space_size(vcpu, vmcs12))
++ return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
++
+ if (nested_vmx_check_host_state(vcpu, vmcs12))
+ return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
+
+@@ -4515,9 +4514,8 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
+ (void)nested_get_evmcs_page(vcpu);
+ }
+
+- /* Service the TLB flush request for L2 before switching to L1. */
+- if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
+- kvm_vcpu_flush_tlb_current(vcpu);
++ /* Service pending TLB flush requests for L2 before switching to L1. */
++ kvm_service_local_tlb_flush_requests(vcpu);
+
+ /*
+ * VCPU_EXREG_PDPTR will be clobbered in arch/x86/kvm/vmx/vmx.h between
+diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c
+index 5f81ef092bd43..1c94783b5a54c 100644
+--- a/arch/x86/kvm/vmx/posted_intr.c
++++ b/arch/x86/kvm/vmx/posted_intr.c
+@@ -5,6 +5,7 @@
+ #include <asm/cpu.h>
+
+ #include "lapic.h"
++#include "irq.h"
+ #include "posted_intr.h"
+ #include "trace.h"
+ #include "vmx.h"
+@@ -77,13 +78,18 @@ after_clear_sn:
+ pi_set_on(pi_desc);
+ }
+
++static bool vmx_can_use_vtd_pi(struct kvm *kvm)
++{
++ return irqchip_in_kernel(kvm) && enable_apicv &&
++ kvm_arch_has_assigned_device(kvm) &&
++ irq_remapping_cap(IRQ_POSTING_CAP);
++}
++
+ void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu)
+ {
+ struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
+
+- if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
+- !irq_remapping_cap(IRQ_POSTING_CAP) ||
+- !kvm_vcpu_apicv_active(vcpu))
++ if (!vmx_can_use_vtd_pi(vcpu->kvm))
+ return;
+
+ /* Set SN when the vCPU is preempted */
+@@ -141,9 +147,7 @@ int pi_pre_block(struct kvm_vcpu *vcpu)
+ struct pi_desc old, new;
+ struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
+
+- if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
+- !irq_remapping_cap(IRQ_POSTING_CAP) ||
+- !kvm_vcpu_apicv_active(vcpu))
++ if (!vmx_can_use_vtd_pi(vcpu->kvm))
+ return 0;
+
+ WARN_ON(irqs_disabled());
+@@ -270,9 +274,7 @@ int pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq,
+ struct vcpu_data vcpu_info;
+ int idx, ret = 0;
+
+- if (!kvm_arch_has_assigned_device(kvm) ||
+- !irq_remapping_cap(IRQ_POSTING_CAP) ||
+- !kvm_vcpu_apicv_active(kvm->vcpus[0]))
++ if (!vmx_can_use_vtd_pi(kvm))
+ return 0;
+
+ idx = srcu_read_lock(&kvm->irq_srcu);
+diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
+index 7d595effb66f0..4e212f04268bb 100644
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -769,24 +769,13 @@ void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu)
+ /*
+ * 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;
+-
+- if (msr <= 0x1fff) {
+- return !!test_bit(msr, msr_bitmap + 0x800 / f);
+- } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+- msr &= 0x1fff;
+- return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+- }
+-
+- return true;
++ return vmx_test_msr_bitmap_write(vmx->loaded_vmcs->msr_bitmap,
++ MSR_IA32_SPEC_CTRL);
+ }
+
+ static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
+@@ -2927,6 +2916,13 @@ static void vmx_flush_tlb_all(struct kvm_vcpu *vcpu)
+ }
+ }
+
++static inline int vmx_get_current_vpid(struct kvm_vcpu *vcpu)
++{
++ if (is_guest_mode(vcpu))
++ return nested_get_vpid02(vcpu);
++ return to_vmx(vcpu)->vpid;
++}
++
+ static void vmx_flush_tlb_current(struct kvm_vcpu *vcpu)
+ {
+ struct kvm_mmu *mmu = vcpu->arch.mmu;
+@@ -2939,31 +2935,29 @@ static void vmx_flush_tlb_current(struct kvm_vcpu *vcpu)
+ if (enable_ept)
+ ept_sync_context(construct_eptp(vcpu, root_hpa,
+ mmu->shadow_root_level));
+- else if (!is_guest_mode(vcpu))
+- vpid_sync_context(to_vmx(vcpu)->vpid);
+ else
+- vpid_sync_context(nested_get_vpid02(vcpu));
++ vpid_sync_context(vmx_get_current_vpid(vcpu));
+ }
+
+ static void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr)
+ {
+ /*
+- * vpid_sync_vcpu_addr() is a nop if vmx->vpid==0, see the comment in
++ * vpid_sync_vcpu_addr() is a nop if vpid==0, see the comment in
+ * vmx_flush_tlb_guest() for an explanation of why this is ok.
+ */
+- vpid_sync_vcpu_addr(to_vmx(vcpu)->vpid, addr);
++ vpid_sync_vcpu_addr(vmx_get_current_vpid(vcpu), addr);
+ }
+
+ static void vmx_flush_tlb_guest(struct kvm_vcpu *vcpu)
+ {
+ /*
+- * vpid_sync_context() is a nop if vmx->vpid==0, e.g. if enable_vpid==0
+- * or a vpid couldn't be allocated for this vCPU. VM-Enter and VM-Exit
+- * are required to flush GVA->{G,H}PA mappings from the TLB if vpid is
++ * vpid_sync_context() is a nop if vpid==0, e.g. if enable_vpid==0 or a
++ * vpid couldn't be allocated for this vCPU. VM-Enter and VM-Exit are
++ * required to flush GVA->{G,H}PA mappings from the TLB if vpid is
+ * disabled (VM-Enter with vpid enabled and vpid==0 is disallowed),
+ * i.e. no explicit INVVPID is necessary.
+ */
+- vpid_sync_context(to_vmx(vcpu)->vpid);
++ vpid_sync_context(vmx_get_current_vpid(vcpu));
+ }
+
+ void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu)
+@@ -3695,46 +3689,6 @@ void free_vpid(int vpid)
+ spin_unlock(&vmx_vpid_lock);
+ }
+
+-static void vmx_clear_msr_bitmap_read(ulong *msr_bitmap, u32 msr)
+-{
+- int f = sizeof(unsigned long);
+-
+- if (msr <= 0x1fff)
+- __clear_bit(msr, msr_bitmap + 0x000 / f);
+- else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
+- __clear_bit(msr & 0x1fff, msr_bitmap + 0x400 / f);
+-}
+-
+-static void vmx_clear_msr_bitmap_write(ulong *msr_bitmap, u32 msr)
+-{
+- int f = sizeof(unsigned long);
+-
+- if (msr <= 0x1fff)
+- __clear_bit(msr, msr_bitmap + 0x800 / f);
+- else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
+- __clear_bit(msr & 0x1fff, msr_bitmap + 0xc00 / f);
+-}
+-
+-static void vmx_set_msr_bitmap_read(ulong *msr_bitmap, u32 msr)
+-{
+- int f = sizeof(unsigned long);
+-
+- if (msr <= 0x1fff)
+- __set_bit(msr, msr_bitmap + 0x000 / f);
+- else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
+- __set_bit(msr & 0x1fff, msr_bitmap + 0x400 / f);
+-}
+-
+-static void vmx_set_msr_bitmap_write(ulong *msr_bitmap, u32 msr)
+-{
+- int f = sizeof(unsigned long);
+-
+- if (msr <= 0x1fff)
+- __set_bit(msr, msr_bitmap + 0x800 / f);
+- else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
+- __set_bit(msr & 0x1fff, msr_bitmap + 0xc00 / f);
+-}
+-
+ void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type)
+ {
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+@@ -6288,9 +6242,9 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
+ {
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ int max_irr;
+- bool max_irr_updated;
++ bool got_posted_interrupt;
+
+- if (KVM_BUG_ON(!vcpu->arch.apicv_active, vcpu->kvm))
++ if (KVM_BUG_ON(!enable_apicv, vcpu->kvm))
+ return -EIO;
+
+ if (pi_test_on(&vmx->pi_desc)) {
+@@ -6300,22 +6254,33 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
+ * But on x86 this is just a compiler barrier anyway.
+ */
+ smp_mb__after_atomic();
+- max_irr_updated =
++ got_posted_interrupt =
+ kvm_apic_update_irr(vcpu, vmx->pi_desc.pir, &max_irr);
+-
+- /*
+- * If we are running L2 and L1 has a new pending interrupt
+- * which can be injected, this may cause a vmexit or it may
+- * be injected into L2. Either way, this interrupt will be
+- * processed via KVM_REQ_EVENT, not RVI, because we do not use
+- * virtual interrupt delivery to inject L1 interrupts into L2.
+- */
+- if (is_guest_mode(vcpu) && max_irr_updated)
+- kvm_make_request(KVM_REQ_EVENT, vcpu);
+ } else {
+ max_irr = kvm_lapic_find_highest_irr(vcpu);
++ got_posted_interrupt = false;
+ }
+- vmx_hwapic_irr_update(vcpu, max_irr);
++
++ /*
++ * Newly recognized interrupts are injected via either virtual interrupt
++ * delivery (RVI) or KVM_REQ_EVENT. Virtual interrupt delivery is
++ * disabled in two cases:
++ *
++ * 1) If L2 is running and the vCPU has a new pending interrupt. If L1
++ * wants to exit on interrupts, KVM_REQ_EVENT is needed to synthesize a
++ * VM-Exit to L1. If L1 doesn't want to exit, the interrupt is injected
++ * into L2, but KVM doesn't use virtual interrupt delivery to inject
++ * interrupts into L2, and so KVM_REQ_EVENT is again needed.
++ *
++ * 2) If APICv is disabled for this vCPU, assigned devices may still
++ * attempt to post interrupts. The posted interrupt vector will cause
++ * a VM-Exit and the subsequent entry will call sync_pir_to_irr.
++ */
++ if (!is_guest_mode(vcpu) && kvm_vcpu_apicv_active(vcpu))
++ vmx_set_rvi(max_irr);
++ else if (got_posted_interrupt)
++ kvm_make_request(KVM_REQ_EVENT, vcpu);
++
+ return max_irr;
+ }
+
+@@ -6720,7 +6685,7 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
+ * 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)))
++ if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
+ vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
+
+ x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0);
+@@ -7551,6 +7516,8 @@ static void vmx_migrate_timers(struct kvm_vcpu *vcpu)
+
+ static void hardware_unsetup(void)
+ {
++ kvm_set_posted_intr_wakeup_handler(NULL);
++
+ if (nested)
+ nested_vmx_hardware_unsetup();
+
+@@ -7809,10 +7776,10 @@ static __init int hardware_setup(void)
+ ple_window_shrink = 0;
+ }
+
+- if (!cpu_has_vmx_apicv()) {
++ if (!cpu_has_vmx_apicv())
+ enable_apicv = 0;
++ if (!enable_apicv)
+ vmx_x86_ops.sync_pir_to_irr = NULL;
+- }
+
+ if (cpu_has_vmx_tsc_scaling()) {
+ kvm_has_tsc_control = true;
+@@ -7879,8 +7846,6 @@ static __init int hardware_setup(void)
+ vmx_x86_ops.request_immediate_exit = __kvm_request_immediate_exit;
+ }
+
+- kvm_set_posted_intr_wakeup_handler(pi_wakeup_handler);
+-
+ kvm_mce_cap_supported |= MCG_LMCE_P;
+
+ if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST)
+@@ -7904,6 +7869,9 @@ static __init int hardware_setup(void)
+ r = alloc_kvm_area();
+ if (r)
+ nested_vmx_hardware_unsetup();
++
++ kvm_set_posted_intr_wakeup_handler(pi_wakeup_handler);
++
+ return r;
+ }
+
+diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
+index 592217fd7d920..3f9c8548625d6 100644
+--- a/arch/x86/kvm/vmx/vmx.h
++++ b/arch/x86/kvm/vmx/vmx.h
+@@ -400,6 +400,69 @@ static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,
+
+ void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu);
+
++static inline bool vmx_test_msr_bitmap_read(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ return test_bit(msr, msr_bitmap + 0x000 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ return test_bit(msr & 0x1fff, msr_bitmap + 0x400 / f);
++ return true;
++}
++
++static inline bool vmx_test_msr_bitmap_write(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ return test_bit(msr, msr_bitmap + 0x800 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ return test_bit(msr & 0x1fff, msr_bitmap + 0xc00 / f);
++ return true;
++}
++
++static inline void vmx_clear_msr_bitmap_read(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ __clear_bit(msr, msr_bitmap + 0x000 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ __clear_bit(msr & 0x1fff, msr_bitmap + 0x400 / f);
++}
++
++static inline void vmx_clear_msr_bitmap_write(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ __clear_bit(msr, msr_bitmap + 0x800 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ __clear_bit(msr & 0x1fff, msr_bitmap + 0xc00 / f);
++}
++
++static inline void vmx_set_msr_bitmap_read(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ __set_bit(msr, msr_bitmap + 0x000 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ __set_bit(msr & 0x1fff, msr_bitmap + 0x400 / f);
++}
++
++static inline void vmx_set_msr_bitmap_write(ulong *msr_bitmap, u32 msr)
++{
++ int f = sizeof(unsigned long);
++
++ if (msr <= 0x1fff)
++ __set_bit(msr, msr_bitmap + 0x800 / f);
++ else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff))
++ __set_bit(msr & 0x1fff, msr_bitmap + 0xc00 / f);
++}
++
++
+ static inline u8 vmx_get_rvi(void)
+ {
+ return vmcs_read16(GUEST_INTR_STATUS) & 0xff;
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index bfe0de3008a60..dea578586fa4e 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -1091,6 +1091,18 @@ static void kvm_invalidate_pcid(struct kvm_vcpu *vcpu, unsigned long pcid)
+ unsigned long roots_to_free = 0;
+ int i;
+
++ /*
++ * MOV CR3 and INVPCID are usually not intercepted when using TDP, but
++ * this is reachable when running EPT=1 and unrestricted_guest=0, and
++ * also via the emulator. KVM's TDP page tables are not in the scope of
++ * the invalidation, but the guest's TLB entries need to be flushed as
++ * the CPU may have cached entries in its TLB for the target PCID.
++ */
++ if (unlikely(tdp_enabled)) {
++ kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
++ return;
++ }
++
+ /*
+ * If neither the current CR3 nor any of the prev_roots use the given
+ * PCID, then nothing needs to be done here because a resync will
+@@ -3193,10 +3205,36 @@ static void kvm_vcpu_flush_tlb_guest(struct kvm_vcpu *vcpu)
+ static_call(kvm_x86_tlb_flush_guest)(vcpu);
+ }
+
++
++static inline void kvm_vcpu_flush_tlb_current(struct kvm_vcpu *vcpu)
++{
++ ++vcpu->stat.tlb_flush;
++ static_call(kvm_x86_tlb_flush_current)(vcpu);
++}
++
++/*
++ * Service "local" TLB flush requests, which are specific to the current MMU
++ * context. In addition to the generic event handling in vcpu_enter_guest(),
++ * TLB flushes that are targeted at an MMU context also need to be serviced
++ * prior before nested VM-Enter/VM-Exit.
++ */
++void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu)
++{
++ if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
++ kvm_vcpu_flush_tlb_current(vcpu);
++
++ if (kvm_check_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu))
++ kvm_vcpu_flush_tlb_guest(vcpu);
++}
++EXPORT_SYMBOL_GPL(kvm_service_local_tlb_flush_requests);
++
+ static void record_steal_time(struct kvm_vcpu *vcpu)
+ {
+- struct kvm_host_map map;
+- struct kvm_steal_time *st;
++ struct gfn_to_hva_cache *ghc = &vcpu->arch.st.cache;
++ struct kvm_steal_time __user *st;
++ struct kvm_memslots *slots;
++ u64 steal;
++ u32 version;
+
+ if (kvm_xen_msr_enabled(vcpu->kvm)) {
+ kvm_xen_runstate_set_running(vcpu);
+@@ -3206,47 +3244,86 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
+ if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
+ return;
+
+- /* -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))
++ if (WARN_ON_ONCE(current->mm != vcpu->kvm->mm))
+ return;
+
+- st = map.hva +
+- offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS);
++ slots = kvm_memslots(vcpu->kvm);
+
++ if (unlikely(slots->generation != ghc->generation ||
++ kvm_is_error_hva(ghc->hva) || !ghc->memslot)) {
++ gfn_t gfn = vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS;
++
++ /* We rely on the fact that it fits in a single page. */
++ BUILD_BUG_ON((sizeof(*st) - 1) & KVM_STEAL_VALID_BITS);
++
++ if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, gfn, sizeof(*st)) ||
++ kvm_is_error_hva(ghc->hva) || !ghc->memslot)
++ return;
++ }
++
++ st = (struct kvm_steal_time __user *)ghc->hva;
+ /*
+ * Doing a TLB flush here, on the guest's behalf, can avoid
+ * expensive IPIs.
+ */
+ if (guest_pv_has(vcpu, KVM_FEATURE_PV_TLB_FLUSH)) {
+- u8 st_preempted = xchg(&st->preempted, 0);
++ u8 st_preempted = 0;
++ int err = -EFAULT;
++
++ if (!user_access_begin(st, sizeof(*st)))
++ return;
++
++ asm volatile("1: xchgb %0, %2\n"
++ "xor %1, %1\n"
++ "2:\n"
++ _ASM_EXTABLE_UA(1b, 2b)
++ : "+q" (st_preempted),
++ "+&r" (err),
++ "+m" (st->preempted));
++ if (err)
++ goto out;
++
++ user_access_end();
++
++ vcpu->arch.st.preempted = 0;
+
+ trace_kvm_pv_tlb_flush(vcpu->vcpu_id,
+ st_preempted & KVM_VCPU_FLUSH_TLB);
+ if (st_preempted & KVM_VCPU_FLUSH_TLB)
+ kvm_vcpu_flush_tlb_guest(vcpu);
++
++ if (!user_access_begin(st, sizeof(*st)))
++ goto dirty;
+ } else {
+- st->preempted = 0;
+- }
++ if (!user_access_begin(st, sizeof(*st)))
++ return;
+
+- vcpu->arch.st.preempted = 0;
++ unsafe_put_user(0, &st->preempted, out);
++ vcpu->arch.st.preempted = 0;
++ }
+
+- if (st->version & 1)
+- st->version += 1; /* first time write, random junk */
++ unsafe_get_user(version, &st->version, out);
++ if (version & 1)
++ version += 1; /* first time write, random junk */
+
+- st->version += 1;
++ version += 1;
++ unsafe_put_user(version, &st->version, out);
+
+ smp_wmb();
+
+- st->steal += current->sched_info.run_delay -
++ unsafe_get_user(steal, &st->steal, out);
++ steal += current->sched_info.run_delay -
+ vcpu->arch.st.last_steal;
+ vcpu->arch.st.last_steal = current->sched_info.run_delay;
++ unsafe_put_user(steal, &st->steal, out);
+
+- smp_wmb();
+-
+- st->version += 1;
++ version += 1;
++ unsafe_put_user(version, &st->version, out);
+
+- kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
++ out:
++ user_access_end();
++ dirty:
++ mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa));
+ }
+
+ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+@@ -3282,7 +3359,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+
+ if (!msr_info->host_initiated)
+ return 1;
+- if (guest_cpuid_has(vcpu, X86_FEATURE_PDCM) && kvm_get_msr_feature(&msr_ent))
++ if (kvm_get_msr_feature(&msr_ent))
+ return 1;
+ if (data & ~msr_ent.data)
+ return 1;
+@@ -4285,8 +4362,10 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+
+ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
+ {
+- struct kvm_host_map map;
+- struct kvm_steal_time *st;
++ struct gfn_to_hva_cache *ghc = &vcpu->arch.st.cache;
++ struct kvm_steal_time __user *st;
++ struct kvm_memslots *slots;
++ static const u8 preempted = KVM_VCPU_PREEMPTED;
+
+ if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
+ return;
+@@ -4294,16 +4373,23 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
+ if (vcpu->arch.st.preempted)
+ return;
+
+- if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
+- &vcpu->arch.st.cache, true))
++ /* This happens on process exit */
++ if (unlikely(current->mm != vcpu->kvm->mm))
++ return;
++
++ slots = kvm_memslots(vcpu->kvm);
++
++ if (unlikely(slots->generation != ghc->generation ||
++ kvm_is_error_hva(ghc->hva) || !ghc->memslot))
+ return;
+
+- st = map.hva +
+- offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS);
++ st = (struct kvm_steal_time __user *)ghc->hva;
++ BUILD_BUG_ON(sizeof(st->preempted) != sizeof(preempted));
+
+- st->preempted = vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
++ if (!copy_to_user_nofault(&st->preempted, &preempted, sizeof(preempted)))
++ vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
+
+- kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true);
++ mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa));
+ }
+
+ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+@@ -4331,8 +4417,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_state *s)
+ {
+- if (vcpu->arch.apicv_active)
+- static_call(kvm_x86_sync_pir_to_irr)(vcpu);
++ static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
+
+ return kvm_apic_get_state(vcpu, s);
+ }
+@@ -6948,7 +7033,13 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
+ unsigned short port, void *val, unsigned int count)
+ {
+ if (vcpu->arch.pio.count) {
+- /* Complete previous iteration. */
++ /*
++ * Complete a previous iteration that required userspace I/O.
++ * Note, @count isn't guaranteed to match pio.count as userspace
++ * can modify ECX before rerunning the vCPU. Ignore any such
++ * shenanigans as KVM doesn't support modifying the rep count,
++ * and the emulator ensures @count doesn't overflow the buffer.
++ */
+ } else {
+ int r = __emulator_pio_in(vcpu, size, port, count);
+ if (!r)
+@@ -6957,7 +7048,6 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
+ /* Results already available, fall through. */
+ }
+
+- WARN_ON(count != vcpu->arch.pio.count);
+ complete_emulator_pio_in(vcpu, val);
+ return 1;
+ }
+@@ -8686,7 +8776,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
+
+ trace_kvm_hypercall(nr, a0, a1, a2, a3);
+
+- op_64_bit = is_64_bit_mode(vcpu);
++ op_64_bit = is_64_bit_hypercall(vcpu);
+ if (!op_64_bit) {
+ nr &= 0xFFFFFFFF;
+ a0 &= 0xFFFFFFFF;
+@@ -9359,8 +9449,7 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
+ if (irqchip_split(vcpu->kvm))
+ kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
+ else {
+- if (vcpu->arch.apicv_active)
+- static_call(kvm_x86_sync_pir_to_irr)(vcpu);
++ static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
+ if (ioapic_in_kernel(vcpu->kvm))
+ kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
+ }
+@@ -9378,12 +9467,16 @@ static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+ if (!kvm_apic_hw_enabled(vcpu->arch.apic))
+ return;
+
+- if (to_hv_vcpu(vcpu))
++ if (to_hv_vcpu(vcpu)) {
+ bitmap_or((ulong *)eoi_exit_bitmap,
+ vcpu->arch.ioapic_handled_vectors,
+ to_hv_synic(vcpu)->vec_bitmap, 256);
++ static_call(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
++ return;
++ }
+
+- static_call(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
++ static_call(kvm_x86_load_eoi_exitmap)(
++ vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
+ }
+
+ void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+@@ -9475,10 +9568,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
+ /* Flushing all ASIDs flushes the current ASID... */
+ kvm_clear_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+ }
+- if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
+- kvm_vcpu_flush_tlb_current(vcpu);
+- if (kvm_check_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu))
+- kvm_vcpu_flush_tlb_guest(vcpu);
++ kvm_service_local_tlb_flush_requests(vcpu);
+
+ if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
+ vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
+@@ -9629,10 +9719,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
+
+ /*
+ * This handles the case where a posted interrupt was
+- * notified with kvm_vcpu_kick.
++ * notified with kvm_vcpu_kick. Assigned devices can
++ * use the POSTED_INTR_VECTOR even if APICv is disabled,
++ * so do it even if APICv is disabled on this vCPU.
+ */
+- if (kvm_lapic_enabled(vcpu) && vcpu->arch.apicv_active)
+- static_call(kvm_x86_sync_pir_to_irr)(vcpu);
++ if (kvm_lapic_enabled(vcpu))
++ static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
+
+ if (kvm_vcpu_exit_request(vcpu)) {
+ vcpu->mode = OUTSIDE_GUEST_MODE;
+@@ -9668,8 +9760,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
+ if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST))
+ break;
+
+- if (vcpu->arch.apicv_active)
+- static_call(kvm_x86_sync_pir_to_irr)(vcpu);
++ if (kvm_lapic_enabled(vcpu))
++ static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
+
+ if (unlikely(kvm_vcpu_exit_request(vcpu))) {
+ exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED;
+@@ -10817,11 +10909,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
+
+ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+ {
+- struct gfn_to_pfn_cache *cache = &vcpu->arch.st.cache;
+ int idx;
+
+- kvm_release_pfn(cache->pfn, cache->dirty, cache);
+-
+ kvmclock_reset(vcpu);
+
+ static_call(kvm_x86_vcpu_free)(vcpu);
+diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
+index 7d66d63dc55a6..bc7ef6820ac8f 100644
+--- a/arch/x86/kvm/x86.h
++++ b/arch/x86/kvm/x86.h
+@@ -103,6 +103,7 @@ static inline unsigned int __shrink_ple_window(unsigned int val,
+
+ #define MSR_IA32_CR_PAT_DEFAULT 0x0007040600070406ULL
+
++void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu);
+ int kvm_check_nested_events(struct kvm_vcpu *vcpu);
+
+ static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu)
+@@ -153,12 +154,24 @@ static inline bool is_64_bit_mode(struct kvm_vcpu *vcpu)
+ {
+ int cs_db, cs_l;
+
++ WARN_ON_ONCE(vcpu->arch.guest_state_protected);
++
+ if (!is_long_mode(vcpu))
+ return false;
+ static_call(kvm_x86_get_cs_db_l_bits)(vcpu, &cs_db, &cs_l);
+ return cs_l;
+ }
+
++static inline bool is_64_bit_hypercall(struct kvm_vcpu *vcpu)
++{
++ /*
++ * If running with protected guest state, the CS register is not
++ * accessible. The hypercall register values will have had to been
++ * provided in 64-bit mode, so assume the guest is in 64-bit.
++ */
++ return vcpu->arch.guest_state_protected || is_64_bit_mode(vcpu);
++}
++
+ static inline bool x86_exception_has_error_code(unsigned int vector)
+ {
+ static u32 exception_has_error_code = BIT(DF_VECTOR) | BIT(TS_VECTOR) |
+@@ -173,12 +186,6 @@ static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
+ return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu;
+ }
+
+-static inline void kvm_vcpu_flush_tlb_current(struct kvm_vcpu *vcpu)
+-{
+- ++vcpu->stat.tlb_flush;
+- static_call(kvm_x86_tlb_flush_current)(vcpu);
+-}
+-
+ static inline int is_pae(struct kvm_vcpu *vcpu)
+ {
+ return kvm_read_cr4_bits(vcpu, X86_CR4_PAE);
+diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
+index 8f62baebd0286..0787d6645573e 100644
+--- a/arch/x86/kvm/xen.c
++++ b/arch/x86/kvm/xen.c
+@@ -299,7 +299,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
+ break;
+
+ case KVM_XEN_ATTR_TYPE_SHARED_INFO:
+- data->u.shared_info.gfn = gpa_to_gfn(kvm->arch.xen.shinfo_gfn);
++ data->u.shared_info.gfn = kvm->arch.xen.shinfo_gfn;
+ r = 0;
+ break;
+
+@@ -698,7 +698,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
+ kvm_hv_hypercall_enabled(vcpu))
+ return kvm_hv_hypercall(vcpu);
+
+- longmode = is_64_bit_mode(vcpu);
++ longmode = is_64_bit_hypercall(vcpu);
+ if (!longmode) {
+ params[0] = (u32)kvm_rbx_read(vcpu);
+ params[1] = (u32)kvm_rcx_read(vcpu);
+diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
+index a1d24fdc07cf0..eb3ccffb9b9dc 100644
+--- a/arch/x86/lib/insn-eval.c
++++ b/arch/x86/lib/insn-eval.c
+@@ -1417,7 +1417,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
+ }
+ }
+
+-static int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip)
++int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip)
+ {
+ unsigned long seg_base = 0;
+
+diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
+index c565def611e24..55e371cc69fd5 100644
+--- a/arch/x86/lib/insn.c
++++ b/arch/x86/lib/insn.c
+@@ -13,6 +13,7 @@
+ #endif
+ #include <asm/inat.h> /*__ignore_sync_check__ */
+ #include <asm/insn.h> /* __ignore_sync_check__ */
++#include <asm/unaligned.h> /* __ignore_sync_check__ */
+
+ #include <linux/errno.h>
+ #include <linux/kconfig.h>
+@@ -37,10 +38,10 @@
+ ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
+
+ #define __get_next(t, insn) \
+- ({ t r; memcpy(&r, insn->next_byte, sizeof(t)); insn->next_byte += sizeof(t); leXX_to_cpu(t, r); })
++ ({ t r = get_unaligned((t *)(insn)->next_byte); (insn)->next_byte += sizeof(t); leXX_to_cpu(t, r); })
+
+ #define __peek_nbyte_next(t, insn, n) \
+- ({ t r; memcpy(&r, (insn)->next_byte + n, sizeof(t)); leXX_to_cpu(t, r); })
++ ({ t r = get_unaligned((t *)(insn)->next_byte + n); leXX_to_cpu(t, r); })
+
+ #define get_next(t, insn) \
+ ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); })
+diff --git a/arch/x86/mm/cpu_entry_area.c b/arch/x86/mm/cpu_entry_area.c
+index f5e1e60c9095f..6c2f1b76a0b61 100644
+--- a/arch/x86/mm/cpu_entry_area.c
++++ b/arch/x86/mm/cpu_entry_area.c
+@@ -110,6 +110,13 @@ static void __init percpu_setup_exception_stacks(unsigned int cpu)
+ cea_map_stack(NMI);
+ cea_map_stack(DB);
+ cea_map_stack(MCE);
++
++ if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
++ if (cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT)) {
++ cea_map_stack(VC);
++ cea_map_stack(VC2);
++ }
++ }
+ }
+ #else
+ static inline void percpu_setup_exception_stacks(unsigned int cpu)
+diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
+index 84a2c8c4af735..4bfed53e210ec 100644
+--- a/arch/x86/mm/fault.c
++++ b/arch/x86/mm/fault.c
+@@ -32,6 +32,7 @@
+ #include <asm/pgtable_areas.h> /* VMALLOC_START, ... */
+ #include <asm/kvm_para.h> /* kvm_handle_async_pf */
+ #include <asm/vdso.h> /* fixup_vdso_exception() */
++#include <asm/irq_stack.h>
+
+ #define CREATE_TRACE_POINTS
+ #include <asm/trace/exceptions.h>
+@@ -631,6 +632,9 @@ static noinline void
+ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+ {
++#ifdef CONFIG_VMAP_STACK
++ struct stack_info info;
++#endif
+ unsigned long flags;
+ int sig;
+
+@@ -649,9 +653,7 @@ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
+ * that we're in vmalloc space to avoid this.
+ */
+ if (is_vmalloc_addr((void *)address) &&
+- (((unsigned long)current->stack - 1 - address < PAGE_SIZE) ||
+- address - ((unsigned long)current->stack + THREAD_SIZE) < PAGE_SIZE)) {
+- unsigned long stack = __this_cpu_ist_top_va(DF) - sizeof(void *);
++ get_stack_guard_info((void *)address, &info)) {
+ /*
+ * We're likely to be running with very little stack space
+ * left. It's plausible that we'd hit this condition but
+@@ -662,13 +664,11 @@ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
+ * and then double-fault, though, because we're likely to
+ * break the console driver and lose most of the stack dump.
+ */
+- asm volatile ("movq %[stack], %%rsp\n\t"
+- "call handle_stack_overflow\n\t"
+- "1: jmp 1b"
+- : ASM_CALL_CONSTRAINT
+- : "D" ("kernel stack overflow (page fault)"),
+- "S" (regs), "d" (address),
+- [stack] "rm" (stack));
++ call_on_stack(__this_cpu_ist_top_va(DF) - sizeof(void*),
++ handle_stack_overflow,
++ ASM_CALL_ARG3,
++ , [arg1] "r" (regs), [arg2] "r" (address), [arg3] "r" (&info));
++
+ unreachable();
+ }
+ #endif
+diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
+index ff08dc4636347..e29b1418d00c7 100644
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -20,6 +20,7 @@
+ #include <linux/bitops.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/virtio_config.h>
++#include <linux/cc_platform.h>
+
+ #include <asm/tlbflush.h>
+ #include <asm/fixmap.h>
+diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c
+index 470b202084306..700ce8fdea87c 100644
+--- a/arch/x86/mm/mem_encrypt_identity.c
++++ b/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>
+diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
+index 9ea57389c554b..d99434dc215c2 100644
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -721,6 +721,20 @@ static void maybe_emit_mod(u8 **pprog, u32 dst_reg, u32 src_reg, bool is64)
+ *pprog = prog;
+ }
+
++/*
++ * Similar version of maybe_emit_mod() for a single register
++ */
++static void maybe_emit_1mod(u8 **pprog, u32 reg, bool is64)
++{
++ u8 *prog = *pprog;
++
++ if (is64)
++ EMIT1(add_1mod(0x48, reg));
++ else if (is_ereg(reg))
++ EMIT1(add_1mod(0x40, reg));
++ *pprog = prog;
++}
++
+ /* LDX: dst_reg = *(u8*)(src_reg + off) */
+ static void emit_ldx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
+ {
+@@ -951,10 +965,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ /* neg dst */
+ case BPF_ALU | BPF_NEG:
+ case BPF_ALU64 | BPF_NEG:
+- if (BPF_CLASS(insn->code) == BPF_ALU64)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_ALU64);
+ EMIT2(0xF7, add_1reg(0xD8, dst_reg));
+ break;
+
+@@ -968,10 +980,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ case BPF_ALU64 | BPF_AND | BPF_K:
+ case BPF_ALU64 | BPF_OR | BPF_K:
+ case BPF_ALU64 | BPF_XOR | BPF_K:
+- if (BPF_CLASS(insn->code) == BPF_ALU64)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_ALU64);
+
+ /*
+ * b3 holds 'normal' opcode, b2 short form only valid
+@@ -1112,10 +1122,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ case BPF_ALU64 | BPF_LSH | BPF_K:
+ case BPF_ALU64 | BPF_RSH | BPF_K:
+ case BPF_ALU64 | BPF_ARSH | BPF_K:
+- if (BPF_CLASS(insn->code) == BPF_ALU64)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_ALU64);
+
+ b3 = simple_alu_opcodes[BPF_OP(insn->code)];
+ if (imm32 == 1)
+@@ -1146,10 +1154,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ }
+
+ /* shl %rax, %cl | shr %rax, %cl | sar %rax, %cl */
+- if (BPF_CLASS(insn->code) == BPF_ALU64)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_ALU64);
+
+ b3 = simple_alu_opcodes[BPF_OP(insn->code)];
+ EMIT2(0xD3, add_1reg(b3, dst_reg));
+@@ -1274,19 +1280,54 @@ st: if (is_imm8(insn->off))
+ case BPF_LDX | BPF_MEM | BPF_DW:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
+- /* test src_reg, src_reg */
+- maybe_emit_mod(&prog, src_reg, src_reg, true); /* always 1 byte */
+- EMIT2(0x85, add_2reg(0xC0, src_reg, src_reg));
+- /* jne start_of_ldx */
+- EMIT2(X86_JNE, 0);
++ /* Though the verifier prevents negative insn->off in BPF_PROBE_MEM
++ * add abs(insn->off) to the limit to make sure that negative
++ * offset won't be an issue.
++ * insn->off is s16, so it won't affect valid pointers.
++ */
++ u64 limit = TASK_SIZE_MAX + PAGE_SIZE + abs(insn->off);
++ u8 *end_of_jmp1, *end_of_jmp2;
++
++ /* Conservatively check that src_reg + insn->off is a kernel address:
++ * 1. src_reg + insn->off >= limit
++ * 2. src_reg + insn->off doesn't become small positive.
++ * Cannot do src_reg + insn->off >= limit in one branch,
++ * since it needs two spare registers, but JIT has only one.
++ */
++
++ /* movabsq r11, limit */
++ EMIT2(add_1mod(0x48, AUX_REG), add_1reg(0xB8, AUX_REG));
++ EMIT((u32)limit, 4);
++ EMIT(limit >> 32, 4);
++ /* cmp src_reg, r11 */
++ maybe_emit_mod(&prog, src_reg, AUX_REG, true);
++ EMIT2(0x39, add_2reg(0xC0, src_reg, AUX_REG));
++ /* if unsigned '<' goto end_of_jmp2 */
++ EMIT2(X86_JB, 0);
++ end_of_jmp1 = prog;
++
++ /* mov r11, src_reg */
++ emit_mov_reg(&prog, true, AUX_REG, src_reg);
++ /* add r11, insn->off */
++ maybe_emit_1mod(&prog, AUX_REG, true);
++ EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off);
++ /* jmp if not carry to start_of_ldx
++ * Otherwise ERR_PTR(-EINVAL) + 128 will be the user addr
++ * that has to be rejected.
++ */
++ EMIT2(0x73 /* JNC */, 0);
++ end_of_jmp2 = prog;
++
+ /* xor dst_reg, dst_reg */
+ emit_mov_imm32(&prog, false, dst_reg, 0);
+ /* jmp byte_after_ldx */
+ EMIT2(0xEB, 0);
+
+- /* populate jmp_offset for JNE above */
+- temp[4] = prog - temp - 5 /* sizeof(test + jne) */;
++ /* populate jmp_offset for JB above to jump to xor dst_reg */
++ end_of_jmp1[-1] = end_of_jmp2 - end_of_jmp1;
++ /* populate jmp_offset for JNC above to jump to start_of_ldx */
+ start_of_ldx = prog;
++ end_of_jmp2[-1] = start_of_ldx - end_of_jmp2;
+ }
+ emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
+ if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
+@@ -1332,7 +1373,7 @@ st: if (is_imm8(insn->off))
+ * End result: x86 insn "mov rbx, qword ptr [rax+0x14]"
+ * of 4 bytes will be ignored and rbx will be zero inited.
+ */
+- ex->fixup = (prog - temp) | (reg2pt_regs[dst_reg] << 8);
++ ex->fixup = (prog - start_of_ldx) | (reg2pt_regs[dst_reg] << 8);
+ }
+ break;
+
+@@ -1459,10 +1500,8 @@ st: if (is_imm8(insn->off))
+ case BPF_JMP | BPF_JSET | BPF_K:
+ case BPF_JMP32 | BPF_JSET | BPF_K:
+ /* test dst_reg, imm32 */
+- if (BPF_CLASS(insn->code) == BPF_JMP)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_JMP);
+ EMIT2_off32(0xF7, add_1reg(0xC0, dst_reg), imm32);
+ goto emit_cond_jmp;
+
+@@ -1495,10 +1534,8 @@ st: if (is_imm8(insn->off))
+ }
+
+ /* cmp dst_reg, imm8/32 */
+- if (BPF_CLASS(insn->code) == BPF_JMP)
+- EMIT1(add_1mod(0x48, dst_reg));
+- else if (is_ereg(dst_reg))
+- EMIT1(add_1mod(0x40, dst_reg));
++ maybe_emit_1mod(&prog, dst_reg,
++ BPF_CLASS(insn->code) == BPF_JMP);
+
+ if (is_imm8(imm32))
+ EMIT3(0x83, add_1reg(0xF8, dst_reg), imm32);
+diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
+index b15ebfe40a73e..b0b848d6933af 100644
+--- a/arch/x86/platform/efi/quirks.c
++++ b/arch/x86/platform/efi/quirks.c
+@@ -277,7 +277,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
+ return;
+ }
+
+- new = early_memremap(data.phys_map, data.size);
++ new = early_memremap_prot(data.phys_map, data.size,
++ pgprot_val(pgprot_encrypted(FIXMAP_PAGE_NORMAL)));
+ if (!new) {
+ pr_err("Failed to map new boot services memmap\n");
+ return;
+diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
+index 31b5856010cba..d3eee1ebcf1d5 100644
+--- a/arch/x86/realmode/init.c
++++ b/arch/x86/realmode/init.c
+@@ -72,6 +72,7 @@ static void __init setup_real_mode(void)
+ #ifdef CONFIG_X86_64
+ u64 *trampoline_pgd;
+ u64 efer;
++ int i;
+ #endif
+
+ base = (unsigned char *)real_mode_header;
+@@ -128,8 +129,17 @@ static void __init setup_real_mode(void)
+ trampoline_header->flags = 0;
+
+ 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
+
+ sme_sev_setup_real_mode(trampoline_header);
+diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S
+index 1e626444712be..3bebf66569b48 100644
+--- a/arch/x86/xen/xen-asm.S
++++ b/arch/x86/xen/xen-asm.S
+@@ -20,6 +20,7 @@
+
+ #include <linux/init.h>
+ #include <linux/linkage.h>
++#include <../entry/calling.h>
+
+ /*
+ * Enable events. This clears the event mask and tests the pending
+@@ -191,6 +192,25 @@ SYM_CODE_START(xen_iret)
+ jmp hypercall_iret
+ SYM_CODE_END(xen_iret)
+
++/*
++ * XEN pv doesn't use trampoline stack, PER_CPU_VAR(cpu_tss_rw + TSS_sp0) is
++ * also the kernel stack. Reusing swapgs_restore_regs_and_return_to_usermode()
++ * in XEN pv would cause %rsp to move up to the top of the kernel stack and
++ * leave the IRET frame below %rsp, which is dangerous to be corrupted if #NMI
++ * interrupts. And swapgs_restore_regs_and_return_to_usermode() pushing the IRET
++ * frame at the same address is useless.
++ */
++SYM_CODE_START(xenpv_restore_regs_and_return_to_usermode)
++ UNWIND_HINT_REGS
++ POP_REGS
++
++ /* stackleak_erase() can work safely on the kernel stack. */
++ STACKLEAK_ERASE_NOCLOBBER
++
++ addq $8, %rsp /* skip regs->orig_ax */
++ jmp xen_iret
++SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
++
+ /*
+ * Xen handles syscall callbacks much like ordinary exceptions, which
+ * means we have:
+diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
+index 9a1c5839dd469..0eec59e4df65c 100644
+--- a/block/blk-cgroup.c
++++ b/block/blk-cgroup.c
+@@ -633,6 +633,14 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
+
+ q = bdev->bd_disk->queue;
+
++ /*
++ * blkcg_deactivate_policy() requires queue to be frozen, we can grab
++ * q_usage_counter to prevent concurrent with blkcg_deactivate_policy().
++ */
++ ret = blk_queue_enter(q, 0);
++ if (ret)
++ goto fail;
++
+ rcu_read_lock();
+ spin_lock_irq(&q->queue_lock);
+
+@@ -667,13 +675,13 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
+ new_blkg = blkg_alloc(pos, q, GFP_KERNEL);
+ if (unlikely(!new_blkg)) {
+ ret = -ENOMEM;
+- goto fail;
++ goto fail_exit_queue;
+ }
+
+ if (radix_tree_preload(GFP_KERNEL)) {
+ blkg_free(new_blkg);
+ ret = -ENOMEM;
+- goto fail;
++ goto fail_exit_queue;
+ }
+
+ rcu_read_lock();
+@@ -702,6 +710,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
+ goto success;
+ }
+ success:
++ blk_queue_exit(q);
+ ctx->bdev = bdev;
+ ctx->blkg = blkg;
+ ctx->body = input;
+@@ -712,6 +721,8 @@ fail_preloaded:
+ fail_unlock:
+ spin_unlock_irq(&q->queue_lock);
+ rcu_read_unlock();
++fail_exit_queue:
++ blk_queue_exit(q);
+ fail:
+ blkdev_put_no_open(bdev);
+ /*
+diff --git a/block/blk-core.c b/block/blk-core.c
+index 4d8f5fe915887..c2d912d0c976c 100644
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -389,8 +389,10 @@ void blk_cleanup_queue(struct request_queue *q)
+ blk_queue_flag_set(QUEUE_FLAG_DEAD, q);
+
+ blk_sync_queue(q);
+- if (queue_is_mq(q))
++ if (queue_is_mq(q)) {
++ blk_mq_cancel_work_sync(q);
+ blk_mq_exit_queue(q);
++ }
+
+ /*
+ * In theory, request pool of sched_tags belongs to request queue.
+@@ -887,10 +889,8 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
+ if (unlikely(!current->io_context))
+ create_task_io_context(current, GFP_ATOMIC, q->node);
+
+- if (blk_throtl_bio(bio)) {
+- blkcg_bio_issue_init(bio);
++ if (blk_throtl_bio(bio))
+ return false;
+- }
+
+ blk_cgroup_bio_start(bio);
+ blkcg_bio_issue_init(bio);
+diff --git a/block/blk-iocost.c b/block/blk-iocost.c
+index b3880e4ba22a1..eb7b0d6bd11f6 100644
+--- a/block/blk-iocost.c
++++ b/block/blk-iocost.c
+@@ -2311,7 +2311,14 @@ static void ioc_timer_fn(struct timer_list *timer)
+ hwm = current_hweight_max(iocg);
+ new_hwi = hweight_after_donation(iocg, old_hwi, hwm,
+ usage, &now);
+- if (new_hwi < hwm) {
++ /*
++ * Donation calculation assumes hweight_after_donation
++ * to be positive, a condition that a donor w/ hwa < 2
++ * can't meet. Don't bother with donation if hwa is
++ * below 2. It's not gonna make a meaningful difference
++ * anyway.
++ */
++ if (new_hwi < hwm && hwa >= 2) {
+ iocg->hweight_donating = hwa;
+ iocg->hweight_after_donation = new_hwi;
+ list_add(&iocg->surplus_list, &surpluses);
+diff --git a/block/blk-mq.c b/block/blk-mq.c
+index 652a31fc3bb38..82de39926a9f6 100644
+--- a/block/blk-mq.c
++++ b/block/blk-mq.c
+@@ -763,7 +763,6 @@ void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list)
+ /* 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);
+@@ -2148,14 +2147,14 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq)
+ }
+
+ /*
+- * Allow 4x BLK_MAX_REQUEST_COUNT requests on plug queue for multiple
++ * Allow 2x BLK_MAX_REQUEST_COUNT requests on plug queue for multiple
+ * queues. This is important for md arrays to benefit from merging
+ * requests.
+ */
+ static inline unsigned short blk_plug_max_rq_count(struct blk_plug *plug)
+ {
+ if (plug->multiple_queues)
+- return BLK_MAX_REQUEST_COUNT * 4;
++ return BLK_MAX_REQUEST_COUNT * 2;
+ return BLK_MAX_REQUEST_COUNT;
+ }
+
+@@ -4019,6 +4018,19 @@ unsigned int blk_mq_rq_cpu(struct request *rq)
+ }
+ EXPORT_SYMBOL(blk_mq_rq_cpu);
+
++void blk_mq_cancel_work_sync(struct request_queue *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);
++ }
++}
++
+ static int __init blk_mq_init(void)
+ {
+ int i;
+diff --git a/block/blk-mq.h b/block/blk-mq.h
+index d08779f77a265..7cdca23b6263d 100644
+--- a/block/blk-mq.h
++++ b/block/blk-mq.h
+@@ -129,6 +129,8 @@ extern int blk_mq_sysfs_register(struct request_queue *q);
+ extern void blk_mq_sysfs_unregister(struct request_queue *q);
+ extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx);
+
++void blk_mq_cancel_work_sync(struct request_queue *q);
++
+ void blk_mq_release(struct request_queue *q);
+
+ static inline struct blk_mq_ctx *__blk_mq_get_ctx(struct request_queue *q,
+diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
+index 614d9d47de36b..4737ec024ee9b 100644
+--- a/block/blk-sysfs.c
++++ b/block/blk-sysfs.c
+@@ -805,16 +805,6 @@ static void blk_release_queue(struct kobject *kobj)
+
+ blk_free_queue_stats(q->stats);
+
+- 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);
+diff --git a/block/blk-wbt.c b/block/blk-wbt.c
+index 874c1c37bf0c6..0c119be0e8133 100644
+--- a/block/blk-wbt.c
++++ b/block/blk-wbt.c
+@@ -357,6 +357,9 @@ static void wb_timer_fn(struct blk_stat_callback *cb)
+ unsigned int inflight = wbt_inflight(rwb);
+ int status;
+
++ if (!rwb->rqos.q->disk)
++ return;
++
+ status = latency_exceeded(rwb, cb->stat);
+
+ trace_wbt_timer(rwb->rqos.q->disk->bdi, status, rqd->scale_step,
+diff --git a/block/blk-zoned.c b/block/blk-zoned.c
+index 1d0c76c18fc52..774ecc598bee2 100644
+--- a/block/blk-zoned.c
++++ b/block/blk-zoned.c
+@@ -429,9 +429,10 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
+ op = REQ_OP_ZONE_RESET;
+
+ /* Invalidate the page cache, including dirty pages. */
++ filemap_invalidate_lock(bdev->bd_inode->i_mapping);
+ ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
+ if (ret)
+- return ret;
++ goto fail;
+ break;
+ case BLKOPENZONE:
+ op = REQ_OP_ZONE_OPEN;
+@@ -449,15 +450,9 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
+ ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors,
+ GFP_KERNEL);
+
+- /*
+- * Invalidate the page cache again for zone reset: writes can only be
+- * direct for zoned devices so concurrent writes would not add any page
+- * to the page cache after/during reset. The page cache may be filled
+- * again due to concurrent reads though and dropping the pages for
+- * these is fine.
+- */
+- if (!ret && cmd == BLKRESETZONE)
+- ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
++fail:
++ if (cmd == BLKRESETZONE)
++ filemap_invalidate_unlock(bdev->bd_inode->i_mapping);
+
+ return ret;
+ }
+diff --git a/block/blk.h b/block/blk.h
+index 6c3c00a8fe19d..aab72194d2266 100644
+--- a/block/blk.h
++++ b/block/blk.h
+@@ -184,6 +184,12 @@ bool blk_bio_list_merge(struct request_queue *q, struct list_head *list,
+ void blk_account_io_start(struct request *req);
+ void blk_account_io_done(struct request *req, u64 now);
+
++/*
++ * Plug flush limits
++ */
++#define BLK_MAX_REQUEST_COUNT 32
++#define BLK_PLUG_FLUSH_SIZE (128 * 1024)
++
+ /*
+ * Internal elevator interface
+ */
+diff --git a/block/elevator.c b/block/elevator.c
+index ff45d8388f487..cd02ae332c4eb 100644
+--- a/block/elevator.c
++++ b/block/elevator.c
+@@ -694,12 +694,18 @@ void elevator_init_mq(struct request_queue *q)
+ if (!e)
+ return;
+
++ /*
++ * We are called before adding disk, when there isn't any FS I/O,
++ * so freezing queue plus canceling dispatch work is enough to
++ * drain any dispatch activities originated from passthrough
++ * requests, then no need to quiesce queue which may add long boot
++ * latency, especially when lots of disks are involved.
++ */
+ blk_mq_freeze_queue(q);
+- blk_mq_quiesce_queue(q);
++ blk_mq_cancel_work_sync(q);
+
+ err = blk_mq_init_sched(q, e);
+
+- blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
+
+ if (err) {
+diff --git a/block/genhd.c b/block/genhd.c
+index ab12ae6e636e8..f091a60dcf1ea 100644
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -467,11 +467,15 @@ int device_add_disk(struct device *parent, struct gendisk *disk,
+
+ disk->part0->bd_holder_dir =
+ kobject_create_and_add("holders", &ddev->kobj);
+- if (!disk->part0->bd_holder_dir)
++ if (!disk->part0->bd_holder_dir) {
++ ret = -ENOMEM;
+ goto out_del_integrity;
++ }
+ disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
+- if (!disk->slave_dir)
++ if (!disk->slave_dir) {
++ ret = -ENOMEM;
+ goto out_put_holder_dir;
++ }
+
+ ret = bd_register_pending_holders(disk);
+ if (ret < 0)
+@@ -1082,6 +1086,8 @@ static void disk_release(struct device *dev)
+ might_sleep();
+ WARN_ON_ONCE(disk_live(disk));
+
++ blk_mq_cancel_work_sync(disk->queue);
++
+ disk_release_events(disk);
+ kfree(disk->random);
+ xa_destroy(&disk->part_tbl);
+diff --git a/block/ioctl.c b/block/ioctl.c
+index eb0491e90b9a0..a31be7fa31a51 100644
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -113,6 +113,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
+ uint64_t range[2];
+ uint64_t start, len;
+ struct request_queue *q = bdev_get_queue(bdev);
++ struct inode *inode = bdev->bd_inode;
+ int err;
+
+ if (!(mode & FMODE_WRITE))
+@@ -135,12 +136,17 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
+ if (start + len > i_size_read(bdev->bd_inode))
+ return -EINVAL;
+
++ filemap_invalidate_lock(inode->i_mapping);
+ err = truncate_bdev_range(bdev, mode, start, start + len - 1);
+ if (err)
+- return err;
++ goto fail;
+
+- return blkdev_issue_discard(bdev, start >> 9, len >> 9,
+- GFP_KERNEL, flags);
++ err = blkdev_issue_discard(bdev, start >> 9, len >> 9,
++ GFP_KERNEL, flags);
++
++fail:
++ filemap_invalidate_unlock(inode->i_mapping);
++ return err;
+ }
+
+ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
+@@ -148,6 +154,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
+ {
+ uint64_t range[2];
+ uint64_t start, end, len;
++ struct inode *inode = bdev->bd_inode;
+ int err;
+
+ if (!(mode & FMODE_WRITE))
+@@ -170,12 +177,17 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
+ return -EINVAL;
+
+ /* Invalidate the page cache, including dirty pages */
++ filemap_invalidate_lock(inode->i_mapping);
+ err = truncate_bdev_range(bdev, mode, start, end);
+ if (err)
+- return err;
++ goto fail;
++
++ err = blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
++ BLKDEV_ZERO_NOUNMAP);
+
+- return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
+- BLKDEV_ZERO_NOUNMAP);
++fail:
++ filemap_invalidate_unlock(inode->i_mapping);
++ return err;
+ }
+
+ static int put_ushort(unsigned short __user *argp, unsigned short val)
+diff --git a/block/ioprio.c b/block/ioprio.c
+index 0e4ff245f2bf2..6f01d35a5145a 100644
+--- a/block/ioprio.c
++++ b/block/ioprio.c
+@@ -69,7 +69,14 @@ int ioprio_check_cap(int ioprio)
+
+ switch (class) {
+ case IOPRIO_CLASS_RT:
+- if (!capable(CAP_SYS_NICE) && !capable(CAP_SYS_ADMIN))
++ /*
++ * Originally this only checked for CAP_SYS_ADMIN,
++ * which was implicitly allowed for pid 0 by security
++ * modules such as SELinux. Make sure we check
++ * CAP_SYS_ADMIN first to avoid a denial/avc for
++ * possibly missing CAP_SYS_NICE permission.
++ */
++ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_NICE))
+ return -EPERM;
+ fallthrough;
+ /* rt has prio field too */
+@@ -213,6 +220,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
+ 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)
+@@ -222,6 +230,8 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
+ 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);
+diff --git a/crypto/Kconfig b/crypto/Kconfig
+index 536df4b6b825c..285f82647d2b7 100644
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -233,12 +233,12 @@ config CRYPTO_DH
+
+ 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
+
+diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
+index d569c7ed6c800..9d10b846ccf73 100644
+--- a/crypto/pcrypt.c
++++ b/crypto/pcrypt.c
+@@ -78,12 +78,14 @@ static void pcrypt_aead_enc(struct padata_priv *padata)
+ {
+ 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);
+ }
+
+@@ -123,12 +125,14 @@ static void pcrypt_aead_dec(struct padata_priv *padata)
+ {
+ 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);
+ }
+
+diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
+index 82b0400985a51..00149657a4bc1 100644
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -1333,7 +1333,7 @@ static void test_mb_skcipher_speed(const char *algo, int enc, int secs,
+
+ if (bs > XBUFSIZE * PAGE_SIZE) {
+ pr_err("template (%u) too big for buffer (%lu)\n",
+- *b_size, XBUFSIZE * PAGE_SIZE);
++ bs, XBUFSIZE * PAGE_SIZE);
+ goto out;
+ }
+
+@@ -1386,8 +1386,7 @@ static void test_mb_skcipher_speed(const char *algo, int enc, int secs,
+ memset(cur->xbuf[p], 0xff, k);
+
+ skcipher_request_set_crypt(cur->req, cur->sg,
+- cur->sg, *b_size,
+- iv);
++ cur->sg, bs, iv);
+ }
+
+ if (secs) {
+diff --git a/drivers/Makefile b/drivers/Makefile
+index be5d40ae14882..a110338c860c7 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -41,8 +41,7 @@ obj-$(CONFIG_DMADEVICES) += dma/
+ # SOC specific infrastructure drivers.
+ obj-y += soc/
+
+-obj-$(CONFIG_VIRTIO) += virtio/
+-obj-$(CONFIG_VIRTIO_PCI_LIB) += virtio/
++obj-y += virtio/
+ obj-$(CONFIG_VDPA) += vdpa/
+ obj-$(CONFIG_XEN) += xen/
+
+diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
+index b0cb662233f1a..81aff651a0d49 100644
+--- a/drivers/acpi/ac.c
++++ b/drivers/acpi/ac.c
+@@ -61,6 +61,7 @@ static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
+
+ static int ac_sleep_before_get_state_ms;
+ static int ac_check_pmic = 1;
++static int ac_only;
+
+ static struct acpi_driver acpi_ac_driver = {
+ .name = "ac",
+@@ -93,6 +94,11 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
+ if (!ac)
+ return -EINVAL;
+
++ if (ac_only) {
++ ac->state = 1;
++ return 0;
++ }
++
+ status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL,
+ &ac->state);
+ if (ACPI_FAILURE(status)) {
+@@ -200,6 +206,12 @@ static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d)
+ return 0;
+ }
+
++static int __init ac_only_quirk(const struct dmi_system_id *d)
++{
++ ac_only = 1;
++ return 0;
++}
++
+ /* Please keep this list alphabetically sorted */
+ static const struct dmi_system_id ac_dmi_table[] __initconst = {
+ {
+@@ -209,6 +221,13 @@ static const struct dmi_system_id ac_dmi_table[] __initconst = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
+ },
+ },
++ {
++ /* Kodlix GK45 returning incorrect state */
++ .callback = ac_only_quirk,
++ .matches = {
++ DMI_MATCH(DMI_PRODUCT_NAME, "GK45"),
++ },
++ },
+ {
+ /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */
+ .callback = ac_do_not_check_pmic_quirk,
+diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
+index d41b810e367c4..4366d36ef1198 100644
+--- a/drivers/acpi/acpica/acglobal.h
++++ b/drivers/acpi/acpica/acglobal.h
+@@ -226,6 +226,8 @@ extern struct acpi_bit_register_info
+ 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);
+
+ /*****************************************************************************
+ *
+diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
+index 803402aefaeb6..808fdf54aeebf 100644
+--- a/drivers/acpi/acpica/hwesleep.c
++++ b/drivers/acpi/acpica/hwesleep.c
+@@ -147,17 +147,13 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
+
+ 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),
+diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
+index 14baa13bf8482..34a3825f25d37 100644
+--- a/drivers/acpi/acpica/hwsleep.c
++++ b/drivers/acpi/acpica/hwsleep.c
+@@ -179,7 +179,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
+
+ 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 +192,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
+ * 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 +213,9 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
+
+ /* 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 */
+diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
+index 89b12afed564e..e4cde23a29061 100644
+--- a/drivers/acpi/acpica/hwxfsleep.c
++++ b/drivers/acpi/acpica/hwxfsleep.c
+@@ -217,6 +217,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
+ 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;
+diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
+index dae91f906cea9..8afa85d6eb6a7 100644
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -169,7 +169,7 @@ static int acpi_battery_is_charged(struct acpi_battery *battery)
+ 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 */
+diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
+index bd482108310cf..3fbb17ecce2d5 100644
+--- a/drivers/acpi/cppc_acpi.c
++++ b/drivers/acpi/cppc_acpi.c
+@@ -1011,7 +1011,14 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
+ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)
+ {
+ struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
+- struct cpc_register_resource *reg = &cpc_desc->cpc_regs[reg_idx];
++ struct cpc_register_resource *reg;
++
++ if (!cpc_desc) {
++ pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
++ return -ENODEV;
++ }
++
++ reg = &cpc_desc->cpc_regs[reg_idx];
+
+ if (CPC_IN_PCC(reg)) {
+ int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
+index a371f273f99dd..9cde299eba880 100644
+--- a/drivers/acpi/pmic/intel_pmic.c
++++ b/drivers/acpi/pmic/intel_pmic.c
+@@ -211,31 +211,36 @@ static acpi_status intel_pmic_regs_handler(u32 function,
+ void *handler_context, void *region_context)
+ {
+ struct intel_pmic_opregion *opregion = region_context;
+- int result = 0;
++ int result = -EINVAL;
++
++ 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;
++ }
++ }
+
+- 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;
++ if (function == ACPI_READ && address == 3) {
++ *value64 = opregion->ctx.val;
+ 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;
+- }
+- memset(&opregion->ctx, 0x00, sizeof(opregion->ctx));
+ }
+
+ if (result < 0) {
+diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
+index f0ed4414edb1f..c95eedd58f5bf 100644
+--- a/drivers/acpi/power.c
++++ b/drivers/acpi/power.c
+@@ -52,7 +52,6 @@ struct acpi_power_resource {
+ u32 order;
+ unsigned int ref_count;
+ u8 state;
+- bool wakeup_enabled;
+ struct mutex resource_lock;
+ struct list_head dependents;
+ };
+@@ -615,20 +614,19 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
+
+ list_for_each_entry(entry, list, node) {
+ struct acpi_power_resource *resource = entry->resource;
+- int result;
+ u8 state;
+
+ mutex_lock(&resource->resource_lock);
+
+- result = acpi_power_get_state(resource, &state);
+- if (result) {
+- mutex_unlock(&resource->resource_lock);
+- return result;
+- }
+- if (state == ACPI_POWER_RESOURCE_STATE_ON) {
+- resource->ref_count++;
+- resource->wakeup_enabled = true;
+- }
++ /*
++ * Make sure that the power resource state and its reference
++ * counter value are consistent with each other.
++ */
++ if (!resource->ref_count &&
++ !acpi_power_get_state(resource, &state) &&
++ state == ACPI_POWER_RESOURCE_STATE_ON)
++ __acpi_power_off(resource);
++
+ if (system_level > resource->system_level)
+ system_level = resource->system_level;
+
+@@ -711,7 +709,6 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
+ */
+ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
+ {
+- struct acpi_power_resource_entry *entry;
+ int err = 0;
+
+ if (!dev || !dev->wakeup.flags.valid)
+@@ -722,26 +719,13 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
+ if (dev->wakeup.prepare_count++)
+ goto out;
+
+- list_for_each_entry(entry, &dev->wakeup.resources, node) {
+- struct acpi_power_resource *resource = entry->resource;
+-
+- mutex_lock(&resource->resource_lock);
+-
+- if (!resource->wakeup_enabled) {
+- err = acpi_power_on_unlocked(resource);
+- if (!err)
+- resource->wakeup_enabled = true;
+- }
+-
+- mutex_unlock(&resource->resource_lock);
+-
+- if (err) {
+- dev_err(&dev->dev,
+- "Cannot turn wakeup power resources on\n");
+- dev->wakeup.flags.valid = 0;
+- goto out;
+- }
++ err = acpi_power_on_list(&dev->wakeup.resources);
++ if (err) {
++ dev_err(&dev->dev, "Cannot turn on wakeup power resources\n");
++ dev->wakeup.flags.valid = 0;
++ goto out;
+ }
++
+ /*
+ * Passing 3 as the third argument below means the device may be
+ * put into arbitrary power state afterward.
+@@ -771,39 +755,31 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
+
+ mutex_lock(&acpi_device_lock);
+
+- if (--dev->wakeup.prepare_count > 0)
++ /* Do nothing if wakeup power has not been enabled for this device. */
++ if (dev->wakeup.prepare_count <= 0)
+ goto out;
+
+- /*
+- * Executing the code below even if prepare_count is already zero when
+- * the function is called may be useful, for example for initialisation.
+- */
+- if (dev->wakeup.prepare_count < 0)
+- dev->wakeup.prepare_count = 0;
++ if (--dev->wakeup.prepare_count > 0)
++ goto out;
+
+ err = acpi_device_sleep_wake(dev, 0, 0, 0);
+ if (err)
+ goto out;
+
++ /*
++ * All of the power resources in the list need to be turned off even if
++ * there are errors.
++ */
+ list_for_each_entry(entry, &dev->wakeup.resources, node) {
+- struct acpi_power_resource *resource = entry->resource;
+-
+- mutex_lock(&resource->resource_lock);
+-
+- if (resource->wakeup_enabled) {
+- err = acpi_power_off_unlocked(resource);
+- if (!err)
+- resource->wakeup_enabled = false;
+- }
+-
+- mutex_unlock(&resource->resource_lock);
++ int ret;
+
+- if (err) {
+- dev_err(&dev->dev,
+- "Cannot turn wakeup power resources off\n");
+- dev->wakeup.flags.valid = 0;
+- break;
+- }
++ ret = acpi_power_off(entry->resource);
++ if (ret && !err)
++ err = ret;
++ }
++ if (err) {
++ dev_err(&dev->dev, "Cannot turn off wakeup power resources\n");
++ dev->wakeup.flags.valid = 0;
+ }
+
+ out:
+diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
+index e312ebaed8db4..781e312f45342 100644
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -1090,15 +1090,10 @@ struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
+ /* All data nodes have parent pointer so just return that */
+ return to_acpi_data_node(fwnode)->parent;
+ } else if (is_acpi_device_node(fwnode)) {
+- acpi_handle handle, parent_handle;
++ struct device *dev = to_acpi_device_node(fwnode)->dev.parent;
+
+- handle = to_acpi_device_node(fwnode)->handle;
+- if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
+- struct acpi_device *adev;
+-
+- if (!acpi_bus_get_device(parent_handle, &adev))
+- return acpi_fwnode_handle(adev);
+- }
++ if (dev)
++ return acpi_fwnode_handle(to_acpi_device(dev));
+ }
+
+ return NULL;
+diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
+index ee78a210c6068..3c25ce8c95ba1 100644
+--- a/drivers/acpi/resource.c
++++ b/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,9 +381,58 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
+ }
+ EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
+
++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"),
++ },
++ },
++ { }
++};
++
++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 },
++};
++
++static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
++ u8 shareable)
++{
++ 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;
+
+@@ -401,7 +451,9 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
+ * 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;
+
+diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
+index 962041148482c..6c0f7f4f7d1de 100644
+--- a/drivers/amba/bus.c
++++ b/drivers/amba/bus.c
+@@ -377,9 +377,6 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
+ 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;
+diff --git a/drivers/android/binder.c b/drivers/android/binder.c
+index 9edacc8b97688..c75fb600740cc 100644
+--- a/drivers/android/binder.c
++++ b/drivers/android/binder.c
+@@ -1870,7 +1870,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
+ 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_end_offset = is_failure && failed_at ? 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)) {
+@@ -1956,9 +1956,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
+ 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.
+ */
+@@ -2056,7 +2055,7 @@ static int binder_translate_binder(struct flat_binder_object *fp,
+ 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;
+ }
+@@ -2102,7 +2101,7 @@ static int binder_translate_handle(struct flat_binder_object *fp,
+ 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;
+ }
+@@ -2190,7 +2189,7 @@ static int binder_translate_fd(u32 fd, binder_size_t fd_offset,
+ 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;
+@@ -2595,8 +2594,8 @@ static void binder_transaction(struct binder_proc *proc,
+ return_error_line = __LINE__;
+ goto err_invalid_target_handle;
+ }
+- if (security_binder_transaction(proc->tsk,
+- target_proc->tsk) < 0) {
++ if (security_binder_transaction(proc->cred,
++ target_proc->cred) < 0) {
+ return_error = BR_FAILED_REPLY;
+ return_error_param = -EPERM;
+ return_error_line = __LINE__;
+@@ -2722,16 +2721,7 @@ static void binder_transaction(struct binder_proc *proc,
+ u32 secid;
+ size_t added_size;
+
+- /*
+- * Arguably this should be the task's subjective LSM secid but
+- * we can't reliably access the subjective creds of a task
+- * other than our own so we must use the objective creds, which
+- * are safe to access. The downside is that if a task is
+- * temporarily overriding it's creds it will not be reflected
+- * here; however, it isn't clear that binder would handle that
+- * case well anyway.
+- */
+- security_task_getsecid_obj(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;
+@@ -3185,6 +3175,7 @@ err_invalid_target_handle:
+ * 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.
+@@ -3194,7 +3185,7 @@ err_invalid_target_handle:
+ static void
+ binder_free_buf(struct binder_proc *proc,
+ struct binder_thread *thread,
+- struct binder_buffer *buffer)
++ struct binder_buffer *buffer, bool is_failure)
+ {
+ binder_inner_proc_lock(proc);
+ if (buffer->transaction) {
+@@ -3222,7 +3213,7 @@ binder_free_buf(struct binder_proc *proc,
+ binder_node_inner_unlock(buf_node);
+ }
+ trace_binder_transaction_buffer_release(buffer);
+- binder_transaction_buffer_release(proc, thread, buffer, 0, false);
++ binder_transaction_buffer_release(proc, thread, buffer, 0, is_failure);
+ binder_alloc_free_buf(&proc->alloc, buffer);
+ }
+
+@@ -3424,7 +3415,7 @@ static int binder_thread_write(struct binder_proc *proc,
+ proc->pid, thread->pid, (u64)data_ptr,
+ buffer->debug_id,
+ buffer->transaction ? "active" : "finished");
+- binder_free_buf(proc, thread, buffer);
++ binder_free_buf(proc, thread, buffer, false);
+ break;
+ }
+
+@@ -4117,7 +4108,7 @@ retry:
+ buffer->transaction = NULL;
+ binder_cleanup_transaction(t, "fd fixups failed",
+ BR_FAILED_REPLY);
+- binder_free_buf(proc, thread, 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,
+@@ -4353,6 +4344,7 @@ static void binder_free_proc(struct binder_proc *proc)
+ }
+ binder_alloc_deferred_release(&proc->alloc);
+ put_task_struct(proc->tsk);
++ put_cred(proc->cred);
+ binder_stats_deleted(BINDER_STAT_PROC);
+ kfree(proc);
+ }
+@@ -4430,23 +4422,20 @@ static int binder_thread_release(struct binder_proc *proc,
+ __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();
+@@ -4564,7 +4553,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp,
+ 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)) {
+@@ -5055,6 +5044,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
+ 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);
+ init_waitqueue_head(&proc->freeze_wait);
+ proc->default_priority = task_nice(current);
+diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h
+index 402c4d4362a83..d6b6b8cb73465 100644
+--- a/drivers/android/binder_internal.h
++++ b/drivers/android/binder_internal.h
+@@ -364,6 +364,9 @@ struct binder_ref {
+ * (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
+@@ -426,6 +429,7 @@ struct binder_proc {
+ struct list_head waiting_threads;
+ int pid;
+ struct task_struct *tsk;
++ const struct cred *cred;
+ struct hlist_node deferred_work_node;
+ int deferred_work;
+ int outstanding_txns;
+diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
+index 186cbf90c8ead..812731e80f8e0 100644
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -442,6 +442,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ /* 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 },
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index 5b3fa2cbe7223..395772fa39432 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -2305,6 +2305,18 @@ int ahci_port_resume(struct ata_port *ap)
+ EXPORT_SYMBOL_GPL(ahci_port_resume);
+
+ #ifdef CONFIG_PM
++static void ahci_handle_s2idle(struct ata_port *ap)
++{
++ void __iomem *port_mmio = ahci_port_base(ap);
++ u32 devslp;
++
++ if (pm_suspend_via_firmware())
++ return;
++ devslp = readl(port_mmio + PORT_DEVSLP);
++ if ((devslp & PORT_DEVSLP_ADSE))
++ ata_msleep(ap, devslp_idle_timeout);
++}
++
+ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+ {
+ const char *emsg = NULL;
+@@ -2318,6 +2330,9 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+ ata_port_freeze(ap);
+ }
+
++ if (acpi_storage_d3(ap->host->dev))
++ ahci_handle_s2idle(ap);
++
+ ahci_rpm_put_port(ap);
+ return rc;
+ }
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index eed65311b5d1d..4d848cfc406fe 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -2007,7 +2007,7 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+
+ 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;
+@@ -2031,8 +2031,9 @@ retry:
+ dev->horkage |= ATA_HORKAGE_NO_DMA_LOG;
+ goto retry;
+ }
+- ata_dev_err(dev, "Read log page 0x%02x failed, Emask 0x%x\n",
+- (unsigned int)page, err_mask);
++ ata_dev_err(dev,
++ "Read log 0x%02x page 0x%02x failed, Emask 0x%x\n",
++ (unsigned int)log, (unsigned int)page, err_mask);
+ }
+
+ return err_mask;
+@@ -2166,6 +2167,9 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
+ struct ata_port *ap = dev->link->ap;
+ unsigned int err_mask;
+
++ if (!ata_identify_page_supported(dev, ATA_LOG_SATA_SETTINGS))
++ return;
++
+ err_mask = ata_read_log_page(dev,
+ ATA_LOG_IDENTIFY_DEVICE,
+ ATA_LOG_SATA_SETTINGS,
+@@ -2442,7 +2446,8 @@ static void ata_dev_config_devslp(struct ata_device *dev)
+ * Check device sleep capability. Get DevSlp timing variables
+ * from SATA Settings page of Identify Device Data Log.
+ */
+- if (!ata_id_has_devslp(dev->id))
++ if (!ata_id_has_devslp(dev->id) ||
++ !ata_identify_page_supported(dev, ATA_LOG_SATA_SETTINGS))
+ return;
+
+ err_mask = ata_read_log_page(dev,
+@@ -3851,6 +3856,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
+ { "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 },
+diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
+index bf9c4b6c5c3d4..1d4a6f1e88cd1 100644
+--- a/drivers/ata/libata-eh.c
++++ b/drivers/ata/libata-eh.c
+@@ -93,6 +93,12 @@ static const unsigned long ata_eh_identify_timeouts[] = {
+ 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 */
+@@ -129,6 +135,8 @@ static const struct ata_eh_cmd_timeout_ent
+ 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),
+diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
+index 1fb4611f7eeb9..10303611d17b9 100644
+--- a/drivers/ata/libata-scsi.c
++++ b/drivers/ata/libata-scsi.c
+@@ -2826,8 +2826,19 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
+ 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;
+diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
+index e5838b23c9e0a..3b31a4f596d86 100644
+--- a/drivers/ata/sata_fsl.c
++++ b/drivers/ata/sata_fsl.c
+@@ -1394,6 +1394,14 @@ static int sata_fsl_init_controller(struct ata_host *host)
+ 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
+ */
+@@ -1426,6 +1434,8 @@ static struct ata_port_operations sata_fsl_ops = {
+ .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,
+ };
+@@ -1480,9 +1490,9 @@ static int sata_fsl_probe(struct platform_device *ofdev)
+ 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;
+@@ -1557,10 +1567,6 @@ static int sata_fsl_remove(struct platform_device *ofdev)
+
+ ata_host_detach(host);
+
+- irq_dispose_mapping(host_priv->irq);
+- iounmap(host_priv->hcr_base);
+- kfree(host_priv);
+-
+ return 0;
+ }
+
+diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c
+index 1e69cc6d21a0d..ed58083499907 100644
+--- a/drivers/auxdisplay/ht16k33.c
++++ b/drivers/auxdisplay/ht16k33.c
+@@ -219,6 +219,15 @@ static const struct backlight_ops ht16k33_bl_ops = {
+ .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;
+@@ -231,6 +240,7 @@ static const struct fb_ops ht16k33_fb_ops = {
+ .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,
+@@ -413,6 +423,33 @@ static int ht16k33_probe(struct i2c_client *client,
+ 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);
+@@ -445,6 +482,7 @@ static int ht16k33_probe(struct i2c_client *client,
+ 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;
+@@ -460,34 +498,6 @@ static int ht16k33_probe(struct i2c_client *client,
+ 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;
+
+diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c
+index 1cce409ce5cac..e33ce0151cdfd 100644
+--- a/drivers/auxdisplay/img-ascii-lcd.c
++++ b/drivers/auxdisplay/img-ascii-lcd.c
+@@ -280,6 +280,16 @@ static int img_ascii_lcd_display(struct img_ascii_lcd_ctx *ctx,
+ 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;
+diff --git a/drivers/base/component.c b/drivers/base/component.c
+index 5e79299f6c3ff..870485cbbb87c 100644
+--- a/drivers/base/component.c
++++ b/drivers/base/component.c
+@@ -246,7 +246,7 @@ static int try_to_bring_up_master(struct master *master,
+ return 0;
+ }
+
+- if (!devres_open_group(master->parent, NULL, GFP_KERNEL))
++ if (!devres_open_group(master->parent, master, GFP_KERNEL))
+ return -ENOMEM;
+
+ /* Found all components */
+@@ -258,6 +258,7 @@ static int try_to_bring_up_master(struct master *master,
+ return ret;
+ }
+
++ devres_close_group(master->parent, NULL);
+ master->bound = true;
+ return 1;
+ }
+@@ -282,7 +283,7 @@ static void take_down_master(struct master *master)
+ {
+ if (master->bound) {
+ master->ops->unbind(master->parent);
+- devres_release_group(master->parent, NULL);
++ devres_release_group(master->parent, master);
+ master->bound = false;
+ }
+ }
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 249da496581a0..63577de268565 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -821,9 +821,7 @@ struct device_link *device_link_add(struct device *consumer,
+ dev_bus_name(supplier), dev_name(supplier),
+ dev_bus_name(consumer), dev_name(consumer));
+ if (device_register(&link->link_dev)) {
+- put_device(consumer);
+- put_device(supplier);
+- kfree(link);
++ put_device(&link->link_dev);
+ link = NULL;
+ goto out;
+ }
+diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
+index bdbedc6660a87..ef904b8b112e6 100644
+--- a/drivers/base/firmware_loader/main.c
++++ b/drivers/base/firmware_loader/main.c
+@@ -100,12 +100,15 @@ static struct firmware_cache fw_cache;
+ 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,
+@@ -117,9 +120,7 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
+ 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);
+ }
+ }
+
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index cbea78e79f3df..a7fdd86fad057 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -711,6 +711,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
+ dev = to_device(dpm_noirq_list.next);
+ get_device(dev);
+ list_move_tail(&dev->power.entry, &dpm_late_early_list);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ if (!is_async(dev)) {
+@@ -725,8 +726,9 @@ static void dpm_noirq_resume_devices(pm_message_t state)
+ }
+ }
+
+- mutex_lock(&dpm_list_mtx);
+ put_device(dev);
++
++ mutex_lock(&dpm_list_mtx);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
+@@ -852,6 +854,7 @@ void dpm_resume_early(pm_message_t state)
+ dev = to_device(dpm_late_early_list.next);
+ get_device(dev);
+ list_move_tail(&dev->power.entry, &dpm_suspended_list);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ if (!is_async(dev)) {
+@@ -865,8 +868,10 @@ void dpm_resume_early(pm_message_t state)
+ pm_dev_err(dev, state, " early", error);
+ }
+ }
+- mutex_lock(&dpm_list_mtx);
++
+ put_device(dev);
++
++ mutex_lock(&dpm_list_mtx);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
+@@ -1029,7 +1034,12 @@ void dpm_resume(pm_message_t state)
+ }
+ if (!list_empty(&dev->power.entry))
+ list_move_tail(&dev->power.entry, &dpm_prepared_list);
++
++ mutex_unlock(&dpm_list_mtx);
++
+ put_device(dev);
++
++ mutex_lock(&dpm_list_mtx);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
+@@ -1051,7 +1061,7 @@ static void device_complete(struct device *dev, pm_message_t state)
+ const char *info = NULL;
+
+ if (dev->power.syscore)
+- return;
++ goto out;
+
+ device_lock(dev);
+
+@@ -1081,6 +1091,7 @@ static void device_complete(struct device *dev, pm_message_t state)
+
+ device_unlock(dev);
+
++out:
+ pm_runtime_put(dev);
+ }
+
+@@ -1106,14 +1117,16 @@ void dpm_complete(pm_message_t state)
+ get_device(dev);
+ dev->power.is_prepared = false;
+ list_move(&dev->power.entry, &list);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ trace_device_pm_callback_start(dev, "", state.event);
+ device_complete(dev, state);
+ trace_device_pm_callback_end(dev, 0);
+
+- mutex_lock(&dpm_list_mtx);
+ put_device(dev);
++
++ mutex_lock(&dpm_list_mtx);
+ }
+ list_splice(&list, &dpm_list);
+ mutex_unlock(&dpm_list_mtx);
+@@ -1298,17 +1311,21 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
+ error = device_suspend_noirq(dev);
+
+ mutex_lock(&dpm_list_mtx);
++
+ if (error) {
+ pm_dev_err(dev, state, " noirq", error);
+ dpm_save_failed_dev(dev_name(dev));
+- put_device(dev);
+- break;
+- }
+- if (!list_empty(&dev->power.entry))
++ } else if (!list_empty(&dev->power.entry)) {
+ list_move(&dev->power.entry, &dpm_noirq_list);
++ }
++
++ mutex_unlock(&dpm_list_mtx);
++
+ put_device(dev);
+
+- if (async_error)
++ mutex_lock(&dpm_list_mtx);
++
++ if (error || async_error)
+ break;
+ }
+ mutex_unlock(&dpm_list_mtx);
+@@ -1475,23 +1492,28 @@ int dpm_suspend_late(pm_message_t state)
+ struct device *dev = to_device(dpm_suspended_list.prev);
+
+ get_device(dev);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ error = device_suspend_late(dev);
+
+ mutex_lock(&dpm_list_mtx);
++
+ if (!list_empty(&dev->power.entry))
+ list_move(&dev->power.entry, &dpm_late_early_list);
+
+ if (error) {
+ pm_dev_err(dev, state, " late", error);
+ dpm_save_failed_dev(dev_name(dev));
+- put_device(dev);
+- break;
+ }
++
++ mutex_unlock(&dpm_list_mtx);
++
+ put_device(dev);
+
+- if (async_error)
++ mutex_lock(&dpm_list_mtx);
++
++ if (error || async_error)
+ break;
+ }
+ mutex_unlock(&dpm_list_mtx);
+@@ -1751,21 +1773,27 @@ int dpm_suspend(pm_message_t state)
+ struct device *dev = to_device(dpm_prepared_list.prev);
+
+ get_device(dev);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ error = device_suspend(dev);
+
+ mutex_lock(&dpm_list_mtx);
++
+ if (error) {
+ pm_dev_err(dev, state, "", error);
+ dpm_save_failed_dev(dev_name(dev));
+- put_device(dev);
+- break;
+- }
+- if (!list_empty(&dev->power.entry))
++ } else if (!list_empty(&dev->power.entry)) {
+ list_move(&dev->power.entry, &dpm_suspended_list);
++ }
++
++ mutex_unlock(&dpm_list_mtx);
++
+ put_device(dev);
+- if (async_error)
++
++ mutex_lock(&dpm_list_mtx);
++
++ if (error || async_error)
+ break;
+ }
+ mutex_unlock(&dpm_list_mtx);
+@@ -1794,9 +1822,6 @@ static int device_prepare(struct device *dev, pm_message_t state)
+ int (*callback)(struct device *) = NULL;
+ int ret = 0;
+
+- if (dev->power.syscore)
+- return 0;
+-
+ /*
+ * If a device's parent goes into runtime suspend at the wrong time,
+ * it won't be possible to resume the device. To prevent this we
+@@ -1805,6 +1830,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
+ */
+ pm_runtime_get_noresume(dev);
+
++ if (dev->power.syscore)
++ return 0;
++
+ device_lock(dev);
+
+ dev->power.wakeup_path = false;
+@@ -1882,6 +1910,7 @@ int dpm_prepare(pm_message_t state)
+ struct device *dev = to_device(dpm_list.next);
+
+ get_device(dev);
++
+ mutex_unlock(&dpm_list_mtx);
+
+ trace_device_pm_callback_start(dev, "", state.event);
+@@ -1889,21 +1918,23 @@ int dpm_prepare(pm_message_t state)
+ trace_device_pm_callback_end(dev, error);
+
+ mutex_lock(&dpm_list_mtx);
+- if (error) {
+- if (error == -EAGAIN) {
+- put_device(dev);
+- error = 0;
+- continue;
+- }
++
++ if (!error) {
++ dev->power.is_prepared = true;
++ if (!list_empty(&dev->power.entry))
++ list_move_tail(&dev->power.entry, &dpm_prepared_list);
++ } else if (error == -EAGAIN) {
++ error = 0;
++ } else {
+ dev_info(dev, "not prepared for power transition: code %d\n",
+ error);
+- put_device(dev);
+- break;
+ }
+- dev->power.is_prepared = true;
+- if (!list_empty(&dev->power.entry))
+- list_move_tail(&dev->power.entry, &dpm_prepared_list);
++
++ mutex_unlock(&dpm_list_mtx);
++
+ put_device(dev);
++
++ mutex_lock(&dpm_list_mtx);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ trace_suspend_resume(TPS("dpm_prepare"), state.event, false);
+diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
+index a093644ac39fb..aab48b292a3bb 100644
+--- a/drivers/block/ataflop.c
++++ b/drivers/block/ataflop.c
+@@ -298,6 +298,7 @@ static struct atari_floppy_struct {
+ disk change detection) */
+ int flags; /* flags */
+ struct gendisk *disk[NUM_DISK_MINORS];
++ bool registered[NUM_DISK_MINORS];
+ int ref;
+ int type;
+ struct blk_mq_tag_set tag_set;
+@@ -456,10 +457,20 @@ static DEFINE_TIMER(fd_timer, check_change);
+
+ static void fd_end_request_cur(blk_status_t err)
+ {
++ DPRINT(("fd_end_request_cur(), bytes %d of %d\n",
++ blk_rq_cur_bytes(fd_request),
++ blk_rq_bytes(fd_request)));
++
+ if (!blk_update_request(fd_request, err,
+ blk_rq_cur_bytes(fd_request))) {
++ DPRINT(("calling __blk_mq_end_request()\n"));
+ __blk_mq_end_request(fd_request, err);
+ fd_request = NULL;
++ } else {
++ /* requeue rest of request */
++ DPRINT(("calling blk_mq_requeue_request()\n"));
++ blk_mq_requeue_request(fd_request, true);
++ fd_request = NULL;
+ }
+ }
+
+@@ -653,9 +664,6 @@ static inline void copy_buffer(void *from, void *to)
+ *p2++ = *p1++;
+ }
+
+-
+-
+-
+ /* General Interrupt Handling */
+
+ static void (*FloppyIRQHandler)( int status ) = NULL;
+@@ -700,12 +708,21 @@ static void fd_error( void )
+ if (fd_request->error_count >= MAX_ERRORS) {
+ printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ finish_fdc();
++ return;
+ }
+ else if (fd_request->error_count == RECALIBRATE_ERRORS) {
+ printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
+ if (SelectedDrive != -1)
+ SUD.track = -1;
+ }
++ /* need to re-run request to recalibrate */
++ atari_disable_irq( IRQ_MFP_FDC );
++
++ setup_req_params( SelectedDrive );
++ do_fd_action( SelectedDrive );
++
++ atari_enable_irq( IRQ_MFP_FDC );
+ }
+
+
+@@ -732,8 +749,10 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
+ if (type) {
+ type--;
+ if (type >= NUM_DISK_MINORS ||
+- minor2disktype[type].drive_types > DriveType)
++ minor2disktype[type].drive_types > DriveType) {
++ finish_fdc();
+ return -EINVAL;
++ }
+ }
+
+ q = unit[drive].disk[type]->queue;
+@@ -751,6 +770,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
+ }
+
+ if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
++ finish_fdc();
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -791,6 +811,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
+
+ wait_for_completion(&format_wait);
+
++ finish_fdc();
+ ret = FormatError ? -EIO : 0;
+ out:
+ blk_mq_unquiesce_queue(q);
+@@ -825,6 +846,7 @@ static void do_fd_action( int drive )
+ else {
+ /* all sectors finished */
+ fd_end_request_cur(BLK_STS_OK);
++ finish_fdc();
+ return;
+ }
+ }
+@@ -1229,6 +1251,7 @@ static void fd_rwsec_done1(int status)
+ else {
+ /* all sectors finished */
+ fd_end_request_cur(BLK_STS_OK);
++ finish_fdc();
+ }
+ return;
+
+@@ -1350,7 +1373,7 @@ static void fd_times_out(struct timer_list *unused)
+
+ static void finish_fdc( void )
+ {
+- if (!NeedSeek) {
++ if (!NeedSeek || !stdma_is_locked_by(floppy_irq)) {
+ finish_fdc_done( 0 );
+ }
+ else {
+@@ -1385,7 +1408,8 @@ static void finish_fdc_done( int dummy )
+ start_motor_off_timer();
+
+ local_irq_save(flags);
+- stdma_release();
++ if (stdma_is_locked_by(floppy_irq))
++ stdma_release();
+ local_irq_restore(flags);
+
+ DPRINT(("finish_fdc() finished\n"));
+@@ -1475,15 +1499,6 @@ static void setup_req_params( int drive )
+ 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)
+ {
+@@ -1491,6 +1506,10 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ int drive = floppy - unit;
+ int type = floppy->type;
+
++ DPRINT(("Queue request: drive %d type %d sectors %d of %d last %d\n",
++ drive, type, blk_rq_cur_sectors(bd->rq),
++ blk_rq_sectors(bd->rq), bd->last));
++
+ spin_lock_irq(&ataflop_lock);
+ if (fd_request) {
+ spin_unlock_irq(&ataflop_lock);
+@@ -1511,6 +1530,7 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ /* drive not connected */
+ printk(KERN_ERR "Unknown Device: fd%d\n", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+
+@@ -1527,11 +1547,13 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ if (--type >= NUM_DISK_MINORS) {
+ printk(KERN_WARNING "fd%d: invalid disk format", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+ if (minor2disktype[type].drive_types > DriveType) {
+ printk(KERN_WARNING "fd%d: unsupported disk format", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+ type = minor2disktype[type].index;
+@@ -1550,8 +1572,6 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ setup_req_params( drive );
+ do_fd_action( drive );
+
+- if (bd->last)
+- finish_fdc();
+ atari_enable_irq( IRQ_MFP_FDC );
+
+ out:
+@@ -1634,6 +1654,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
+ /* what if type > 0 here? Overwrite specified entry ? */
+ if (type) {
+ /* refuse to re-set a predefined type for now */
++ finish_fdc();
+ return -EINVAL;
+ }
+
+@@ -1701,8 +1722,10 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
+
+ /* sanity check */
+ if (setprm.track != dtp->blocks/dtp->spt/2 ||
+- setprm.head != 2)
++ setprm.head != 2) {
++ finish_fdc();
+ return -EINVAL;
++ }
+
+ UDT = dtp;
+ set_capacity(disk, UDT->blocks);
+@@ -1962,7 +1985,6 @@ static const struct block_device_operations floppy_fops = {
+
+ static const struct blk_mq_ops ataflop_mq_ops = {
+ .queue_rq = ataflop_queue_rq,
+- .commit_rqs = ataflop_commit_rqs,
+ };
+
+ static int ataflop_alloc_disk(unsigned int drive, unsigned int type)
+@@ -1986,8 +2008,6 @@ static int ataflop_alloc_disk(unsigned int drive, unsigned int type)
+ return 0;
+ }
+
+-static DEFINE_MUTEX(ataflop_probe_lock);
+-
+ static void ataflop_probe(dev_t dev)
+ {
+ int drive = MINOR(dev) & 3;
+@@ -1998,12 +2018,46 @@ static void ataflop_probe(dev_t dev)
+
+ if (drive >= FD_MAX_UNITS || type >= NUM_DISK_MINORS)
+ return;
+- mutex_lock(&ataflop_probe_lock);
+ if (!unit[drive].disk[type]) {
+- if (ataflop_alloc_disk(drive, type) == 0)
++ if (ataflop_alloc_disk(drive, type) == 0) {
+ add_disk(unit[drive].disk[type]);
++ unit[drive].registered[type] = true;
++ }
++ }
++}
++
++static void atari_floppy_cleanup(void)
++{
++ int i;
++ int type;
++
++ for (i = 0; i < FD_MAX_UNITS; i++) {
++ for (type = 0; type < NUM_DISK_MINORS; type++) {
++ if (!unit[i].disk[type])
++ continue;
++ del_gendisk(unit[i].disk[type]);
++ blk_cleanup_queue(unit[i].disk[type]->queue);
++ put_disk(unit[i].disk[type]);
++ }
++ blk_mq_free_tag_set(&unit[i].tag_set);
++ }
++
++ del_timer_sync(&fd_timer);
++ atari_stram_free(DMABuffer);
++}
++
++static void atari_cleanup_floppy_disk(struct atari_floppy_struct *fs)
++{
++ int type;
++
++ for (type = 0; type < NUM_DISK_MINORS; type++) {
++ if (!fs->disk[type])
++ continue;
++ if (fs->registered[type])
++ del_gendisk(fs->disk[type]);
++ blk_cleanup_disk(fs->disk[type]);
+ }
+- mutex_unlock(&ataflop_probe_lock);
++ blk_mq_free_tag_set(&fs->tag_set);
+ }
+
+ static int __init atari_floppy_init (void)
+@@ -2015,11 +2069,6 @@ static int __init atari_floppy_init (void)
+ /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
+ return -ENODEV;
+
+- mutex_lock(&ataflop_probe_lock);
+- ret = __register_blkdev(FLOPPY_MAJOR, "fd", ataflop_probe);
+- if (ret)
+- goto out_unlock;
+-
+ for (i = 0; i < FD_MAX_UNITS; i++) {
+ memset(&unit[i].tag_set, 0, sizeof(unit[i].tag_set));
+ unit[i].tag_set.ops = &ataflop_mq_ops;
+@@ -2065,6 +2114,7 @@ static int __init atari_floppy_init (void)
+ unit[i].track = -1;
+ unit[i].flags = 0;
+ add_disk(unit[i].disk[0]);
++ unit[i].registered[0] = true;
+ }
+
+ printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
+@@ -2072,18 +2122,17 @@ static int __init atari_floppy_init (void)
+ UseTrackbuffer ? "" : "no ");
+ config_types();
+
+- return 0;
++ ret = __register_blkdev(FLOPPY_MAJOR, "fd", ataflop_probe);
++ if (ret) {
++ printk(KERN_ERR "atari_floppy_init: cannot register block device\n");
++ atari_floppy_cleanup();
++ }
++ return ret;
+
+ err:
+- while (--i >= 0) {
+- blk_cleanup_queue(unit[i].disk[0]->queue);
+- put_disk(unit[i].disk[0]);
+- blk_mq_free_tag_set(&unit[i].tag_set);
+- }
++ while (--i >= 0)
++ atari_cleanup_floppy_disk(&unit[i]);
+
+- unregister_blkdev(FLOPPY_MAJOR, "fd");
+-out_unlock:
+- mutex_unlock(&ataflop_probe_lock);
+ return ret;
+ }
+
+@@ -2128,22 +2177,8 @@ __setup("floppy=", atari_floppy_setup);
+
+ static void __exit atari_floppy_exit(void)
+ {
+- int i, type;
+-
+- for (i = 0; i < FD_MAX_UNITS; i++) {
+- for (type = 0; type < NUM_DISK_MINORS; type++) {
+- if (!unit[i].disk[type])
+- continue;
+- del_gendisk(unit[i].disk[type]);
+- blk_cleanup_queue(unit[i].disk[type]->queue);
+- put_disk(unit[i].disk[type]);
+- }
+- blk_mq_free_tag_set(&unit[i].tag_set);
+- }
+ unregister_blkdev(FLOPPY_MAJOR, "fd");
+-
+- del_timer_sync(&fd_timer);
+- atari_stram_free( DMABuffer );
++ atari_floppy_cleanup();
+ }
+
+ module_init(atari_floppy_init)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index fef79ea52e3ed..fb2aafabfebc1 100644
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -4478,6 +4478,7 @@ static const struct blk_mq_ops floppy_mq_ops = {
+ };
+
+ static struct platform_device floppy_device[N_DRIVE];
++static bool registered[N_DRIVE];
+
+ static bool floppy_available(int drive)
+ {
+@@ -4693,6 +4694,8 @@ static int __init do_floppy_init(void)
+ if (err)
+ goto out_remove_drives;
+
++ registered[drive] = true;
++
+ device_add_disk(&floppy_device[drive].dev, disks[drive][0],
+ NULL);
+ }
+@@ -4703,7 +4706,8 @@ out_remove_drives:
+ while (drive--) {
+ if (floppy_available(drive)) {
+ del_gendisk(disks[drive][0]);
+- platform_device_unregister(&floppy_device[drive]);
++ if (registered[drive])
++ platform_device_unregister(&floppy_device[drive]);
+ }
+ }
+ out_release_dma:
+@@ -4946,7 +4950,8 @@ static void __exit floppy_module_exit(void)
+ if (disks[drive][i])
+ del_gendisk(disks[drive][i]);
+ }
+- platform_device_unregister(&floppy_device[drive]);
++ if (registered[drive])
++ platform_device_unregister(&floppy_device[drive]);
+ }
+ for (i = 0; i < ARRAY_SIZE(floppy_type); i++) {
+ if (disks[drive][i])
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index 7bf4686af774e..c00ae30fde89e 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -272,19 +272,6 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
+ blk_mq_unfreeze_queue(lo->lo_queue);
+ }
+
+-/**
+- * loop_validate_block_size() - validates the passed in block size
+- * @bsize: size to validate
+- */
+-static int
+-loop_validate_block_size(unsigned short bsize)
+-{
+- if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
+- return -EINVAL;
+-
+- return 0;
+-}
+-
+ /**
+ * loop_set_size() - sets device size and notifies userspace
+ * @lo: struct loop_device to set the size for
+@@ -1236,7 +1223,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
+ }
+
+ if (config->block_size) {
+- error = loop_validate_block_size(config->block_size);
++ error = blk_validate_block_size(config->block_size);
+ if (error)
+ goto out_unlock;
+ }
+@@ -1759,7 +1746,7 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
+ if (lo->lo_state != Lo_bound)
+ return -ENXIO;
+
+- err = loop_validate_block_size(arg);
++ err = blk_validate_block_size(arg);
+ if (err)
+ return err;
+
+@@ -2442,7 +2429,7 @@ static int loop_control_remove(int idx)
+ int ret;
+
+ if (idx < 0) {
+- pr_warn("deleting an unspecified loop device is not supported.\n");
++ pr_warn_once("deleting an unspecified loop device is not supported.\n");
+ return -EINVAL;
+ }
+
+diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
+index 1183f7872b713..577c7dba5d78d 100644
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -122,10 +122,10 @@ struct nbd_device {
+ struct work_struct remove_work;
+
+ struct list_head list;
+- struct task_struct *task_recv;
+ struct task_struct *task_setup;
+
+ unsigned long flags;
++ pid_t pid; /* pid of nbd-client, if attached */
+
+ char *backend;
+ };
+@@ -217,7 +217,7 @@ static ssize_t pid_show(struct device *dev,
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nbd_device *nbd = (struct nbd_device *)disk->private_data;
+
+- return sprintf(buf, "%d\n", task_pid_nr(nbd->task_recv));
++ return sprintf(buf, "%d\n", nbd->pid);
+ }
+
+ static const struct device_attribute pid_attr = {
+@@ -329,7 +329,7 @@ static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
+ nbd->config->bytesize = bytesize;
+ nbd->config->blksize_bits = __ffs(blksize);
+
+- if (!nbd->task_recv)
++ if (!nbd->pid)
+ return 0;
+
+ if (nbd->config->flags & NBD_FLAG_SEND_TRIM) {
+@@ -1241,7 +1241,7 @@ static void nbd_config_put(struct nbd_device *nbd)
+ if (test_and_clear_bit(NBD_RT_HAS_PID_FILE,
+ &config->runtime_flags))
+ device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
+- nbd->task_recv = NULL;
++ nbd->pid = 0;
+ if (test_and_clear_bit(NBD_RT_HAS_BACKEND_FILE,
+ &config->runtime_flags)) {
+ device_remove_file(disk_to_dev(nbd->disk), &backend_attr);
+@@ -1282,7 +1282,7 @@ static int nbd_start_device(struct nbd_device *nbd)
+ int num_connections = config->num_connections;
+ int error = 0, i;
+
+- if (nbd->task_recv)
++ if (nbd->pid)
+ return -EBUSY;
+ if (!config->socks)
+ return -EINVAL;
+@@ -1301,7 +1301,7 @@ static int nbd_start_device(struct nbd_device *nbd)
+ }
+
+ blk_mq_update_nr_hw_queues(&nbd->tag_set, config->num_connections);
+- nbd->task_recv = current;
++ nbd->pid = task_pid_nr(current);
+
+ nbd_parse_flags(nbd);
+
+@@ -1557,8 +1557,8 @@ static int nbd_dbg_tasks_show(struct seq_file *s, void *unused)
+ {
+ struct nbd_device *nbd = s->private;
+
+- if (nbd->task_recv)
+- seq_printf(s, "recv: %d\n", task_pid_nr(nbd->task_recv));
++ if (nbd->pid)
++ seq_printf(s, "recv: %d\n", nbd->pid);
+
+ return 0;
+ }
+@@ -1749,11 +1749,11 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
+ disk->major = NBD_MAJOR;
+
+ /* Too big first_minor can cause duplicate creation of
+- * sysfs files/links, since first_minor will be truncated to
+- * byte in __device_add_disk().
++ * sysfs files/links, since index << part_shift might overflow, or
++ * MKDEV() expect that the max bits of first_minor is 20.
+ */
+ disk->first_minor = index << part_shift;
+- if (disk->first_minor > 0xff) {
++ if (disk->first_minor < index || disk->first_minor > MINORMASK) {
+ err = -EINVAL;
+ goto out_free_idr;
+ }
+@@ -2135,7 +2135,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
+ mutex_lock(&nbd->config_lock);
+ config = nbd->config;
+ if (!test_bit(NBD_RT_BOUND, &config->runtime_flags) ||
+- !nbd->task_recv) {
++ !nbd->pid) {
+ dev_err(nbd_to_dev(nbd),
+ "not configured, cannot reconfigure\n");
+ ret = -EINVAL;
+diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
+index 72902104f1112..4dbb71230d6e7 100644
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -1511,9 +1511,12 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+ 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:
+@@ -1529,6 +1532,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+ unsigned long id;
+ unsigned int op;
+
++ eoiflag = 0;
++
+ RING_COPY_RESPONSE(&rinfo->ring, i, &bret);
+ id = bret.id;
+
+@@ -1645,6 +1650,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+
+ spin_unlock_irqrestore(&rinfo->ring_lock, flags);
+
++ xen_irq_lateeoi(irq, eoiflag);
++
+ return IRQ_HANDLED;
+
+ err:
+@@ -1652,6 +1659,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+
+ 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;
+ }
+@@ -1691,8 +1700,8 @@ static int setup_blkring(struct xenbus_device *dev,
+ 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");
+diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
+index fcaf2750f68f7..6383c81ac5b37 100644
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -910,7 +910,7 @@ static ssize_t read_block_state(struct file *file, char __user *buf,
+ 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;
+ }
+diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
+index e9d91d7c0db48..9ba22b13b4fa0 100644
+--- a/drivers/bluetooth/btmtkuart.c
++++ b/drivers/bluetooth/btmtkuart.c
+@@ -158,8 +158,10 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
+ 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 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
+ 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 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
+ 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 */
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index 60d2fce59a71d..79d0db542da3b 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -433,6 +433,10 @@ static const struct usb_device_id blacklist_table[] = {
+ { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
+ { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
+
++ /* Additional Realtek 8761B Bluetooth devices */
++ { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
++
+ /* Additional Realtek 8761BU Bluetooth devices */
+ { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
+diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
+index 0c0dedece59c5..d49a39d17d7dc 100644
+--- a/drivers/bluetooth/hci_h5.c
++++ b/drivers/bluetooth/hci_h5.c
+@@ -587,9 +587,11 @@ static int h5_recv(struct hci_uart *hu, const void *data, int count)
+ count -= processed;
+ }
+
+- pm_runtime_get(&hu->serdev->dev);
+- pm_runtime_mark_last_busy(&hu->serdev->dev);
+- pm_runtime_put_autosuspend(&hu->serdev->dev);
++ if (hu->serdev) {
++ pm_runtime_get(&hu->serdev->dev);
++ pm_runtime_mark_last_busy(&hu->serdev->dev);
++ pm_runtime_put_autosuspend(&hu->serdev->dev);
++ }
+
+ return 0;
+ }
+@@ -846,6 +848,8 @@ static int h5_serdev_probe(struct serdev_device *serdev)
+ h5->vnd = data->vnd;
+ }
+
++ if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
++ set_bit(H5_WAKEUP_DISABLE, &h5->flags);
+
+ h5->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(h5->enable_gpio))
+@@ -860,9 +864,6 @@ static int h5_serdev_probe(struct serdev_device *serdev)
+ if (err)
+ return err;
+
+- if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
+- set_bit(H5_WAKEUP_DISABLE, &h5->flags);
+-
+ return 0;
+ }
+
+@@ -962,11 +963,13 @@ static void h5_btrtl_open(struct h5 *h5)
+ serdev_device_set_parity(h5->hu->serdev, SERDEV_PARITY_EVEN);
+ serdev_device_set_baudrate(h5->hu->serdev, 115200);
+
+- pm_runtime_set_active(&h5->hu->serdev->dev);
+- pm_runtime_use_autosuspend(&h5->hu->serdev->dev);
+- pm_runtime_set_autosuspend_delay(&h5->hu->serdev->dev,
+- SUSPEND_TIMEOUT_MS);
+- pm_runtime_enable(&h5->hu->serdev->dev);
++ if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
++ pm_runtime_set_active(&h5->hu->serdev->dev);
++ pm_runtime_use_autosuspend(&h5->hu->serdev->dev);
++ pm_runtime_set_autosuspend_delay(&h5->hu->serdev->dev,
++ SUSPEND_TIMEOUT_MS);
++ pm_runtime_enable(&h5->hu->serdev->dev);
++ }
+
+ /* The controller needs up to 500ms to wakeup */
+ gpiod_set_value_cansleep(h5->enable_gpio, 1);
+@@ -976,7 +979,8 @@ static void h5_btrtl_open(struct h5 *h5)
+
+ static void h5_btrtl_close(struct h5 *h5)
+ {
+- pm_runtime_disable(&h5->hu->serdev->dev);
++ if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags))
++ pm_runtime_disable(&h5->hu->serdev->dev);
+
+ gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
+ gpiod_set_value_cansleep(h5->enable_gpio, 0);
+diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
+index fb99e3727155b..547e6e769546a 100644
+--- a/drivers/bus/mhi/core/pm.c
++++ b/drivers/bus/mhi/core/pm.c
+@@ -881,7 +881,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl)
+ }
+ EXPORT_SYMBOL_GPL(mhi_pm_suspend);
+
+-int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
++static int __mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force)
+ {
+ struct mhi_chan *itr, *tmp;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+@@ -898,8 +898,12 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
+ if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
+ return -EIO;
+
+- if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3)
+- return -EINVAL;
++ if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) {
++ dev_warn(dev, "Resuming from non M3 state (%s)\n",
++ TO_MHI_STATE_STR(mhi_get_mhi_state(mhi_cntrl)));
++ if (!force)
++ return -EINVAL;
++ }
+
+ /* Notify clients about exiting LPM */
+ list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) {
+@@ -940,8 +944,19 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
+
+ return 0;
+ }
++
++int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
++{
++ return __mhi_pm_resume(mhi_cntrl, false);
++}
+ EXPORT_SYMBOL_GPL(mhi_pm_resume);
+
++int mhi_pm_resume_force(struct mhi_controller *mhi_cntrl)
++{
++ return __mhi_pm_resume(mhi_cntrl, true);
++}
++EXPORT_SYMBOL_GPL(mhi_pm_resume_force);
++
+ int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl)
+ {
+ int ret;
+diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c
+index 59a4896a80309..4c577a7317091 100644
+--- a/drivers/bus/mhi/pci_generic.c
++++ b/drivers/bus/mhi/pci_generic.c
+@@ -20,7 +20,7 @@
+
+ #define MHI_PCI_DEFAULT_BAR_NUM 0
+
+-#define MHI_POST_RESET_DELAY_MS 500
++#define MHI_POST_RESET_DELAY_MS 2000
+
+ #define HEALTH_CHECK_PERIOD (HZ * 2)
+
+diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
+index 6a8b7fb5be58d..ebf22929ff328 100644
+--- a/drivers/bus/ti-sysc.c
++++ b/drivers/bus/ti-sysc.c
+@@ -6,6 +6,7 @@
+ #include <linux/io.h>
+ #include <linux/clk.h>
+ #include <linux/clkdev.h>
++#include <linux/cpu_pm.h>
+ #include <linux/delay.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
+@@ -17,6 +18,7 @@
+ #include <linux/of_platform.h>
+ #include <linux/slab.h>
+ #include <linux/sys_soc.h>
++#include <linux/timekeeping.h>
+ #include <linux/iopoll.h>
+
+ #include <linux/platform_data/ti-sysc.h>
+@@ -51,11 +53,18 @@ struct sysc_address {
+ struct list_head node;
+ };
+
++struct sysc_module {
++ struct sysc *ddata;
++ struct list_head node;
++};
++
+ struct sysc_soc_info {
+ unsigned long general_purpose:1;
+ enum sysc_soc soc;
+- struct mutex list_lock; /* disabled modules list lock */
++ struct mutex list_lock; /* disabled and restored modules list lock */
+ struct list_head disabled_modules;
++ struct list_head restored_modules;
++ struct notifier_block nb;
+ };
+
+ enum sysc_clocks {
+@@ -223,37 +232,77 @@ static u32 sysc_read_sysstatus(struct sysc *ddata)
+ return sysc_read(ddata, offset);
+ }
+
+-/* Poll on reset status */
+-static int sysc_wait_softreset(struct sysc *ddata)
++static int sysc_poll_reset_sysstatus(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);
++ int error, retries;
++ u32 syss_done, rstval;
+
+ if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
+ syss_done = 0;
+ else
+ syss_done = ddata->cfg.syss_mask;
+
+- if (syss_offset >= 0) {
++ if (likely(!timekeeping_suspended)) {
+ error = readx_poll_timeout_atomic(sysc_read_sysstatus, ddata,
+ rstval, (rstval & ddata->cfg.syss_mask) ==
+ syss_done, 100, MAX_MODULE_SOFTRESET_WAIT);
++ } else {
++ retries = MAX_MODULE_SOFTRESET_WAIT;
++ while (retries--) {
++ rstval = sysc_read_sysstatus(ddata);
++ if ((rstval & ddata->cfg.syss_mask) == syss_done)
++ return 0;
++ udelay(2); /* Account for udelay flakeyness */
++ }
++ error = -ETIMEDOUT;
++ }
++
++ return error;
++}
++
++static int sysc_poll_reset_sysconfig(struct sysc *ddata)
++{
++ int error, retries;
++ u32 sysc_mask, rstval;
++
++ sysc_mask = BIT(ddata->cap->regbits->srst_shift);
+
+- } else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
++ if (likely(!timekeeping_suspended)) {
+ error = readx_poll_timeout_atomic(sysc_read_sysconfig, ddata,
+ rstval, !(rstval & sysc_mask),
+ 100, MAX_MODULE_SOFTRESET_WAIT);
++ } else {
++ retries = MAX_MODULE_SOFTRESET_WAIT;
++ while (retries--) {
++ rstval = sysc_read_sysconfig(ddata);
++ if (!(rstval & sysc_mask))
++ return 0;
++ udelay(2); /* Account for udelay flakeyness */
++ }
++ error = -ETIMEDOUT;
+ }
+
+ return error;
+ }
+
++/* Poll on reset status */
++static int sysc_wait_softreset(struct sysc *ddata)
++{
++ int syss_offset, error = 0;
++
++ if (ddata->cap->regbits->srst_shift < 0)
++ return 0;
++
++ syss_offset = ddata->offsets[SYSC_SYSSTATUS];
++
++ if (syss_offset >= 0)
++ error = sysc_poll_reset_sysstatus(ddata);
++ else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS)
++ error = sysc_poll_reset_sysconfig(ddata);
++
++ return error;
++}
++
+ static int sysc_add_named_clock_from_child(struct sysc *ddata,
+ const char *name,
+ const char *optfck_name)
+@@ -1518,7 +1567,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
+ 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_REINIT_ON_RESUME),
++ SYSC_QUIRK_REINIT_ON_CTX_LOST),
+ SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
+ SYSC_MODULE_QUIRK_WDT),
+ /* PRUSS on am3, am4 and am5 */
+@@ -2401,6 +2450,78 @@ static struct dev_pm_domain sysc_child_pm_domain = {
+ }
+ };
+
++/* Caller needs to take list_lock if ever used outside of cpu_pm */
++static void sysc_reinit_modules(struct sysc_soc_info *soc)
++{
++ struct sysc_module *module;
++ struct list_head *pos;
++ struct sysc *ddata;
++
++ list_for_each(pos, &sysc_soc->restored_modules) {
++ module = list_entry(pos, struct sysc_module, node);
++ ddata = module->ddata;
++ sysc_reinit_module(ddata, ddata->enabled);
++ }
++}
++
++/**
++ * sysc_context_notifier - optionally reset and restore module after idle
++ * @nb: notifier block
++ * @cmd: unused
++ * @v: unused
++ *
++ * Some interconnect target modules need to be restored, or reset and restored
++ * on CPU_PM CPU_PM_CLUSTER_EXIT notifier. This is needed at least for am335x
++ * OTG and GPMC target modules even if the modules are unused.
++ */
++static int sysc_context_notifier(struct notifier_block *nb, unsigned long cmd,
++ void *v)
++{
++ struct sysc_soc_info *soc;
++
++ soc = container_of(nb, struct sysc_soc_info, nb);
++
++ switch (cmd) {
++ case CPU_CLUSTER_PM_ENTER:
++ break;
++ case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */
++ break;
++ case CPU_CLUSTER_PM_EXIT:
++ sysc_reinit_modules(soc);
++ break;
++ }
++
++ return NOTIFY_OK;
++}
++
++/**
++ * sysc_add_restored - optionally add reset and restore quirk hanlling
++ * @ddata: device data
++ */
++static void sysc_add_restored(struct sysc *ddata)
++{
++ struct sysc_module *restored_module;
++
++ restored_module = kzalloc(sizeof(*restored_module), GFP_KERNEL);
++ if (!restored_module)
++ return;
++
++ restored_module->ddata = ddata;
++
++ mutex_lock(&sysc_soc->list_lock);
++
++ list_add(&restored_module->node, &sysc_soc->restored_modules);
++
++ if (sysc_soc->nb.notifier_call)
++ goto out_unlock;
++
++ sysc_soc->nb.notifier_call = sysc_context_notifier;
++ cpu_pm_register_notifier(&sysc_soc->nb);
++
++out_unlock:
++ mutex_unlock(&sysc_soc->list_lock);
++}
++
+ /**
+ * sysc_legacy_idle_quirk - handle children in omap_device compatible way
+ * @ddata: device driver data
+@@ -2900,12 +3021,14 @@ static int sysc_add_disabled(unsigned long base)
+ }
+
+ /*
+- * One time init to detect the booted SoC and disable unavailable features.
++ * One time init to detect the booted SoC, disable unavailable features
++ * and initialize list for optional cpu_pm notifier.
++ *
+ * Note that we initialize static data shared across all ti-sysc instances
+ * so ddata is only used for SoC type. This can be called from module_init
+ * once we no longer need to rely on platform data.
+ */
+-static int sysc_init_soc(struct sysc *ddata)
++static int sysc_init_static_data(struct sysc *ddata)
+ {
+ const struct soc_device_attribute *match;
+ struct ti_sysc_platform_data *pdata;
+@@ -2921,6 +3044,7 @@ static int sysc_init_soc(struct sysc *ddata)
+
+ mutex_init(&sysc_soc->list_lock);
+ INIT_LIST_HEAD(&sysc_soc->disabled_modules);
++ INIT_LIST_HEAD(&sysc_soc->restored_modules);
+ sysc_soc->general_purpose = true;
+
+ pdata = dev_get_platdata(ddata->dev);
+@@ -2985,15 +3109,24 @@ static int sysc_init_soc(struct sysc *ddata)
+ return 0;
+ }
+
+-static void sysc_cleanup_soc(void)
++static void sysc_cleanup_static_data(void)
+ {
++ struct sysc_module *restored_module;
+ struct sysc_address *disabled_module;
+ struct list_head *pos, *tmp;
+
+ if (!sysc_soc)
+ return;
+
++ if (sysc_soc->nb.notifier_call)
++ cpu_pm_unregister_notifier(&sysc_soc->nb);
++
+ mutex_lock(&sysc_soc->list_lock);
++ list_for_each_safe(pos, tmp, &sysc_soc->restored_modules) {
++ restored_module = list_entry(pos, struct sysc_module, node);
++ list_del(pos);
++ kfree(restored_module);
++ }
+ list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) {
+ disabled_module = list_entry(pos, struct sysc_address, node);
+ list_del(pos);
+@@ -3061,7 +3194,7 @@ static int sysc_probe(struct platform_device *pdev)
+ ddata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ddata);
+
+- error = sysc_init_soc(ddata);
++ error = sysc_init_static_data(ddata);
+ if (error)
+ return error;
+
+@@ -3159,6 +3292,9 @@ static int sysc_probe(struct platform_device *pdev)
+ pm_runtime_put(&pdev->dev);
+ }
+
++ if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_CTX_LOST)
++ sysc_add_restored(ddata);
++
+ return 0;
+
+ err:
+@@ -3240,7 +3376,7 @@ static void __exit sysc_exit(void)
+ {
+ bus_unregister_notifier(&platform_bus_type, &sysc_nb);
+ platform_driver_unregister(&sysc_driver);
+- sysc_cleanup_soc();
++ sysc_cleanup_static_data();
+ }
+ module_exit(sysc_exit);
+
+diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
+index ed3c4c42fc23b..d68d05d5d3838 100644
+--- a/drivers/char/agp/parisc-agp.c
++++ b/drivers/char/agp/parisc-agp.c
+@@ -281,7 +281,7 @@ agp_ioc_init(void __iomem *ioc_regs)
+ return 0;
+ }
+
+-static int
++static int __init
+ lba_find_capability(int cap)
+ {
+ struct _parisc_agp_info *info = &parisc_agp_info;
+@@ -366,7 +366,7 @@ fail:
+ return error;
+ }
+
+-static int
++static int __init
+ find_quicksilver(struct device *dev, void *data)
+ {
+ struct parisc_device **lba = data;
+@@ -378,7 +378,7 @@ find_quicksilver(struct device *dev, void *data)
+ return 0;
+ }
+
+-static int
++static int __init
+ parisc_agp_init(void)
+ {
+ extern struct sba_device *sba_list;
+diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c
+index 8ad7b515a51b8..6c00ea0085553 100644
+--- a/drivers/char/hw_random/mtk-rng.c
++++ b/drivers/char/hw_random/mtk-rng.c
+@@ -166,8 +166,13 @@ static int mtk_rng_runtime_resume(struct device *dev)
+ 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
+diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
+index e96cb5c4f97a3..b404cc46cbda7 100644
+--- a/drivers/char/ipmi/ipmi_msghandler.c
++++ b/drivers/char/ipmi/ipmi_msghandler.c
+@@ -191,6 +191,8 @@ struct ipmi_user {
+ 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)
+ {
+@@ -1261,7 +1263,7 @@ static void free_user(struct kref *ref)
+ 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)
+@@ -4789,7 +4791,9 @@ static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
+ 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)
+@@ -4808,7 +4812,9 @@ EXPORT_SYMBOL(ipmi_alloc_smi_msg);
+ 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)
+@@ -4826,7 +4832,7 @@ static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+
+ 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);
+ }
+@@ -5149,6 +5155,13 @@ static int ipmi_init_msghandler(void)
+
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+
++ 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;
++ }
++
+ initialized = true;
+
+ out:
+@@ -5174,6 +5187,8 @@ static void __exit cleanup_ipmi(void)
+ int count;
+
+ if (initialized) {
++ destroy_workqueue(remove_work_wq);
++
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &panic_block);
+
+diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
+index e4ff3b50de7f3..883b4a3410122 100644
+--- a/drivers/char/ipmi/ipmi_watchdog.c
++++ b/drivers/char/ipmi/ipmi_watchdog.c
+@@ -342,13 +342,17 @@ static atomic_t msg_tofree = ATOMIC_INIT(0);
+ 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
+@@ -434,8 +438,10 @@ static int _ipmi_set_timeout(int do_heartbeat)
+ 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);
+
+@@ -497,7 +503,7 @@ static void panic_halt_ipmi_heartbeat(void)
+ msg.cmd = IPMI_WDOG_RESET_TIMER;
+ msg.data = NULL;
+ msg.data_len = 0;
+- atomic_inc(&panic_done_count);
++ atomic_add(2, &panic_done_count);
+ rv = ipmi_request_supply_msgs(watchdog_user,
+ (struct ipmi_addr *) &addr,
+ 0,
+@@ -507,7 +513,7 @@ static void panic_halt_ipmi_heartbeat(void)
+ &panic_halt_heartbeat_recv_msg,
+ 1);
+ if (rv)
+- atomic_dec(&panic_done_count);
++ atomic_sub(2, &panic_done_count);
+ }
+
+ static struct ipmi_smi_msg panic_halt_smi_msg = {
+@@ -531,12 +537,12 @@ static void panic_halt_ipmi_set_timeout(void)
+ /* Wait for the messages to be free. */
+ while (atomic_read(&panic_done_count) != 0)
+ ipmi_poll_interface(watchdog_user);
+- atomic_inc(&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_dec(&panic_done_count);
++ atomic_sub(2, &panic_done_count);
+ pr_warn("Unable to extend the watchdog timeout\n");
+ } else {
+ if (send_heartbeat_now)
+@@ -580,6 +586,7 @@ restart:
+ &recv_msg,
+ 1);
+ if (rv) {
++ atomic_set(&msg_tofree, 0);
+ pr_warn("heartbeat send failure: %d\n", rv);
+ return rv;
+ }
+diff --git a/drivers/char/ipmi/kcs_bmc_serio.c b/drivers/char/ipmi/kcs_bmc_serio.c
+index 7948cabde50b4..7e2067628a6ce 100644
+--- a/drivers/char/ipmi/kcs_bmc_serio.c
++++ b/drivers/char/ipmi/kcs_bmc_serio.c
+@@ -73,10 +73,12 @@ static int kcs_bmc_serio_add_device(struct kcs_bmc_device *kcs_bmc)
+ struct serio *port;
+
+ priv = devm_kzalloc(kcs_bmc->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
+
+ /* Use kzalloc() as the allocation is cleaned up with kfree() via serio_unregister_port() */
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+- if (!(priv && port))
++ if (!port)
+ return -ENOMEM;
+
+ port->id.type = SERIO_8042;
+diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
+index 784b8b3cb903f..97e916856cf3e 100644
+--- a/drivers/char/tpm/tpm2-space.c
++++ b/drivers/char/tpm/tpm2-space.c
+@@ -455,6 +455,9 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
+ 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;
+
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index 69579efb247b3..b2659a4c40168 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -48,6 +48,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
+ unsigned long timeout, wait_queue_head_t *queue,
+ bool check_cancel)
+ {
++ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+ unsigned long stop;
+ long rc;
+ u8 status;
+@@ -80,8 +81,8 @@ again:
+ }
+ } else {
+ do {
+- usleep_range(TPM_TIMEOUT_USECS_MIN,
+- TPM_TIMEOUT_USECS_MAX);
++ usleep_range(priv->timeout_min,
++ priv->timeout_max);
+ status = chip->ops->status(chip);
+ if ((status & mask) == mask)
+ return 0;
+@@ -945,7 +946,22 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX);
+ chip->timeout_c = msecs_to_jiffies(TIS_TIMEOUT_C_MAX);
+ chip->timeout_d = msecs_to_jiffies(TIS_TIMEOUT_D_MAX);
++ priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
++ priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
+ priv->phy_ops = phy_ops;
++
++ rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor);
++ if (rc < 0)
++ goto out_err;
++
++ priv->manufacturer_id = vendor;
++
++ if (priv->manufacturer_id == TPM_VID_ATML &&
++ !(chip->flags & TPM_CHIP_FLAG_TPM2)) {
++ priv->timeout_min = TIS_TIMEOUT_MIN_ATML;
++ priv->timeout_max = TIS_TIMEOUT_MAX_ATML;
++ }
++
+ dev_set_drvdata(&chip->dev, priv);
+
+ if (is_bsw()) {
+@@ -988,12 +1004,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ if (rc)
+ goto out_err;
+
+- rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor);
+- if (rc < 0)
+- goto out_err;
+-
+- priv->manufacturer_id = vendor;
+-
+ rc = tpm_tis_read8(priv, TPM_RID(0), &rid);
+ if (rc < 0)
+ goto out_err;
+diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
+index b2a3c6c72882d..3be24f221e32a 100644
+--- a/drivers/char/tpm/tpm_tis_core.h
++++ b/drivers/char/tpm/tpm_tis_core.h
+@@ -54,6 +54,8 @@ enum tis_defaults {
+ TIS_MEM_LEN = 0x5000,
+ TIS_SHORT_TIMEOUT = 750, /* ms */
+ TIS_LONG_TIMEOUT = 2000, /* 2 sec */
++ TIS_TIMEOUT_MIN_ATML = 14700, /* usecs */
++ TIS_TIMEOUT_MAX_ATML = 15000, /* usecs */
+ };
+
+ /* Some timeout values are needed before it is known whether the chip is
+@@ -98,6 +100,8 @@ struct tpm_tis_data {
+ wait_queue_head_t read_queue;
+ const struct tpm_tis_phy_ops *phy_ops;
+ unsigned short rng_quality;
++ unsigned int timeout_min; /* usecs */
++ unsigned int timeout_max; /* usecs */
+ };
+
+ struct tpm_tis_phy_ops {
+diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c
+index 54584b4b00d19..aaa59a00eeaef 100644
+--- a/drivers/char/tpm/tpm_tis_spi_main.c
++++ b/drivers/char/tpm/tpm_tis_spi_main.c
+@@ -267,6 +267,7 @@ static const struct spi_device_id tpm_tis_spi_id[] = {
+ { "st33htpm-spi", (unsigned long)tpm_tis_spi_probe },
+ { "slb9670", (unsigned long)tpm_tis_spi_probe },
+ { "tpm_tis_spi", (unsigned long)tpm_tis_spi_probe },
++ { "tpm_tis-spi", (unsigned long)tpm_tis_spi_probe },
+ { "cr50", (unsigned long)cr50_spi_probe },
+ {}
+ };
+diff --git a/drivers/char/xillybus/xillyusb.c b/drivers/char/xillybus/xillyusb.c
+index e7f88f35c7028..dc3551796e5ed 100644
+--- a/drivers/char/xillybus/xillyusb.c
++++ b/drivers/char/xillybus/xillyusb.c
+@@ -1912,6 +1912,7 @@ static int xillyusb_setup_base_eps(struct xillyusb_dev *xdev)
+
+ dealloc:
+ endpoint_dealloc(xdev->msg_ep); /* Also frees FIFO mem if allocated */
++ xdev->msg_ep = NULL;
+ return -ENOMEM;
+ }
+
+diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
+index a80427980bf73..04d0dd8385945 100644
+--- a/drivers/clk/at91/clk-master.c
++++ b/drivers/clk/at91/clk-master.c
+@@ -280,7 +280,7 @@ static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
+
+ else if (pres == 3)
+ pres = MASTER_PRES_MAX;
+- else
++ else if (pres)
+ pres = ffs(pres) - 1;
+
+ spin_lock_irqsave(master->lock, flags);
+@@ -309,7 +309,7 @@ static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
+ spin_unlock_irqrestore(master->lock, flags);
+
+ pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
+- if (pres == 3 && characteristics->have_div3_pres)
++ if (pres == MASTER_PRES_MAX && characteristics->have_div3_pres)
+ pres = 3;
+ else
+ pres = (1 << pres);
+@@ -610,7 +610,7 @@ static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate,
+
+ if (div == 3)
+ div = MASTER_PRES_MAX;
+- else
++ else if (div)
+ div = ffs(div) - 1;
+
+ spin_lock_irqsave(master->lock, flags);
+diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
+index 34e3ab13741ac..1f52409475e9c 100644
+--- a/drivers/clk/at91/clk-sam9x60-pll.c
++++ b/drivers/clk/at91/clk-sam9x60-pll.c
+@@ -71,8 +71,8 @@ static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,
+ struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+ struct sam9x60_frac *frac = to_sam9x60_frac(core);
+
+- return (parent_rate * (frac->mul + 1) +
+- ((u64)parent_rate * frac->frac >> 22));
++ return parent_rate * (frac->mul + 1) +
++ DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));
+ }
+
+ static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
+diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
+index 20ee9dccee787..b40035b011d0a 100644
+--- a/drivers/clk/at91/pmc.c
++++ b/drivers/clk/at91/pmc.c
+@@ -267,6 +267,11 @@ static int __init pmc_register_ops(void)
+ if (!np)
+ return -ENODEV;
+
++ if (!of_device_is_available(np)) {
++ of_node_put(np);
++ return -ENODEV;
++ }
++
+ pmcreg = device_node_to_regmap(np);
+ of_node_put(np);
+ if (IS_ERR(pmcreg))
+diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
+index cf8c079aa086a..019e712f90d6f 100644
+--- a/drivers/clk/at91/sama7g5.c
++++ b/drivers/clk/at91/sama7g5.c
+@@ -982,16 +982,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
+ }
+
+ parent_names[0] = "cpupll_divpmcck";
+- hw = at91_clk_register_master_pres(regmap, "cpuck", 1, parent_names,
+- &mck0_layout, &mck0_characteristics,
+- &pmc_mck0_lock,
+- CLK_SET_RATE_PARENT, 0);
+- if (IS_ERR(hw))
+- goto err_free;
+-
+- sama7g5_pmc->chws[PMC_CPU] = hw;
+-
+- hw = at91_clk_register_master_div(regmap, "mck0", "cpuck",
++ hw = at91_clk_register_master_div(regmap, "mck0", "cpupll_divpmcck",
+ &mck0_layout, &mck0_characteristics,
+ &pmc_mck0_lock, 0);
+ if (IS_ERR(hw))
+diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c
+index bc3be5f3eae15..24dab2312bc6f 100644
+--- a/drivers/clk/clk-ast2600.c
++++ b/drivers/clk/clk-ast2600.c
+@@ -51,6 +51,8 @@ static DEFINE_SPINLOCK(aspeed_g6_clk_lock);
+ 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:
+@@ -191,9 +193,8 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val)
+ static struct clk_hw *ast2600_calc_apll(const char *name, u32 val)
+ {
+ unsigned int mult, div;
+- u32 chip_id = readl(scu_g6_base + ASPEED_G6_SILICON_REV);
+
+- if (((chip_id & CHIP_REVISION_ID) >> 16) >= 2) {
++ if (soc_rev >= 2) {
+ if (val & BIT(24)) {
+ /* Pass through mode */
+ mult = div = 1;
+@@ -707,7 +708,7 @@ static const u32 ast2600_a1_axi_ahb200_tbl[] = {
+ static void __init aspeed_g6_cc(struct regmap *map)
+ {
+ struct clk_hw *hw;
+- u32 val, div, divbits, chip_id, axi_div, ahb_div;
++ u32 val, div, divbits, axi_div, ahb_div;
+
+ clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000);
+
+@@ -738,8 +739,7 @@ static void __init aspeed_g6_cc(struct regmap *map)
+ axi_div = 2;
+
+ divbits = (val >> 11) & 0x3;
+- regmap_read(map, ASPEED_G6_SILICON_REV, &chip_id);
+- if (chip_id & BIT(16)) {
++ if (soc_rev >= 1) {
+ if (!divbits) {
+ ahb_div = ast2600_a1_axi_ahb200_tbl[(val >> 8) & 0x3];
+ if (val & BIT(16))
+@@ -784,6 +784,8 @@ static void __init aspeed_g6_cc_init(struct device_node *np)
+ 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)
+diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
+index 65508eb89ec99..a277fd4f2f0a6 100644
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -3415,6 +3415,14 @@ static int __clk_core_init(struct clk_core *core)
+
+ 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;
+@@ -3579,8 +3587,10 @@ static int __clk_core_init(struct clk_core *core)
+ out:
+ clk_pm_runtime_put(core);
+ unlock:
+- if (ret)
++ if (ret) {
+ hlist_del_init(&core->child_node);
++ core->hw->core = NULL;
++ }
+
+ clk_prepare_unlock();
+
+@@ -3844,7 +3854,6 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
+ 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)
+@@ -3862,7 +3871,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
+ 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)
+diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
+index 5dbb6a9377324..206e4c43f68f8 100644
+--- a/drivers/clk/imx/clk-imx6ul.c
++++ b/drivers/clk/imx/clk-imx6ul.c
+@@ -161,7 +161,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
+ 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 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
+ 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));
+diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c
+index d3e905cf867d7..b23758083ce52 100644
+--- a/drivers/clk/imx/clk-imx8qxp-lpcg.c
++++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c
+@@ -370,7 +370,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
+ .probe = imx8qxp_lpcg_clk_probe,
+ };
+
+-builtin_platform_driver(imx8qxp_lpcg_clk_driver);
++module_platform_driver(imx8qxp_lpcg_clk_driver);
+
+ MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
+ MODULE_DESCRIPTION("NXP i.MX8QXP LPCG clock driver");
+diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
+index c53a688d8ccca..40a2efb1329be 100644
+--- a/drivers/clk/imx/clk-imx8qxp.c
++++ b/drivers/clk/imx/clk-imx8qxp.c
+@@ -308,7 +308,7 @@ static struct platform_driver imx8qxp_clk_driver = {
+ },
+ .probe = imx8qxp_clk_probe,
+ };
+-builtin_platform_driver(imx8qxp_clk_driver);
++module_platform_driver(imx8qxp_clk_driver);
+
+ MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
+ MODULE_DESCRIPTION("NXP i.MX8QXP clock driver");
+diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
+index 266c7595d3302..af31633a8862e 100644
+--- a/drivers/clk/ingenic/cgu.c
++++ b/drivers/clk/ingenic/cgu.c
+@@ -453,15 +453,15 @@ ingenic_clk_calc_div(struct clk_hw *hw,
+ }
+
+ /* 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;
+diff --git a/drivers/clk/mvebu/ap-cpu-clk.c b/drivers/clk/mvebu/ap-cpu-clk.c
+index 08ba59ec3fb17..71bdd7c3ff034 100644
+--- a/drivers/clk/mvebu/ap-cpu-clk.c
++++ b/drivers/clk/mvebu/ap-cpu-clk.c
+@@ -256,12 +256,15 @@ static int ap_cpu_clock_probe(struct platform_device *pdev)
+ 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 @@ static int ap_cpu_clock_probe(struct platform_device *pdev)
+ 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 @@ static int ap_cpu_clock_probe(struct platform_device *pdev)
+ 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 @@ static int ap_cpu_clock_probe(struct platform_device *pdev)
+ 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;
+ }
+
+diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
+index eaedcceb766f9..8f65b9bdafce4 100644
+--- a/drivers/clk/qcom/clk-alpha-pll.c
++++ b/drivers/clk/qcom/clk-alpha-pll.c
+@@ -1429,6 +1429,15 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
+ void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+ const struct alpha_pll_config *config)
+ {
++ /*
++ * If the bootloader left the PLL enabled it's likely that there are
++ * RCGs that will lock up if we disable the PLL below.
++ */
++ if (trion_pll_is_enabled(pll, regmap)) {
++ pr_debug("Trion PLL is already enabled, skipping configuration\n");
++ return;
++ }
++
+ clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
+ regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
+ clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
+diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c
+index b2d00b4519634..45d9cca28064f 100644
+--- a/drivers/clk/qcom/clk-regmap-mux.c
++++ b/drivers/clk/qcom/clk-regmap-mux.c
+@@ -28,7 +28,7 @@ static u8 mux_get_parent(struct clk_hw *hw)
+ 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;
+ }
+diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
+index 60d2a78d13950..2af04fc4abfa9 100644
+--- a/drivers/clk/qcom/common.c
++++ b/drivers/clk/qcom/common.c
+@@ -69,6 +69,18 @@ int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
+ }
+ 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)
+ {
+diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
+index bb39a7e106d8a..9c8f7b798d9fc 100644
+--- a/drivers/clk/qcom/common.h
++++ b/drivers/clk/qcom/common.h
+@@ -49,6 +49,8 @@ extern void
+ 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);
+diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
+index 3c3a7ff045621..9b1674b28d45d 100644
+--- a/drivers/clk/qcom/gcc-msm8996.c
++++ b/drivers/clk/qcom/gcc-msm8996.c
+@@ -2937,20 +2937,6 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
+ },
+ };
+
+-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 = {
+@@ -3474,7 +3460,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
+ [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,
+diff --git a/drivers/clk/qcom/gcc-sm6125.c b/drivers/clk/qcom/gcc-sm6125.c
+index 543cfab7561f9..431b55bb0d2f7 100644
+--- a/drivers/clk/qcom/gcc-sm6125.c
++++ b/drivers/clk/qcom/gcc-sm6125.c
+@@ -1121,7 +1121,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+- .ops = &clk_rcg2_ops,
++ .ops = &clk_rcg2_floor_ops,
+ },
+ };
+
+@@ -1143,7 +1143,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+- .ops = &clk_rcg2_floor_ops,
++ .ops = &clk_rcg2_ops,
+ },
+ };
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+index f32366d9336e7..bd9a8782fec3d 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
++++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+@@ -1464,7 +1464,7 @@ static void __init sun4i_ccu_init(struct device_node *node,
+ val &= ~GENMASK(7, 6);
+ writel(val | (2 << 6), reg + SUN4I_AHB_REG);
+
+- sunxi_ccu_probe(node, reg, desc);
++ of_sunxi_ccu_probe(node, reg, desc);
+ }
+
+ static void __init sun4i_a10_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+index a56142b909938..6f2a589705561 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
+@@ -196,7 +196,7 @@ static int sun50i_a100_r_ccu_probe(struct platform_device *pdev)
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_r_ccu_desc);
++ return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_r_ccu_desc);
+ }
+
+ static const struct of_device_id sun50i_a100_r_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+index 81b48c73d389f..913bb08e6dee8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
+@@ -1247,7 +1247,7 @@ static int sun50i_a100_ccu_probe(struct platform_device *pdev)
+ writel(val, reg + sun50i_a100_usb2_clk_regs[i]);
+ }
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_ccu_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_ccu_desc);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+index 149cfde817cba..54f25c624f020 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+@@ -955,7 +955,7 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev)
+
+ writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a64_ccu_desc);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+index f8909a7ed5539..f30d7eb5424d8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+@@ -232,7 +232,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
+ return;
+ }
+
+- sunxi_ccu_probe(node, reg, desc);
++ of_sunxi_ccu_probe(node, reg, desc);
+ }
+
+ static void __init sun50i_h6_r_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+index bff446b782907..c0800da2fa3d7 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+@@ -1240,7 +1240,7 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev)
+ val |= BIT(24);
+ writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG);
+
+- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc);
++ return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc);
+ }
+
+ static const struct of_device_id sun50i_h6_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+index 225307305880e..22eb18079a154 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+@@ -1141,9 +1141,7 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node)
+ val |= BIT(24);
+ writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG);
+
+- i = sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
+- if (i)
+- pr_err("%pOF: probing clocks fails: %d\n", node, i);
++ of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
+ }
+
+ CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu",
+diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c
+index b78e9b507c1c6..1f4bc0e773a7e 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun5i.c
++++ b/drivers/clk/sunxi-ng/ccu-sun5i.c
+@@ -1012,7 +1012,7 @@ static void __init sun5i_ccu_init(struct device_node *node,
+ val &= ~GENMASK(7, 6);
+ writel(val | (2 << 6), reg + SUN5I_AHB_REG);
+
+- sunxi_ccu_probe(node, reg, desc);
++ of_sunxi_ccu_probe(node, reg, desc);
+ }
+
+ static void __init sun5i_a10s_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+index 9b40d53266a3f..3df5c0b415804 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
++++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+@@ -1257,7 +1257,7 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
+ val |= 0x3 << 12;
+ writel(val, reg + SUN6I_A31_AHB1_REG);
+
+- sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
++ of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
+
+ ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
+ &sun6i_a31_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+index 103aa504f6c8a..577bb235d6584 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+@@ -745,7 +745,7 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node)
+ val &= ~BIT(16);
+ writel(val, reg + SUN8I_A23_PLL_MIPI_REG);
+
+- sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
++ of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
+ }
+ CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu",
+ sun8i_a23_ccu_setup);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+index 91838cd110377..8f65cd03f5acc 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+@@ -805,7 +805,7 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
+ val &= ~BIT(16);
+ writel(val, reg + SUN8I_A33_PLL_MIPI_REG);
+
+- sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
++ of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
+
+ /* Gate then ungate PLL CPU after any rate changes */
+ ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+index 2b434521c5ccf..c2ddcd2ddab4e 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+@@ -906,7 +906,7 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev)
+ sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C0CPUX_REG);
+ sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C1CPUX_REG);
+
+- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_a83t_ccu_desc);
++ return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a83t_ccu_desc);
+ }
+
+ static const struct of_device_id sun8i_a83t_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+index 524f33275bc73..4b94b6041b271 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+@@ -342,7 +342,7 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
+ goto err_disable_mod_clk;
+ }
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg, ccu_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
+ if (ret)
+ goto err_assert_reset;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+index 7e629a4493afd..d2fc2903787d8 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+@@ -1154,7 +1154,7 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
+ val &= ~GENMASK(19, 16);
+ writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
+
+- sunxi_ccu_probe(node, reg, desc);
++ of_sunxi_ccu_probe(node, reg, desc);
+
+ /* Gate then ungate PLL CPU after any rate changes */
+ ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+index 4c8c491b87c27..9e754d1f754a1 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+@@ -265,7 +265,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
+ return;
+ }
+
+- sunxi_ccu_probe(node, reg, desc);
++ of_sunxi_ccu_probe(node, reg, desc);
+ }
+
+ static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+index 84153418453f4..002e0c3a04dbe 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+@@ -1346,7 +1346,7 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev)
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_r40_ccu_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_r40_ccu_desc);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+index f49724a22540e..ce150f83ab54e 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
++++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+@@ -822,7 +822,7 @@ static void __init sun8i_v3_v3s_ccu_init(struct device_node *node,
+ val &= ~GENMASK(19, 16);
+ writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG);
+
+- sunxi_ccu_probe(node, reg, ccu_desc);
++ of_sunxi_ccu_probe(node, reg, ccu_desc);
+ }
+
+ static void __init sun8i_v3s_ccu_setup(struct device_node *node)
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+index 6616e8114f623..261e64416f26a 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
+@@ -246,8 +246,7 @@ static int sun9i_a80_de_clk_probe(struct platform_device *pdev)
+ goto err_disable_clk;
+ }
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
+- &sun9i_a80_de_clk_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_de_clk_desc);
+ if (ret)
+ goto err_assert_reset;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+index 4b4a507d04edf..596243b3e0fa3 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+@@ -117,8 +117,7 @@ static int sun9i_a80_usb_clk_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+- ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
+- &sun9i_a80_usb_clk_desc);
++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_usb_clk_desc);
+ if (ret)
+ goto err_disable_clk;
+
+diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+index ef29582676f6e..97aaed0e68500 100644
+--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+@@ -1231,7 +1231,7 @@ static int sun9i_a80_ccu_probe(struct platform_device *pdev)
+ sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C0CPUX_REG);
+ sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C1CPUX_REG);
+
+- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun9i_a80_ccu_desc);
++ return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_ccu_desc);
+ }
+
+ static const struct of_device_id sun9i_a80_ccu_ids[] = {
+diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+index 7ecc3a5a5b5e1..61ad7ee91c114 100644
+--- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
++++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+@@ -538,7 +538,7 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
+ val &= ~GENMASK(19, 16);
+ writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG);
+
+- sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
++ of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
+
+ /* Gate then ungate PLL CPU after any rate changes */
+ ccu_pll_notifier_register(&suniv_pll_cpu_nb);
+diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
+index 2e20e650b6c01..88cb569e58358 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.c
++++ b/drivers/clk/sunxi-ng/ccu_common.c
+@@ -7,6 +7,7 @@
+
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
++#include <linux/device.h>
+ #include <linux/iopoll.h>
+ #include <linux/slab.h>
+
+@@ -14,6 +15,11 @@
+ #include "ccu_gate.h"
+ #include "ccu_reset.h"
+
++struct sunxi_ccu {
++ const struct sunxi_ccu_desc *desc;
++ struct ccu_reset reset;
++};
++
+ static DEFINE_SPINLOCK(ccu_lock);
+
+ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
+@@ -79,12 +85,15 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
+ &pll_nb->clk_nb);
+ }
+
+-int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+- const struct sunxi_ccu_desc *desc)
++static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
++ struct device_node *node, void __iomem *reg,
++ const struct sunxi_ccu_desc *desc)
+ {
+ struct ccu_reset *reset;
+ int i, ret;
+
++ ccu->desc = desc;
++
+ for (i = 0; i < desc->num_ccu_clks; i++) {
+ struct ccu_common *cclk = desc->ccu_clks[i];
+
+@@ -103,7 +112,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+ continue;
+
+ name = hw->init->name;
+- ret = of_clk_hw_register(node, hw);
++ if (dev)
++ ret = clk_hw_register(dev, hw);
++ else
++ ret = of_clk_hw_register(node, hw);
+ if (ret) {
+ pr_err("Couldn't register clock %d - %s\n", i, name);
+ goto err_clk_unreg;
+@@ -115,15 +127,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+ if (ret)
+ goto err_clk_unreg;
+
+- reset = kzalloc(sizeof(*reset), GFP_KERNEL);
+- if (!reset) {
+- ret = -ENOMEM;
+- goto err_alloc_reset;
+- }
+-
++ reset = &ccu->reset;
+ reset->rcdev.of_node = node;
+ reset->rcdev.ops = &ccu_reset_ops;
+- reset->rcdev.owner = THIS_MODULE;
++ reset->rcdev.owner = dev ? dev->driver->owner : THIS_MODULE;
+ reset->rcdev.nr_resets = desc->num_resets;
+ reset->base = reg;
+ reset->lock = &ccu_lock;
+@@ -131,13 +138,11 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+
+ ret = reset_controller_register(&reset->rcdev);
+ if (ret)
+- goto err_of_clk_unreg;
++ goto err_del_provider;
+
+ return 0;
+
+-err_of_clk_unreg:
+- kfree(reset);
+-err_alloc_reset:
++err_del_provider:
+ of_clk_del_provider(node);
+ err_clk_unreg:
+ while (--i >= 0) {
+@@ -149,3 +154,59 @@ err_clk_unreg:
+ }
+ return ret;
+ }
++
++static void devm_sunxi_ccu_release(struct device *dev, void *res)
++{
++ struct sunxi_ccu *ccu = res;
++ const struct sunxi_ccu_desc *desc = ccu->desc;
++ int i;
++
++ reset_controller_unregister(&ccu->reset.rcdev);
++ of_clk_del_provider(dev->of_node);
++
++ for (i = 0; i < desc->hw_clks->num; i++) {
++ struct clk_hw *hw = desc->hw_clks->hws[i];
++
++ if (!hw)
++ continue;
++ clk_hw_unregister(hw);
++ }
++}
++
++int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
++ const struct sunxi_ccu_desc *desc)
++{
++ struct sunxi_ccu *ccu;
++ int ret;
++
++ ccu = devres_alloc(devm_sunxi_ccu_release, sizeof(*ccu), GFP_KERNEL);
++ if (!ccu)
++ return -ENOMEM;
++
++ ret = sunxi_ccu_probe(ccu, dev, dev->of_node, reg, desc);
++ if (ret) {
++ devres_free(ccu);
++ return ret;
++ }
++
++ devres_add(dev, ccu);
++
++ return 0;
++}
++
++void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
++ const struct sunxi_ccu_desc *desc)
++{
++ struct sunxi_ccu *ccu;
++ int ret;
++
++ ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
++ if (!ccu)
++ return;
++
++ ret = sunxi_ccu_probe(ccu, NULL, node, reg, desc);
++ if (ret) {
++ pr_err("%pOF: probing clocks failed: %d\n", node, ret);
++ kfree(ccu);
++ }
++}
+diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
+index 04e7a12200a21..98a1834b58bb4 100644
+--- a/drivers/clk/sunxi-ng/ccu_common.h
++++ b/drivers/clk/sunxi-ng/ccu_common.h
+@@ -63,7 +63,9 @@ struct ccu_pll_nb {
+
+ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb);
+
+-int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
+- const struct sunxi_ccu_desc *desc);
++int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
++ const struct sunxi_ccu_desc *desc);
++void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
++ const struct sunxi_ccu_desc *desc);
+
+ #endif /* _COMMON_H_ */
+diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
+index 0f5e3983951a8..08f8cb944a2ac 100644
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -24,6 +24,7 @@ config I8253_LOCK
+
+ config OMAP_DM_TIMER
+ bool
++ select TIMER_OF
+
+ config CLKBLD_I8253
+ def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK
+diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
+index 3819ef5b70989..3245eb0c602d2 100644
+--- a/drivers/clocksource/dw_apb_timer_of.c
++++ b/drivers/clocksource/dw_apb_timer_of.c
+@@ -47,7 +47,7 @@ static int __init timer_get_base_and_rate(struct device_node *np,
+ pr_warn("pclk for %pOFn is present, but could not be activated\n",
+ np);
+
+- if (!of_property_read_u32(np, "clock-freq", rate) &&
++ if (!of_property_read_u32(np, "clock-freq", rate) ||
+ !of_property_read_u32(np, "clock-frequency", rate))
+ return 0;
+
+diff --git a/drivers/comedi/drivers/dt9812.c b/drivers/comedi/drivers/dt9812.c
+index 634f57730c1e0..704b04d2980d3 100644
+--- a/drivers/comedi/drivers/dt9812.c
++++ b/drivers/comedi/drivers/dt9812.c
+@@ -32,6 +32,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/errno.h>
++#include <linux/slab.h>
+ #include <linux/uaccess.h>
+
+ #include "../comedi_usb.h"
+@@ -237,22 +238,42 @@ static int dt9812_read_info(struct comedi_device *dev,
+ {
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct dt9812_private *devpriv = dev->private;
+- struct dt9812_usb_cmd cmd;
++ struct dt9812_usb_cmd *cmd;
++ size_t tbuf_size;
+ int count, ret;
++ void *tbuf;
+
+- cmd.cmd = cpu_to_le32(DT9812_R_FLASH_DATA);
+- cmd.u.flash_data_info.address =
++ tbuf_size = max(sizeof(*cmd), buf_size);
++
++ tbuf = kzalloc(tbuf_size, GFP_KERNEL);
++ if (!tbuf)
++ return -ENOMEM;
++
++ cmd = tbuf;
++
++ cmd->cmd = cpu_to_le32(DT9812_R_FLASH_DATA);
++ cmd->u.flash_data_info.address =
+ cpu_to_le16(DT9812_DIAGS_BOARD_INFO_ADDR + offset);
+- cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size);
++ cmd->u.flash_data_info.numbytes = cpu_to_le16(buf_size);
+
+ /* DT9812 only responds to 32 byte writes!! */
+ ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
+- &cmd, 32, &count, DT9812_USB_TIMEOUT);
++ cmd, sizeof(*cmd), &count, DT9812_USB_TIMEOUT);
+ if (ret)
+- return ret;
++ goto out;
++
++ ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
++ tbuf, buf_size, &count, DT9812_USB_TIMEOUT);
++ if (!ret) {
++ if (count == buf_size)
++ memcpy(buf, tbuf, buf_size);
++ else
++ ret = -EREMOTEIO;
++ }
++out:
++ kfree(tbuf);
+
+- return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
+- buf, buf_size, &count, DT9812_USB_TIMEOUT);
++ return ret;
+ }
+
+ static int dt9812_read_multiple_registers(struct comedi_device *dev,
+@@ -261,22 +282,42 @@ static int dt9812_read_multiple_registers(struct comedi_device *dev,
+ {
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct dt9812_private *devpriv = dev->private;
+- struct dt9812_usb_cmd cmd;
++ struct dt9812_usb_cmd *cmd;
+ int i, count, ret;
++ size_t buf_size;
++ void *buf;
+
+- cmd.cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG);
+- cmd.u.read_multi_info.count = reg_count;
++ buf_size = max_t(size_t, sizeof(*cmd), reg_count);
++
++ buf = kzalloc(buf_size, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ cmd = buf;
++
++ cmd->cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG);
++ cmd->u.read_multi_info.count = reg_count;
+ for (i = 0; i < reg_count; i++)
+- cmd.u.read_multi_info.address[i] = address[i];
++ cmd->u.read_multi_info.address[i] = address[i];
+
+ /* DT9812 only responds to 32 byte writes!! */
+ ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
+- &cmd, 32, &count, DT9812_USB_TIMEOUT);
++ cmd, sizeof(*cmd), &count, DT9812_USB_TIMEOUT);
+ if (ret)
+- return ret;
++ goto out;
++
++ ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
++ buf, reg_count, &count, DT9812_USB_TIMEOUT);
++ if (!ret) {
++ if (count == reg_count)
++ memcpy(value, buf, reg_count);
++ else
++ ret = -EREMOTEIO;
++ }
++out:
++ kfree(buf);
+
+- return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
+- value, reg_count, &count, DT9812_USB_TIMEOUT);
++ return ret;
+ }
+
+ static int dt9812_write_multiple_registers(struct comedi_device *dev,
+@@ -285,19 +326,27 @@ static int dt9812_write_multiple_registers(struct comedi_device *dev,
+ {
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct dt9812_private *devpriv = dev->private;
+- struct dt9812_usb_cmd cmd;
++ struct dt9812_usb_cmd *cmd;
+ int i, count;
++ int ret;
++
++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
++ if (!cmd)
++ return -ENOMEM;
+
+- cmd.cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG);
+- cmd.u.read_multi_info.count = reg_count;
++ cmd->cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG);
++ cmd->u.read_multi_info.count = reg_count;
+ for (i = 0; i < reg_count; i++) {
+- cmd.u.write_multi_info.write[i].address = address[i];
+- cmd.u.write_multi_info.write[i].value = value[i];
++ cmd->u.write_multi_info.write[i].address = address[i];
++ cmd->u.write_multi_info.write[i].value = value[i];
+ }
+
+ /* DT9812 only responds to 32 byte writes!! */
+- return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
+- &cmd, 32, &count, DT9812_USB_TIMEOUT);
++ ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
++ cmd, sizeof(*cmd), &count, DT9812_USB_TIMEOUT);
++ kfree(cmd);
++
++ return ret;
+ }
+
+ static int dt9812_rmw_multiple_registers(struct comedi_device *dev,
+@@ -306,17 +355,25 @@ static int dt9812_rmw_multiple_registers(struct comedi_device *dev,
+ {
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct dt9812_private *devpriv = dev->private;
+- struct dt9812_usb_cmd cmd;
++ struct dt9812_usb_cmd *cmd;
+ int i, count;
++ int ret;
++
++ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
++ if (!cmd)
++ return -ENOMEM;
+
+- cmd.cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG);
+- cmd.u.rmw_multi_info.count = reg_count;
++ cmd->cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG);
++ cmd->u.rmw_multi_info.count = reg_count;
+ for (i = 0; i < reg_count; i++)
+- cmd.u.rmw_multi_info.rmw[i] = rmw[i];
++ cmd->u.rmw_multi_info.rmw[i] = rmw[i];
+
+ /* DT9812 only responds to 32 byte writes!! */
+- return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
+- &cmd, 32, &count, DT9812_USB_TIMEOUT);
++ ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
++ cmd, sizeof(*cmd), &count, DT9812_USB_TIMEOUT);
++ kfree(cmd);
++
++ return ret;
+ }
+
+ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits)
+diff --git a/drivers/comedi/drivers/ni_usb6501.c b/drivers/comedi/drivers/ni_usb6501.c
+index 5b6d9d783b2f7..c42987b74b1dc 100644
+--- a/drivers/comedi/drivers/ni_usb6501.c
++++ b/drivers/comedi/drivers/ni_usb6501.c
+@@ -144,6 +144,10 @@ static const u8 READ_COUNTER_RESPONSE[] = {0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00};
+
++/* Largest supported packets */
++static const size_t TX_MAX_SIZE = sizeof(SET_PORT_DIR_REQUEST);
++static const size_t RX_MAX_SIZE = sizeof(READ_PORT_RESPONSE);
++
+ enum commands {
+ READ_PORT,
+ WRITE_PORT,
+@@ -501,6 +505,12 @@ static int ni6501_find_endpoints(struct comedi_device *dev)
+ if (!devpriv->ep_rx || !devpriv->ep_tx)
+ return -ENODEV;
+
++ if (usb_endpoint_maxp(devpriv->ep_rx) < RX_MAX_SIZE)
++ return -ENODEV;
++
++ if (usb_endpoint_maxp(devpriv->ep_tx) < TX_MAX_SIZE)
++ return -ENODEV;
++
+ return 0;
+ }
+
+diff --git a/drivers/comedi/drivers/vmk80xx.c b/drivers/comedi/drivers/vmk80xx.c
+index 9f920819cd742..4b00a9ea611ab 100644
+--- a/drivers/comedi/drivers/vmk80xx.c
++++ b/drivers/comedi/drivers/vmk80xx.c
+@@ -90,6 +90,9 @@ enum {
+ #define IC3_VERSION BIT(0)
+ #define IC6_VERSION BIT(1)
+
++#define MIN_BUF_SIZE 64
++#define PACKET_TIMEOUT 10000 /* ms */
++
+ enum vmk80xx_model {
+ VMK8055_MODEL,
+ VMK8061_MODEL
+@@ -157,22 +160,21 @@ static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
+ __u8 rx_addr;
+ unsigned int tx_pipe;
+ unsigned int rx_pipe;
+- size_t size;
++ size_t tx_size;
++ size_t rx_size;
+
+ tx_addr = devpriv->ep_tx->bEndpointAddress;
+ rx_addr = devpriv->ep_rx->bEndpointAddress;
+ tx_pipe = usb_sndbulkpipe(usb, tx_addr);
+ rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
++ tx_size = usb_endpoint_maxp(devpriv->ep_tx);
++ rx_size = usb_endpoint_maxp(devpriv->ep_rx);
+
+- /*
+- * The max packet size attributes of the K8061
+- * input/output endpoints are identical
+- */
+- size = usb_endpoint_maxp(devpriv->ep_tx);
++ usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf, tx_size, NULL,
++ PACKET_TIMEOUT);
+
+- usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
+- size, NULL, devpriv->ep_tx->bInterval);
+- usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
++ usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, rx_size, NULL,
++ PACKET_TIMEOUT);
+ }
+
+ static int vmk80xx_read_packet(struct comedi_device *dev)
+@@ -191,7 +193,7 @@ static int vmk80xx_read_packet(struct comedi_device *dev)
+ pipe = usb_rcvintpipe(usb, ep->bEndpointAddress);
+ return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf,
+ usb_endpoint_maxp(ep), NULL,
+- HZ * 10);
++ PACKET_TIMEOUT);
+ }
+
+ static int vmk80xx_write_packet(struct comedi_device *dev, int cmd)
+@@ -212,7 +214,7 @@ static int vmk80xx_write_packet(struct comedi_device *dev, int cmd)
+ pipe = usb_sndintpipe(usb, ep->bEndpointAddress);
+ return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf,
+ usb_endpoint_maxp(ep), NULL,
+- HZ * 10);
++ PACKET_TIMEOUT);
+ }
+
+ static int vmk80xx_reset_device(struct comedi_device *dev)
+@@ -678,12 +680,12 @@ static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
+ struct vmk80xx_private *devpriv = dev->private;
+ size_t size;
+
+- size = usb_endpoint_maxp(devpriv->ep_rx);
++ size = max(usb_endpoint_maxp(devpriv->ep_rx), MIN_BUF_SIZE);
+ devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
+ if (!devpriv->usb_rx_buf)
+ return -ENOMEM;
+
+- size = usb_endpoint_maxp(devpriv->ep_tx);
++ size = max(usb_endpoint_maxp(devpriv->ep_rx), MIN_BUF_SIZE);
+ devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
+ if (!devpriv->usb_tx_buf)
+ return -ENOMEM;
+diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
+index 5782b15a8caad..fcb44352623ee 100644
+--- a/drivers/cpufreq/cpufreq.c
++++ b/drivers/cpufreq/cpufreq.c
+@@ -1004,10 +1004,9 @@ static struct kobj_type ktype_cpufreq = {
+ .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;
+
+@@ -1391,7 +1390,7 @@ static int cpufreq_online(unsigned int cpu)
+ 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),
+@@ -1565,7 +1564,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+ /* 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;
+ }
+@@ -2523,8 +2522,15 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
+ if (ret)
+ return ret;
+
++ /*
++ * Resolve policy min/max to available frequencies. It ensures
++ * no frequency resolution will neither overshoot the requested maximum
++ * nor undershoot the requested minimum.
++ */
+ policy->min = new_data.min;
+ policy->max = new_data.max;
++ policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L);
++ policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H);
+ trace_cpu_frequency_limits(policy);
+
+ policy->cached_target_freq = UINT_MAX;
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 8c176b7dae415..e15c3bc17a55c 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -537,7 +537,8 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
+ * scaling factor is too high, so recompute it to make the HWP_CAP
+ * highest performance correspond to the maximum turbo frequency.
+ */
+- if (turbo_freq < cpu->pstate.turbo_pstate * scaling) {
++ cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
++ if (turbo_freq < cpu->pstate.turbo_freq) {
+ cpu->pstate.turbo_freq = turbo_freq;
+ scaling = DIV_ROUND_UP(turbo_freq, cpu->pstate.turbo_pstate);
+ cpu->pstate.scaling = scaling;
+@@ -998,9 +999,22 @@ static void intel_pstate_hwp_offline(struct cpudata *cpu)
+ */
+ value &= ~GENMASK_ULL(31, 24);
+ value |= HWP_ENERGY_PERF_PREFERENCE(cpu->epp_cached);
+- WRITE_ONCE(cpu->hwp_req_cached, value);
++ /*
++ * However, make sure that EPP will be set to "performance" when
++ * the CPU is brought back online again and the "performance"
++ * scaling algorithm is still in effect.
++ */
++ cpu->epp_policy = CPUFREQ_POLICY_UNKNOWN;
+ }
+
++ /*
++ * Clear the desired perf field in the cached HWP request value to
++ * prevent nonzero desired values from being leaked into the active
++ * mode.
++ */
++ value &= ~HWP_DESIRED_PERF(~0L);
++ WRITE_ONCE(cpu->hwp_req_cached, value);
++
+ value &= ~GENMASK_ULL(31, 0);
+ min_perf = HWP_LOWEST_PERF(READ_ONCE(cpu->hwp_cap_cached));
+
+@@ -2241,6 +2255,7 @@ static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = {
+ X86_MATCH(BROADWELL_D, core_funcs),
+ X86_MATCH(BROADWELL_X, core_funcs),
+ X86_MATCH(SKYLAKE_X, core_funcs),
++ X86_MATCH(ICELAKE_X, core_funcs),
+ {}
+ };
+
+@@ -2902,6 +2917,27 @@ static int intel_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+ return intel_pstate_cpu_exit(policy);
+ }
+
++static int intel_cpufreq_suspend(struct cpufreq_policy *policy)
++{
++ intel_pstate_suspend(policy);
++
++ if (hwp_active) {
++ struct cpudata *cpu = all_cpu_data[policy->cpu];
++ u64 value = READ_ONCE(cpu->hwp_req_cached);
++
++ /*
++ * Clear the desired perf field in MSR_HWP_REQUEST in case
++ * intel_cpufreq_adjust_perf() is in use and the last value
++ * written by it may not be suitable.
++ */
++ value &= ~HWP_DESIRED_PERF(~0L);
++ wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
++ WRITE_ONCE(cpu->hwp_req_cached, value);
++ }
++
++ return 0;
++}
++
+ static struct cpufreq_driver intel_cpufreq = {
+ .flags = CPUFREQ_CONST_LOOPS,
+ .verify = intel_cpufreq_verify_policy,
+@@ -2911,7 +2947,7 @@ static struct cpufreq_driver intel_cpufreq = {
+ .exit = intel_cpufreq_cpu_exit,
+ .offline = intel_cpufreq_cpu_offline,
+ .online = intel_pstate_cpu_online,
+- .suspend = intel_pstate_suspend,
++ .suspend = intel_cpufreq_suspend,
+ .resume = intel_pstate_resume,
+ .update_limits = intel_pstate_update_limits,
+ .name = "intel_cpufreq",
+diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
+index 53ec9585ccd44..469e18547d06c 100644
+--- a/drivers/cpuidle/sysfs.c
++++ b/drivers/cpuidle/sysfs.c
+@@ -488,6 +488,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
+ &kdev->kobj, "state%d", i);
+ if (ret) {
+ kobject_put(&kobj->kobj);
++ kfree(kobj);
+ goto error_state;
+ }
+ cpuidle_add_s2idle_attr_group(kobj);
+@@ -619,6 +620,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
+ &kdev->kobj, "driver");
+ if (ret) {
+ kobject_put(&kdrv->kobj);
++ kfree(kdrv);
+ return ret;
+ }
+
+@@ -705,7 +707,6 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
+ if (!kdev)
+ return -ENOMEM;
+ kdev->dev = dev;
+- dev->kobj_dev = kdev;
+
+ init_completion(&kdev->kobj_unregister);
+
+@@ -713,9 +714,11 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
+ "cpuidle");
+ if (error) {
+ kobject_put(&kdev->kobj);
++ kfree(kdev);
+ return error;
+ }
+
++ dev->kobj_dev = kdev;
+ kobject_uevent(&kdev->kobj, KOBJ_ADD);
+
+ return 0;
+diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
+index e313233ec6de7..bf6275ffc4aad 100644
+--- a/drivers/crypto/caam/caampkc.c
++++ b/drivers/crypto/caam/caampkc.c
+@@ -1153,16 +1153,27 @@ static struct caam_akcipher_alg caam_rsa = {
+ 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)
++ if (priv->era < 10) {
+ pk_inst = (rd_reg32(&priv->ctrl->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->ctrl->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)
+diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
+index af61f3a2c0d46..3738625c02509 100644
+--- a/drivers/crypto/caam/regs.h
++++ b/drivers/crypto/caam/regs.h
+@@ -322,6 +322,9 @@ struct version_regs {
+ /* 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
+diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c
+index e599ac6dc162a..790fa9058a36d 100644
+--- a/drivers/crypto/ccree/cc_driver.c
++++ b/drivers/crypto/ccree/cc_driver.c
+@@ -103,7 +103,8 @@ MODULE_DEVICE_TABLE(of, arm_ccree_dev_of_match);
+ static void init_cc_cache_params(struct cc_drvdata *drvdata)
+ {
+ struct device *dev = drvdata_to_dev(drvdata);
+- u32 cache_params, ace_const, val, mask;
++ u32 cache_params, ace_const, val;
++ u64 mask;
+
+ /* compute CC_AXIM_CACHE_PARAMS */
+ cache_params = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS));
+diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+index a72723455df72..877a948469bd1 100644
+--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+@@ -1274,6 +1274,7 @@ static int aead_do_fallback(struct aead_request *req, bool is_enc)
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(&rctx->fbk_req, req->src,
+ req->dst, req->cryptlen, req->iv);
++ aead_request_set_ad(&rctx->fbk_req, req->assoclen);
+ ret = is_enc ? crypto_aead_encrypt(&rctx->fbk_req) :
+ crypto_aead_decrypt(&rctx->fbk_req);
+ } else {
+diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
+index 33d8e50dcbdac..88c0ded411f15 100644
+--- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
++++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
+ /* Copyright(c) 2020 Intel Corporation */
++#include <linux/iopoll.h>
+ #include <adf_accel_devices.h>
+ #include <adf_common_drv.h>
+ #include <adf_pf2vf_msg.h>
+@@ -161,6 +162,35 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev)
+ ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_MASK_OFFSET, 0);
+ }
+
++static int adf_init_device(struct adf_accel_dev *accel_dev)
++{
++ void __iomem *addr;
++ u32 status;
++ u32 csr;
++ int ret;
++
++ addr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr;
++
++ /* Temporarily mask PM interrupt */
++ csr = ADF_CSR_RD(addr, ADF_4XXX_ERRMSK2);
++ csr |= ADF_4XXX_PM_SOU;
++ ADF_CSR_WR(addr, ADF_4XXX_ERRMSK2, csr);
++
++ /* Set DRV_ACTIVE bit to power up the device */
++ ADF_CSR_WR(addr, ADF_4XXX_PM_INTERRUPT, ADF_4XXX_PM_DRV_ACTIVE);
++
++ /* Poll status register to make sure the device is powered up */
++ ret = read_poll_timeout(ADF_CSR_RD, status,
++ status & ADF_4XXX_PM_INIT_STATE,
++ ADF_4XXX_PM_POLL_DELAY_US,
++ ADF_4XXX_PM_POLL_TIMEOUT_US, true, addr,
++ ADF_4XXX_PM_STATUS);
++ if (ret)
++ dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n");
++
++ return ret;
++}
++
+ static int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev)
+ {
+ return 0;
+@@ -215,6 +245,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
+ hw_data->exit_arb = adf_exit_arb;
+ hw_data->get_arb_mapping = adf_get_arbiter_mapping;
+ hw_data->enable_ints = adf_enable_ints;
++ hw_data->init_device = adf_init_device;
+ hw_data->reset_device = adf_reset_flr;
+ hw_data->admin_ae_mask = ADF_4XXX_ADMIN_AE_MASK;
+ hw_data->uof_get_num_objs = uof_get_num_objs;
+diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
+index 4fe2a776293c2..924bac6feb372 100644
+--- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
++++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
+@@ -62,6 +62,16 @@
+ #define ADF_4XXX_ADMINMSGLR_OFFSET (0x500578)
+ #define ADF_4XXX_MAILBOX_BASE_OFFSET (0x600970)
+
++/* Power management */
++#define ADF_4XXX_PM_POLL_DELAY_US 20
++#define ADF_4XXX_PM_POLL_TIMEOUT_US USEC_PER_SEC
++#define ADF_4XXX_PM_STATUS (0x50A00C)
++#define ADF_4XXX_PM_INTERRUPT (0x50A028)
++#define ADF_4XXX_PM_DRV_ACTIVE BIT(20)
++#define ADF_4XXX_PM_INIT_STATE BIT(21)
++/* Power management source in ERRSOU2 and ERRMSK2 */
++#define ADF_4XXX_PM_SOU BIT(18)
++
+ /* Firmware Binaries */
+ #define ADF_4XXX_FW "qat_4xxx.bin"
+ #define ADF_4XXX_MMP "qat_4xxx_mmp.bin"
+diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
+index 38c0af6d4e43e..580566cfcb04c 100644
+--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
++++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
+@@ -166,6 +166,7 @@ struct adf_hw_device_data {
+ int (*init_arb)(struct adf_accel_dev *accel_dev);
+ void (*exit_arb)(struct adf_accel_dev *accel_dev);
+ const u32 *(*get_arb_mapping)(void);
++ int (*init_device)(struct adf_accel_dev *accel_dev);
+ void (*disable_iov)(struct adf_accel_dev *accel_dev);
+ void (*configure_iov_threads)(struct adf_accel_dev *accel_dev,
+ bool enable);
+diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c
+index 60bc7b991d351..e3749e5817d94 100644
+--- a/drivers/crypto/qat/qat_common/adf_init.c
++++ b/drivers/crypto/qat/qat_common/adf_init.c
+@@ -79,6 +79,11 @@ int adf_dev_init(struct adf_accel_dev *accel_dev)
+ return -EFAULT;
+ }
+
++ if (hw_data->init_device && hw_data->init_device(accel_dev)) {
++ dev_err(&GET_DEV(accel_dev), "Failed to initialize device\n");
++ return -EFAULT;
++ }
++
+ if (hw_data->init_admin_comms && hw_data->init_admin_comms(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev), "Failed initialize admin comms\n");
+ return -EFAULT;
+diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
+index 976b9ab7617cd..5a41beb8f20f6 100644
+--- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
++++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
+@@ -156,6 +156,13 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr)
+ 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;
+@@ -204,6 +211,11 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info)
+
+ /* 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;
+@@ -287,6 +299,7 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info)
+ 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));
+
+diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c
+index 7828a6573f3e2..2e300c255ab94 100644
+--- a/drivers/crypto/qat/qat_common/adf_vf_isr.c
++++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c
+@@ -101,6 +101,11 @@ static void adf_pf2vf_bh_handler(void *data)
+
+ /* 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 */
+@@ -149,6 +154,7 @@ static void adf_pf2vf_bh_handler(void *data)
+ 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;
+diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
+index 55aa3a71169b0..7717e9e5977bb 100644
+--- a/drivers/crypto/s5p-sss.c
++++ b/drivers/crypto/s5p-sss.c
+@@ -2171,6 +2171,8 @@ static int s5p_aes_probe(struct platform_device *pdev)
+
+ 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
+diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
+index 8e45aa07d662f..5444b5a7fd3c4 100644
+--- a/drivers/cxl/pci.c
++++ b/drivers/cxl/pci.c
+@@ -972,7 +972,7 @@ static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm,
+ if (pci_resource_len(pdev, bar) < offset) {
+ dev_err(dev, "BAR%d: %pr: too small (offset: %#llx)\n", bar,
+ &pdev->resource[bar], (unsigned long long)offset);
+- return IOMEM_ERR_PTR(-ENXIO);
++ return NULL;
+ }
+
+ addr = pci_iomap(pdev, bar, 0);
+diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
+index 63d32261b63ff..61e20ae7b08b7 100644
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -74,7 +74,7 @@ static void dma_buf_release(struct dentry *dentry)
+ * If you hit this BUG() it means someone dropped their ref to the
+ * dma-buf while still having pending operation to the buffer.
+ */
+- BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active);
++ BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
+
+ dma_buf_stats_teardown(dmabuf);
+ dmabuf->ops->release(dmabuf);
+@@ -82,6 +82,7 @@ static void dma_buf_release(struct dentry *dentry)
+ 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);
+@@ -205,16 +206,55 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
+ wake_up_locked_poll(dcb->poll, dcb->active);
+ dcb->active = 0;
+ spin_unlock_irqrestore(&dcb->poll->lock, flags);
++ dma_fence_put(fence);
++}
++
++static bool dma_buf_poll_shared(struct dma_resv *resv,
++ struct dma_buf_poll_cb_t *dcb)
++{
++ struct dma_resv_list *fobj = dma_resv_shared_list(resv);
++ struct dma_fence *fence;
++ int i, r;
++
++ if (!fobj)
++ return false;
++
++ for (i = 0; i < fobj->shared_count; ++i) {
++ fence = rcu_dereference_protected(fobj->shared[i],
++ dma_resv_held(resv));
++ dma_fence_get(fence);
++ r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
++ if (!r)
++ return true;
++ dma_fence_put(fence);
++ }
++
++ return false;
++}
++
++static bool dma_buf_poll_excl(struct dma_resv *resv,
++ struct dma_buf_poll_cb_t *dcb)
++{
++ struct dma_fence *fence = dma_resv_excl_fence(resv);
++ int r;
++
++ if (!fence)
++ return false;
++
++ dma_fence_get(fence);
++ r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
++ if (!r)
++ return true;
++ dma_fence_put(fence);
++
++ return false;
+ }
+
+ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+ {
+ struct dma_buf *dmabuf;
+ struct dma_resv *resv;
+- struct dma_resv_list *fobj;
+- struct dma_fence *fence_excl;
+ __poll_t events;
+- unsigned shared_count, seq;
+
+ dmabuf = file->private_data;
+ if (!dmabuf || !dmabuf->resv)
+@@ -228,101 +268,50 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+ if (!events)
+ return 0;
+
+-retry:
+- seq = read_seqcount_begin(&resv->seq);
+- rcu_read_lock();
+-
+- fobj = rcu_dereference(resv->fence);
+- if (fobj)
+- shared_count = fobj->shared_count;
+- else
+- shared_count = 0;
+- fence_excl = dma_resv_excl_fence(resv);
+- if (read_seqcount_retry(&resv->seq, seq)) {
+- rcu_read_unlock();
+- goto retry;
+- }
+-
+- if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) {
+- struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
+- __poll_t pevents = EPOLLIN;
++ dma_resv_lock(resv, NULL);
+
+- if (shared_count == 0)
+- pevents |= EPOLLOUT;
++ if (events & EPOLLOUT) {
++ struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_out;
+
++ /* Check that callback isn't busy */
+ spin_lock_irq(&dmabuf->poll.lock);
+- if (dcb->active) {
+- dcb->active |= pevents;
+- events &= ~pevents;
+- } else
+- dcb->active = pevents;
++ if (dcb->active)
++ events &= ~EPOLLOUT;
++ else
++ dcb->active = EPOLLOUT;
+ spin_unlock_irq(&dmabuf->poll.lock);
+
+- if (events & pevents) {
+- if (!dma_fence_get_rcu(fence_excl)) {
+- /* force a recheck */
+- events &= ~pevents;
+- dma_buf_poll_cb(NULL, &dcb->cb);
+- } else if (!dma_fence_add_callback(fence_excl, &dcb->cb,
+- dma_buf_poll_cb)) {
+- events &= ~pevents;
+- dma_fence_put(fence_excl);
+- } else {
+- /*
+- * No callback queued, wake up any additional
+- * waiters.
+- */
+- dma_fence_put(fence_excl);
++ if (events & EPOLLOUT) {
++ if (!dma_buf_poll_shared(resv, dcb) &&
++ !dma_buf_poll_excl(resv, dcb))
++ /* No callback queued, wake up any other waiters */
+ dma_buf_poll_cb(NULL, &dcb->cb);
+- }
++ else
++ events &= ~EPOLLOUT;
+ }
+ }
+
+- if ((events & EPOLLOUT) && shared_count > 0) {
+- struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared;
+- int i;
++ if (events & EPOLLIN) {
++ struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_in;
+
+- /* Only queue a new callback if no event has fired yet */
++ /* Check that callback isn't busy */
+ spin_lock_irq(&dmabuf->poll.lock);
+ if (dcb->active)
+- events &= ~EPOLLOUT;
++ events &= ~EPOLLIN;
+ else
+- dcb->active = EPOLLOUT;
++ dcb->active = EPOLLIN;
+ spin_unlock_irq(&dmabuf->poll.lock);
+
+- if (!(events & EPOLLOUT))
+- goto out;
+-
+- for (i = 0; i < shared_count; ++i) {
+- struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
+-
+- if (!dma_fence_get_rcu(fence)) {
+- /*
+- * fence refcount dropped to zero, this means
+- * that fobj has been freed
+- *
+- * call dma_buf_poll_cb and force a recheck!
+- */
+- events &= ~EPOLLOUT;
++ if (events & EPOLLIN) {
++ if (!dma_buf_poll_excl(resv, dcb))
++ /* No callback queued, wake up any other waiters */
+ dma_buf_poll_cb(NULL, &dcb->cb);
+- break;
+- }
+- if (!dma_fence_add_callback(fence, &dcb->cb,
+- dma_buf_poll_cb)) {
+- dma_fence_put(fence);
+- events &= ~EPOLLOUT;
+- break;
+- }
+- dma_fence_put(fence);
++ else
++ events &= ~EPOLLIN;
+ }
+-
+- /* No callback queued, wake up any additional waiters. */
+- if (i == shared_count)
+- dma_buf_poll_cb(NULL, &dcb->cb);
+ }
+
+-out:
+- rcu_read_unlock();
++ dma_resv_unlock(resv);
+ return events;
+ }
+
+@@ -565,8 +554,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
+ 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;
++ dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;
++ dmabuf->cb_in.active = dmabuf->cb_out.active = 0;
+
+ if (!resv) {
+ resv = (struct dma_resv *)&dmabuf[1];
+diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
+index 23a7e74ef9666..8660508f3684f 100644
+--- a/drivers/dma-buf/heaps/system_heap.c
++++ b/drivers/dma-buf/heaps/system_heap.c
+@@ -289,7 +289,7 @@ static void system_heap_dma_buf_release(struct dma_buf *dmabuf)
+ int i;
+
+ table = &buffer->sg_table;
+- for_each_sg(table->sgl, sg, table->nents, i) {
++ for_each_sgtable_sg(table, sg, i) {
+ struct page *page = sg_page(sg);
+
+ __free_pages(page, compound_order(page));
+diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
+index ab78e0f6afd70..e18abbd56fb51 100644
+--- a/drivers/dma/at_xdmac.c
++++ b/drivers/dma/at_xdmac.c
+@@ -155,7 +155,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 */
+@@ -1926,6 +1926,30 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan)
+ return;
+ }
+
++static void at_xdmac_axi_config(struct platform_device *pdev)
++{
++ struct at_xdmac *atxdmac = (struct at_xdmac *)platform_get_drvdata(pdev);
++ bool dev_m2m = false;
++ u32 dma_requests;
++
++ if (!atxdmac->layout->axi_config)
++ return; /* Not supported */
++
++ if (!of_property_read_u32(pdev->dev.of_node, "dma-requests",
++ &dma_requests)) {
++ dev_info(&pdev->dev, "controller in mem2mem mode.\n");
++ dev_m2m = true;
++ }
++
++ if (dev_m2m) {
++ at_xdmac_write(atxdmac, AT_XDMAC_GCFG, AT_XDMAC_GCFG_M2M);
++ at_xdmac_write(atxdmac, AT_XDMAC_GWAC, AT_XDMAC_GWAC_M2M);
++ } else {
++ at_xdmac_write(atxdmac, AT_XDMAC_GCFG, AT_XDMAC_GCFG_P2M);
++ at_xdmac_write(atxdmac, AT_XDMAC_GWAC, AT_XDMAC_GWAC_P2M);
++ }
++}
++
+ #ifdef CONFIG_PM
+ static int atmel_xdmac_prepare(struct device *dev)
+ {
+@@ -1975,6 +1999,7 @@ static int atmel_xdmac_resume(struct device *dev)
+ struct at_xdmac *atxdmac = dev_get_drvdata(dev);
+ struct at_xdmac_chan *atchan;
+ struct dma_chan *chan, *_chan;
++ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+ int i;
+ int ret;
+
+@@ -1982,6 +2007,8 @@ static int atmel_xdmac_resume(struct device *dev)
+ if (ret)
+ return ret;
+
++ at_xdmac_axi_config(pdev);
++
+ /* Clear pending interrupts. */
+ for (i = 0; i < atxdmac->dma.chancnt; i++) {
+ atchan = &atxdmac->chan[i];
+@@ -2007,30 +2034,6 @@ static int atmel_xdmac_resume(struct device *dev)
+ }
+ #endif /* CONFIG_PM_SLEEP */
+
+-static void at_xdmac_axi_config(struct platform_device *pdev)
+-{
+- struct at_xdmac *atxdmac = (struct at_xdmac *)platform_get_drvdata(pdev);
+- bool dev_m2m = false;
+- u32 dma_requests;
+-
+- if (!atxdmac->layout->axi_config)
+- return; /* Not supported */
+-
+- if (!of_property_read_u32(pdev->dev.of_node, "dma-requests",
+- &dma_requests)) {
+- dev_info(&pdev->dev, "controller in mem2mem mode.\n");
+- dev_m2m = true;
+- }
+-
+- if (dev_m2m) {
+- at_xdmac_write(atxdmac, AT_XDMAC_GCFG, AT_XDMAC_GCFG_M2M);
+- at_xdmac_write(atxdmac, AT_XDMAC_GWAC, AT_XDMAC_GWAC_M2M);
+- } else {
+- at_xdmac_write(atxdmac, AT_XDMAC_GCFG, AT_XDMAC_GCFG_P2M);
+- at_xdmac_write(atxdmac, AT_XDMAC_GWAC, AT_XDMAC_GWAC_P2M);
+- }
+-}
+-
+ static int at_xdmac_probe(struct platform_device *pdev)
+ {
+ struct at_xdmac *atxdmac;
+diff --git a/drivers/dma/bestcomm/ata.c b/drivers/dma/bestcomm/ata.c
+index 2fd87f83cf90b..e169f18da551f 100644
+--- a/drivers/dma/bestcomm/ata.c
++++ b/drivers/dma/bestcomm/ata.c
+@@ -133,7 +133,7 @@ void bcom_ata_reset_bd(struct bcom_task *tsk)
+ struct bcom_ata_var *var;
+
+ /* Reset all BD */
+- memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
++ memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ tsk->index = 0;
+ tsk->outdex = 0;
+diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c
+index d91cbbe7a48fb..8c42e5ca00a99 100644
+--- a/drivers/dma/bestcomm/bestcomm.c
++++ b/drivers/dma/bestcomm/bestcomm.c
+@@ -95,7 +95,7 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size)
+ tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
+ if (!tsk->bd)
+ goto error;
+- memset(tsk->bd, 0x00, bd_count * bd_size);
++ memset_io(tsk->bd, 0x00, bd_count * bd_size);
+
+ tsk->num_bd = bd_count;
+ tsk->bd_size = bd_size;
+@@ -186,16 +186,16 @@ bcom_load_image(int task, u32 *task_image)
+ inc = bcom_task_inc(task);
+
+ /* Clear & copy */
+- memset(var, 0x00, BCOM_VAR_SIZE);
+- memset(inc, 0x00, BCOM_INC_SIZE);
++ memset_io(var, 0x00, BCOM_VAR_SIZE);
++ memset_io(inc, 0x00, BCOM_INC_SIZE);
+
+ desc_src = (u32 *)(hdr + 1);
+ var_src = desc_src + hdr->desc_size;
+ inc_src = var_src + hdr->var_size;
+
+- memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
+- memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
+- memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
++ memcpy_toio(desc, desc_src, hdr->desc_size * sizeof(u32));
++ memcpy_toio(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
++ memcpy_toio(inc, inc_src, hdr->inc_size * sizeof(u32));
+
+ return 0;
+ }
+@@ -302,13 +302,13 @@ static int bcom_engine_init(void)
+ return -ENOMEM;
+ }
+
+- memset(bcom_eng->tdt, 0x00, tdt_size);
+- memset(bcom_eng->ctx, 0x00, ctx_size);
+- memset(bcom_eng->var, 0x00, var_size);
+- memset(bcom_eng->fdt, 0x00, fdt_size);
++ memset_io(bcom_eng->tdt, 0x00, tdt_size);
++ memset_io(bcom_eng->ctx, 0x00, ctx_size);
++ memset_io(bcom_eng->var, 0x00, var_size);
++ memset_io(bcom_eng->fdt, 0x00, fdt_size);
+
+ /* Copy the FDT for the EU#3 */
+- memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
++ memcpy_toio(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
+
+ /* Initialize Task base structure */
+ for (task=0; task<BCOM_MAX_TASKS; task++)
+diff --git a/drivers/dma/bestcomm/fec.c b/drivers/dma/bestcomm/fec.c
+index 7f1fb1c999e43..d203618ac11fe 100644
+--- a/drivers/dma/bestcomm/fec.c
++++ b/drivers/dma/bestcomm/fec.c
+@@ -140,7 +140,7 @@ bcom_fec_rx_reset(struct bcom_task *tsk)
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+- memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
++ memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
+@@ -241,7 +241,7 @@ bcom_fec_tx_reset(struct bcom_task *tsk)
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+- memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
++ memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
+diff --git a/drivers/dma/bestcomm/gen_bd.c b/drivers/dma/bestcomm/gen_bd.c
+index 906ddba6a6f5d..8a24a5cbc2633 100644
+--- a/drivers/dma/bestcomm/gen_bd.c
++++ b/drivers/dma/bestcomm/gen_bd.c
+@@ -142,7 +142,7 @@ bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+- memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
++ memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
+@@ -226,7 +226,7 @@ bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+- memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
++ memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
+diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
+index 1bfbd64b13717..53f16d3f00294 100644
+--- a/drivers/dma/dmaengine.h
++++ b/drivers/dma/dmaengine.h
+@@ -176,7 +176,7 @@ dmaengine_desc_get_callback_invoke(struct dma_async_tx_descriptor *tx,
+ static inline bool
+ dmaengine_desc_callback_valid(struct dmaengine_desc_callback *cb)
+ {
+- return (cb->callback) ? true : false;
++ return cb->callback || cb->callback_result;
+ }
+
+ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
+diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
+index 83a5ff2ecf2a0..419b206f8a42d 100644
+--- a/drivers/dma/idxd/device.c
++++ b/drivers/dma/idxd/device.c
+@@ -427,7 +427,6 @@ void idxd_wq_quiesce(struct idxd_wq *wq)
+ {
+ percpu_ref_kill(&wq->wq_active);
+ wait_for_completion(&wq->wq_dead);
+- percpu_ref_exit(&wq->wq_active);
+ }
+
+ /* Device control bits */
+@@ -584,6 +583,8 @@ void idxd_device_reset(struct idxd_device *idxd)
+ spin_lock(&idxd->dev_lock);
+ idxd_device_clear_state(idxd);
+ idxd->state = IDXD_DEV_DISABLED;
++ idxd_unmask_error_interrupts(idxd);
++ idxd_msix_perm_setup(idxd);
+ spin_unlock(&idxd->dev_lock);
+ }
+
+diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c
+index e0f056c1d1f56..c39e9483206ad 100644
+--- a/drivers/dma/idxd/dma.c
++++ b/drivers/dma/idxd/dma.c
+@@ -311,6 +311,7 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev)
+
+ err_dma:
+ idxd_wq_quiesce(wq);
++ percpu_ref_exit(&wq->wq_active);
+ err_ref:
+ idxd_wq_free_resources(wq);
+ err_res_alloc:
+@@ -328,9 +329,9 @@ static void idxd_dmaengine_drv_remove(struct idxd_dev *idxd_dev)
+ mutex_lock(&wq->wq_lock);
+ idxd_wq_quiesce(wq);
+ idxd_unregister_dma_channel(wq);
+- __drv_disable_wq(wq);
+ idxd_wq_free_resources(wq);
+- wq->type = IDXD_WQT_NONE;
++ __drv_disable_wq(wq);
++ percpu_ref_exit(&wq->wq_active);
+ mutex_unlock(&wq->wq_lock);
+ }
+
+diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
+index eb09bc591c316..7bf03f371ce19 100644
+--- a/drivers/dma/idxd/init.c
++++ b/drivers/dma/idxd/init.c
+@@ -797,11 +797,19 @@ static void idxd_remove(struct pci_dev *pdev)
+ int msixcnt = pci_msix_vec_count(pdev);
+ int i;
+
+- dev_dbg(&pdev->dev, "%s called\n", __func__);
++ idxd_unregister_devices(idxd);
++ /*
++ * When ->release() is called for the idxd->conf_dev, it frees all the memory related
++ * to the idxd context. The driver still needs those bits in order to do the rest of
++ * the cleanup. However, we do need to unbound the idxd sub-driver. So take a ref
++ * on the device here to hold off the freeing while allowing the idxd sub-driver
++ * to unbind.
++ */
++ get_device(idxd_confdev(idxd));
++ device_unregister(idxd_confdev(idxd));
+ idxd_shutdown(pdev);
+ if (device_pasid_enabled(idxd))
+ idxd_disable_system_pasid(idxd);
+- idxd_unregister_devices(idxd);
+
+ for (i = 0; i < msixcnt; i++) {
+ irq_entry = &idxd->irq_entries[i];
+@@ -815,7 +823,7 @@ static void idxd_remove(struct pci_dev *pdev)
+ pci_disable_device(pdev);
+ destroy_workqueue(idxd->wq);
+ perfmon_pmu_remove(idxd);
+- device_unregister(idxd_confdev(idxd));
++ put_device(idxd_confdev(idxd));
+ }
+
+ static struct pci_driver idxd_pci_driver = {
+diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
+index ca88fa7a328e7..6d6af0dc3c0ec 100644
+--- a/drivers/dma/idxd/irq.c
++++ b/drivers/dma/idxd/irq.c
+@@ -63,6 +63,9 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
+ int i;
+ bool err = false;
+
++ if (cause & IDXD_INTC_HALT_STATE)
++ goto halt;
++
+ if (cause & IDXD_INTC_ERR) {
+ spin_lock(&idxd->dev_lock);
+ for (i = 0; i < 4; i++)
+@@ -121,6 +124,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
+ if (!err)
+ return 0;
+
++halt:
+ gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET);
+ if (gensts.state == IDXD_DEVICE_STATE_HALT) {
+ idxd->state = IDXD_DEV_HALTED;
+@@ -133,9 +137,10 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
+ INIT_WORK(&idxd->work, idxd_device_reinit);
+ queue_work(idxd->wq, &idxd->work);
+ } else {
+- spin_lock(&idxd->dev_lock);
++ idxd->state = IDXD_DEV_HALTED;
+ idxd_wqs_quiesce(idxd);
+ idxd_wqs_unmap_portal(idxd);
++ spin_lock(&idxd->dev_lock);
+ idxd_device_clear_state(idxd);
+ dev_err(&idxd->pdev->dev,
+ "idxd halted, need %s.\n",
+diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h
+index ffc7550a77eeb..97ffb06de9b0d 100644
+--- a/drivers/dma/idxd/registers.h
++++ b/drivers/dma/idxd/registers.h
+@@ -158,6 +158,7 @@ enum idxd_device_reset_type {
+ #define IDXD_INTC_CMD 0x02
+ #define IDXD_INTC_OCCUPY 0x04
+ #define IDXD_INTC_PERFMON_OVFL 0x08
++#define IDXD_INTC_HALT_STATE 0x10
+
+ #define IDXD_CMD_OFFSET 0xa0
+ union idxd_command_reg {
+diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c
+index de76fb4abac24..83452fbbb168b 100644
+--- a/drivers/dma/idxd/submit.c
++++ b/drivers/dma/idxd/submit.c
+@@ -106,6 +106,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
+ {
+ struct idxd_desc *d, *t, *found = NULL;
+ struct llist_node *head;
++ LIST_HEAD(flist);
+
+ desc->completion->status = IDXD_COMP_DESC_ABORT;
+ /*
+@@ -120,7 +121,11 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
+ found = desc;
+ continue;
+ }
+- list_add_tail(&desc->list, &ie->work_list);
++
++ if (d->completion->status)
++ list_add_tail(&d->list, &flist);
++ else
++ list_add_tail(&d->list, &ie->work_list);
+ }
+ }
+
+@@ -130,6 +135,17 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
+
+ if (found)
+ complete_desc(found, IDXD_COMPLETE_ABORT);
++
++ /*
++ * complete_desc() will return desc to allocator and the desc can be
++ * acquired by a different process and the desc->list can be modified.
++ * Delete desc from list so the list trasversing does not get corrupted
++ * by the other process.
++ */
++ list_for_each_entry_safe(d, t, &flist, list) {
++ list_del_init(&d->list);
++ complete_desc(d, IDXD_COMPLETE_NORMAL);
++ }
+ }
+
+ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
+diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
+index 962b6e05287b5..d95c421877fb7 100644
+--- a/drivers/dma/st_fdma.c
++++ b/drivers/dma/st_fdma.c
+@@ -874,4 +874,4 @@ MODULE_LICENSE("GPL v2");
+ 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);
+diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
+index 9063c727962ed..7dfc743ac4338 100644
+--- a/drivers/dma/stm32-dma.c
++++ b/drivers/dma/stm32-dma.c
+@@ -270,7 +270,6 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len,
+ u32 threshold)
+ {
+ enum dma_slave_buswidth max_width;
+- u64 addr = buf_addr;
+
+ if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL)
+ max_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+@@ -281,7 +280,7 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len,
+ max_width > DMA_SLAVE_BUSWIDTH_1_BYTE)
+ max_width = max_width >> 1;
+
+- if (do_div(addr, max_width))
++ if (buf_addr & (max_width - 1))
+ max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
+ return max_width;
+@@ -753,8 +752,14 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
+ if (src_bus_width < 0)
+ return src_bus_width;
+
+- /* Set memory burst size */
+- src_maxburst = STM32_DMA_MAX_BURST;
++ /*
++ * Set memory burst size - burst not possible if address is not aligned on
++ * the address boundary equal to the size of the transfer
++ */
++ if (buf_addr & (buf_len - 1))
++ src_maxburst = 1;
++ else
++ src_maxburst = STM32_DMA_MAX_BURST;
+ src_best_burst = stm32_dma_get_best_burst(buf_len,
+ src_maxburst,
+ fifoth,
+@@ -803,8 +808,14 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
+ if (dst_bus_width < 0)
+ return dst_bus_width;
+
+- /* Set memory burst size */
+- dst_maxburst = STM32_DMA_MAX_BURST;
++ /*
++ * Set memory burst size - burst not possible if address is not aligned on
++ * the address boundary equal to the size of the transfer
++ */
++ if (buf_addr & (buf_len - 1))
++ dst_maxburst = 1;
++ else
++ dst_maxburst = STM32_DMA_MAX_BURST;
+ dst_best_burst = stm32_dma_get_best_burst(buf_len,
+ dst_maxburst,
+ fifoth,
+diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
+index b1115a6d1935c..d1dff3a29db59 100644
+--- a/drivers/dma/tegra210-adma.c
++++ b/drivers/dma/tegra210-adma.c
+@@ -867,7 +867,7 @@ static int tegra_adma_probe(struct platform_device *pdev)
+
+ pm_runtime_enable(&pdev->dev);
+
+- ret = pm_runtime_get_sync(&pdev->dev);
++ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ goto rpm_disable;
+
+diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
+index a35858610780c..041d8e32d6300 100644
+--- a/drivers/dma/ti/k3-udma.c
++++ b/drivers/dma/ti/k3-udma.c
+@@ -1348,6 +1348,7 @@ static int bcdma_get_bchan(struct udma_chan *uc)
+ {
+ struct udma_dev *ud = uc->ud;
+ enum udma_tp_level tpl;
++ int ret;
+
+ if (uc->bchan) {
+ dev_dbg(ud->dev, "chan%d: already have bchan%d allocated\n",
+@@ -1365,8 +1366,11 @@ static int bcdma_get_bchan(struct udma_chan *uc)
+ tpl = ud->bchan_tpl.levels - 1;
+
+ uc->bchan = __udma_reserve_bchan(ud, tpl, -1);
+- if (IS_ERR(uc->bchan))
+- return PTR_ERR(uc->bchan);
++ if (IS_ERR(uc->bchan)) {
++ ret = PTR_ERR(uc->bchan);
++ uc->bchan = NULL;
++ return ret;
++ }
+
+ uc->tchan = uc->bchan;
+
+@@ -1376,6 +1380,7 @@ static int bcdma_get_bchan(struct udma_chan *uc)
+ static int udma_get_tchan(struct udma_chan *uc)
+ {
+ struct udma_dev *ud = uc->ud;
++ int ret;
+
+ if (uc->tchan) {
+ dev_dbg(ud->dev, "chan%d: already have tchan%d allocated\n",
+@@ -1390,8 +1395,11 @@ static int udma_get_tchan(struct udma_chan *uc)
+ */
+ uc->tchan = __udma_reserve_tchan(ud, uc->config.channel_tpl,
+ uc->config.mapped_channel_id);
+- if (IS_ERR(uc->tchan))
+- return PTR_ERR(uc->tchan);
++ if (IS_ERR(uc->tchan)) {
++ ret = PTR_ERR(uc->tchan);
++ uc->tchan = NULL;
++ return ret;
++ }
+
+ if (ud->tflow_cnt) {
+ int tflow_id;
+@@ -1421,6 +1429,7 @@ static int udma_get_tchan(struct udma_chan *uc)
+ static int udma_get_rchan(struct udma_chan *uc)
+ {
+ struct udma_dev *ud = uc->ud;
++ int ret;
+
+ if (uc->rchan) {
+ dev_dbg(ud->dev, "chan%d: already have rchan%d allocated\n",
+@@ -1435,8 +1444,13 @@ static int udma_get_rchan(struct udma_chan *uc)
+ */
+ uc->rchan = __udma_reserve_rchan(ud, uc->config.channel_tpl,
+ uc->config.mapped_channel_id);
++ if (IS_ERR(uc->rchan)) {
++ ret = PTR_ERR(uc->rchan);
++ uc->rchan = NULL;
++ return ret;
++ }
+
+- return PTR_ERR_OR_ZERO(uc->rchan);
++ return 0;
+ }
+
+ static int udma_get_chan_pair(struct udma_chan *uc)
+@@ -1490,6 +1504,7 @@ static int udma_get_chan_pair(struct udma_chan *uc)
+ static int udma_get_rflow(struct udma_chan *uc, int flow_id)
+ {
+ struct udma_dev *ud = uc->ud;
++ int ret;
+
+ if (!uc->rchan) {
+ dev_err(ud->dev, "chan%d: does not have rchan??\n", uc->id);
+@@ -1503,8 +1518,13 @@ static int udma_get_rflow(struct udma_chan *uc, int flow_id)
+ }
+
+ uc->rflow = __udma_get_rflow(ud, flow_id);
++ if (IS_ERR(uc->rflow)) {
++ ret = PTR_ERR(uc->rflow);
++ uc->rflow = NULL;
++ return ret;
++ }
+
+- return PTR_ERR_OR_ZERO(uc->rflow);
++ return 0;
+ }
+
+ static void bcdma_put_bchan(struct udma_chan *uc)
+diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c
+index b280a53e8570a..ce5c66e6897d2 100644
+--- a/drivers/dma/xilinx/xilinx_dpdma.c
++++ b/drivers/dma/xilinx/xilinx_dpdma.c
+@@ -271,9 +271,6 @@ struct xilinx_dpdma_device {
+ /* -----------------------------------------------------------------------------
+ * DebugFS
+ */
+-
+-#ifdef CONFIG_DEBUG_FS
+-
+ #define XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE 32
+ #define XILINX_DPDMA_DEBUGFS_UINT16_MAX_STR "65535"
+
+@@ -299,7 +296,7 @@ struct xilinx_dpdma_debugfs_request {
+
+ static void xilinx_dpdma_debugfs_desc_done_irq(struct xilinx_dpdma_chan *chan)
+ {
+- if (chan->id == dpdma_debugfs.chan_id)
++ if (IS_ENABLED(CONFIG_DEBUG_FS) && chan->id == dpdma_debugfs.chan_id)
+ dpdma_debugfs.xilinx_dpdma_irq_done_count++;
+ }
+
+@@ -462,16 +459,6 @@ static void xilinx_dpdma_debugfs_init(struct xilinx_dpdma_device *xdev)
+ dev_err(xdev->dev, "Failed to create debugfs testcase file\n");
+ }
+
+-#else
+-static void xilinx_dpdma_debugfs_init(struct xilinx_dpdma_device *xdev)
+-{
+-}
+-
+-static void xilinx_dpdma_debugfs_desc_done_irq(struct xilinx_dpdma_chan *chan)
+-{
+-}
+-#endif /* CONFIG_DEBUG_FS */
+-
+ /* -----------------------------------------------------------------------------
+ * I/O Accessors
+ */
+diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
+index 99b06a3e8fb12..4fce75013674f 100644
+--- a/drivers/edac/amd64_edac.c
++++ b/drivers/edac/amd64_edac.c
+@@ -1065,12 +1065,14 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
+ #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))
+@@ -1083,6 +1085,20 @@ static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
+ 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;
+ }
+
+@@ -1891,10 +1907,14 @@ static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
+ *
+ * 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);
+diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
+index 4c626fcd4dcbb..1522d4aa2ca62 100644
+--- a/drivers/edac/sb_edac.c
++++ b/drivers/edac/sb_edac.c
+@@ -1052,7 +1052,7 @@ static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
+ 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)
+diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
+index de416f9e79213..f5219334fd3a5 100644
+--- a/drivers/firmware/arm_scmi/base.c
++++ b/drivers/firmware/arm_scmi/base.c
+@@ -34,6 +34,12 @@ struct scmi_msg_resp_base_attributes {
+ __le16 reserved;
+ };
+
++struct scmi_msg_resp_base_discover_agent {
++ __le32 agent_id;
++ u8 name[SCMI_MAX_STR_SIZE];
++};
++
++
+ struct scmi_msg_base_error_notify {
+ __le32 event_control;
+ #define BASE_TP_NOTIFY_ALL BIT(0)
+@@ -225,18 +231,21 @@ static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
+ int id, char *name)
+ {
+ int ret;
++ struct scmi_msg_resp_base_discover_agent *agent_info;
+ struct scmi_xfer *t;
+
+ ret = ph->xops->xfer_get_init(ph, BASE_DISCOVER_AGENT,
+- sizeof(__le32), SCMI_MAX_STR_SIZE, &t);
++ sizeof(__le32), sizeof(*agent_info), &t);
+ if (ret)
+ return ret;
+
+ put_unaligned_le32(id, t->tx.buf);
+
+ ret = ph->xops->do_xfer(ph, t);
+- if (!ret)
+- strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
++ if (!ret) {
++ agent_info = t->rx.buf;
++ strlcpy(name, agent_info->name, SCMI_MAX_STR_SIZE);
++ }
+
+ ph->xops->xfer_put(ph, t);
+
+diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c
+index 4371fdcd5a73f..581d34c957695 100644
+--- a/drivers/firmware/arm_scmi/scmi_pm_domain.c
++++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c
+@@ -138,9 +138,7 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
+ scmi_pd_data->domains = domains;
+ scmi_pd_data->num_domains = num_domains;
+
+- of_genpd_add_provider_onecell(np, scmi_pd_data);
+-
+- return 0;
++ return of_genpd_add_provider_onecell(np, scmi_pd_data);
+ }
+
+ static const struct scmi_device_id scmi_id_table[] = {
+diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
+index 308471586381f..cdbb287bd8bcd 100644
+--- a/drivers/firmware/arm_scmi/sensors.c
++++ b/drivers/firmware/arm_scmi/sensors.c
+@@ -637,7 +637,7 @@ static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph,
+ if (ret)
+ return ret;
+
+- put_unaligned_le32(cpu_to_le32(sensor_id), t->tx.buf);
++ put_unaligned_le32(sensor_id, t->tx.buf);
+ ret = ph->xops->do_xfer(ph, t);
+ if (!ret) {
+ struct sensors_info *si = ph->get_priv(ph);
+diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c
+index 11e8efb713751..87039c5c03fdb 100644
+--- a/drivers/firmware/arm_scmi/virtio.c
++++ b/drivers/firmware/arm_scmi/virtio.c
+@@ -82,7 +82,8 @@ static bool scmi_vio_have_vq_rx(struct virtio_device *vdev)
+ }
+
+ static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
+- struct scmi_vio_msg *msg)
++ struct scmi_vio_msg *msg,
++ struct device *dev)
+ {
+ struct scatterlist sg_in;
+ int rc;
+@@ -94,8 +95,7 @@ static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
+
+ rc = virtqueue_add_inbuf(vioch->vqueue, &sg_in, 1, msg, GFP_ATOMIC);
+ if (rc)
+- dev_err_once(vioch->cinfo->dev,
+- "failed to add to virtqueue (%d)\n", rc);
++ dev_err_once(dev, "failed to add to virtqueue (%d)\n", rc);
+ else
+ virtqueue_kick(vioch->vqueue);
+
+@@ -108,7 +108,7 @@ static void scmi_finalize_message(struct scmi_vio_channel *vioch,
+ struct scmi_vio_msg *msg)
+ {
+ if (vioch->is_rx) {
+- scmi_vio_feed_vq_rx(vioch, msg);
++ scmi_vio_feed_vq_rx(vioch, msg, vioch->cinfo->dev);
+ } else {
+ /* Here IRQs are assumed to be already disabled by the caller */
+ spin_lock(&vioch->lock);
+@@ -269,7 +269,7 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
+ list_add_tail(&msg->list, &vioch->free_list);
+ spin_unlock_irqrestore(&vioch->lock, flags);
+ } else {
+- scmi_vio_feed_vq_rx(vioch, msg);
++ scmi_vio_feed_vq_rx(vioch, msg, cinfo->dev);
+ }
+ }
+
+diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
+index a5048956a0be9..ac08e819088bb 100644
+--- a/drivers/firmware/arm_scmi/voltage.c
++++ b/drivers/firmware/arm_scmi/voltage.c
+@@ -156,7 +156,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
+ int cnt;
+
+ cmd->domain_id = cpu_to_le32(v->id);
+- cmd->level_index = desc_index;
++ cmd->level_index = cpu_to_le32(desc_index);
+ ret = ph->xops->do_xfer(ph, tl);
+ if (ret)
+ break;
+diff --git a/drivers/firmware/psci/psci_checker.c b/drivers/firmware/psci/psci_checker.c
+index 9a369a2eda71d..116eb465cdb42 100644
+--- a/drivers/firmware/psci/psci_checker.c
++++ b/drivers/firmware/psci/psci_checker.c
+@@ -155,7 +155,7 @@ static int alloc_init_cpu_groups(cpumask_var_t **pcpu_groups)
+ 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) {
+ free_cpumask_var(tmp);
+diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
+index 2ee97bab74409..27a64de919817 100644
+--- a/drivers/firmware/qcom_scm.c
++++ b/drivers/firmware/qcom_scm.c
+@@ -252,7 +252,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+ break;
+ default:
+ pr_err("Unknown SMC convention being used\n");
+- return -EINVAL;
++ return false;
+ }
+
+ ret = qcom_scm_call(dev, &desc, &res);
+diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/firmware/scpi_pm_domain.c
+index 51201600d789b..800673910b511 100644
+--- a/drivers/firmware/scpi_pm_domain.c
++++ b/drivers/firmware/scpi_pm_domain.c
+@@ -16,7 +16,6 @@ struct scpi_pm_domain {
+ struct generic_pm_domain genpd;
+ struct scpi_ops *ops;
+ u32 domain;
+- char name[30];
+ };
+
+ /*
+@@ -110,8 +109,13 @@ static int scpi_pm_domain_probe(struct platform_device *pdev)
+
+ 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;
+
+diff --git a/drivers/firmware/smccc/soc_id.c b/drivers/firmware/smccc/soc_id.c
+index 581aa5e9b0778..dd7c3d5e8b0bb 100644
+--- a/drivers/firmware/smccc/soc_id.c
++++ b/drivers/firmware/smccc/soc_id.c
+@@ -50,7 +50,7 @@ static int __init smccc_soc_init(void)
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_SOC_ID, &res);
+
+- if (res.a0 == SMCCC_RET_NOT_SUPPORTED) {
++ if ((int)res.a0 == SMCCC_RET_NOT_SUPPORTED) {
+ pr_info("ARCH_SOC_ID not implemented, skipping ....\n");
+ return 0;
+ }
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index fae5141251e5d..947474f6abb45 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -523,6 +523,7 @@ config GPIO_REG
+ config GPIO_ROCKCHIP
+ tristate "Rockchip GPIO support"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
++ select GENERIC_IRQ_CHIP
+ select GPIOLIB_IRQCHIP
+ default ARCH_ROCKCHIP
+ help
+diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c
+index eeeb39bc171dc..bd75401b549d1 100644
+--- a/drivers/gpio/gpio-realtek-otto.c
++++ b/drivers/gpio/gpio-realtek-otto.c
+@@ -205,7 +205,7 @@ static void realtek_gpio_irq_handler(struct irq_desc *desc)
+ status = realtek_gpio_read_isr(ctrl, lines_done / 8);
+ port_pin_count = min(gc->ngpio - lines_done, 8U);
+ for_each_set_bit(offset, &status, port_pin_count)
+- generic_handle_domain_irq(gc->irq.domain, offset);
++ generic_handle_domain_irq(gc->irq.domain, offset + lines_done);
+ }
+
+ chained_irq_exit(irq_chip, desc);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 269437b013280..289c7dc053634 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -1078,8 +1078,6 @@ struct amdgpu_device {
+ char product_name[32];
+ char serial[20];
+
+- struct amdgpu_autodump autodump;
+-
+ atomic_t throttling_logging_enabled;
+ struct ratelimit_state throttling_logging_rs;
+ uint32_t ras_hw_enabled;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+index 054c1a224defb..ab36cce59d2e4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+@@ -1393,7 +1393,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
+ struct sg_table *sg = NULL;
+ uint64_t user_addr = 0;
+ struct amdgpu_bo *bo;
+- struct drm_gem_object *gobj;
++ struct drm_gem_object *gobj = NULL;
+ u32 domain, alloc_domain;
+ u64 alloc_flags;
+ int ret;
+@@ -1503,14 +1503,16 @@ allocate_init_user_pages_failed:
+ remove_kgd_mem_from_kfd_bo_list(*mem, avm->process_info);
+ drm_vma_node_revoke(&gobj->vma_node, drm_priv);
+ err_node_allow:
+- amdgpu_bo_unref(&bo);
+ /* Don't unreserve system mem limit twice */
+ goto err_reserve_limit;
+ err_bo_create:
+ unreserve_mem_limit(adev, size, alloc_domain, !!sg);
+ err_reserve_limit:
+ mutex_destroy(&(*mem)->lock);
+- kfree(*mem);
++ if (gobj)
++ drm_gem_object_put(gobj);
++ else
++ kfree(*mem);
+ err:
+ if (sg) {
+ sg_free_table(sg);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+index 15c45b2a39835..714178f1b6c6e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+@@ -61,7 +61,7 @@ static void amdgpu_bo_list_free(struct kref *ref)
+
+ 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;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+index c905a4cfc173d..044b41f0bfd9c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+@@ -61,7 +61,7 @@ int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
+ 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 *
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+index b9c11c2b2885a..0de66f59adb8a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+@@ -827,6 +827,7 @@ static int amdgpu_connector_vga_get_modes(struct drm_connector *connector)
+
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
++ amdgpu_get_native_mode(connector);
+
+ return ret;
+ }
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+index 463b9c0283f7e..ec30d81586a79 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+@@ -27,7 +27,6 @@
+ #include <linux/pci.h>
+ #include <linux/uaccess.h>
+ #include <linux/pm_runtime.h>
+-#include <linux/poll.h>
+
+ #include "amdgpu.h"
+ #include "amdgpu_pm.h"
+@@ -37,85 +36,7 @@
+ #include "amdgpu_securedisplay.h"
+ #include "amdgpu_fw_attestation.h"
+
+-int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
+-{
+ #if defined(CONFIG_DEBUG_FS)
+- unsigned long timeout = 600 * HZ;
+- int ret;
+-
+- wake_up_interruptible(&adev->autodump.gpu_hang);
+-
+- ret = wait_for_completion_interruptible_timeout(&adev->autodump.dumping, timeout);
+- if (ret == 0) {
+- pr_err("autodump: timeout, move on to gpu recovery\n");
+- return -ETIMEDOUT;
+- }
+-#endif
+- return 0;
+-}
+-
+-#if defined(CONFIG_DEBUG_FS)
+-
+-static int amdgpu_debugfs_autodump_open(struct inode *inode, struct file *file)
+-{
+- struct amdgpu_device *adev = inode->i_private;
+- int ret;
+-
+- file->private_data = adev;
+-
+- ret = down_read_killable(&adev->reset_sem);
+- if (ret)
+- return ret;
+-
+- if (adev->autodump.dumping.done) {
+- reinit_completion(&adev->autodump.dumping);
+- ret = 0;
+- } else {
+- ret = -EBUSY;
+- }
+-
+- up_read(&adev->reset_sem);
+-
+- return ret;
+-}
+-
+-static int amdgpu_debugfs_autodump_release(struct inode *inode, struct file *file)
+-{
+- struct amdgpu_device *adev = file->private_data;
+-
+- complete_all(&adev->autodump.dumping);
+- return 0;
+-}
+-
+-static unsigned int amdgpu_debugfs_autodump_poll(struct file *file, struct poll_table_struct *poll_table)
+-{
+- struct amdgpu_device *adev = file->private_data;
+-
+- poll_wait(file, &adev->autodump.gpu_hang, poll_table);
+-
+- if (amdgpu_in_reset(adev))
+- return POLLIN | POLLRDNORM | POLLWRNORM;
+-
+- return 0;
+-}
+-
+-static const struct file_operations autodump_debug_fops = {
+- .owner = THIS_MODULE,
+- .open = amdgpu_debugfs_autodump_open,
+- .poll = amdgpu_debugfs_autodump_poll,
+- .release = amdgpu_debugfs_autodump_release,
+-};
+-
+-static void amdgpu_debugfs_autodump_init(struct amdgpu_device *adev)
+-{
+- init_completion(&adev->autodump.dumping);
+- complete_all(&adev->autodump.dumping);
+- init_waitqueue_head(&adev->autodump.gpu_hang);
+-
+- debugfs_create_file("amdgpu_autodump", 0600,
+- adev_to_drm(adev)->primary->debugfs_root,
+- adev, &autodump_debug_fops);
+-}
+
+ /**
+ * amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes
+@@ -1588,7 +1509,6 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
+ }
+
+ amdgpu_ras_debugfs_create_all(adev);
+- amdgpu_debugfs_autodump_init(adev);
+ amdgpu_rap_debugfs_init(adev);
+ amdgpu_securedisplay_debugfs_init(adev);
+ amdgpu_fw_attestation_debugfs_init(adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
+index 141a8474e24f2..8b641f40fdf66 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
+@@ -26,10 +26,6 @@
+ /*
+ * Debugfs
+ */
+-struct amdgpu_autodump {
+- struct completion dumping;
+- struct wait_queue_head gpu_hang;
+-};
+
+ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
+ int amdgpu_debugfs_init(struct amdgpu_device *adev);
+@@ -37,4 +33,3 @@ void amdgpu_debugfs_fini(struct amdgpu_device *adev);
+ void amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
+ void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
+ void amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
+-int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index af9bdf16eefd4..1545884dc703e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -2394,6 +2394,10 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
+ if (r)
+ goto init_failed;
+
++ r = amdgpu_amdkfd_resume_iommu(adev);
++ if (r)
++ goto init_failed;
++
+ r = amdgpu_device_ip_hw_init_phase1(adev);
+ if (r)
+ goto init_failed;
+@@ -2432,10 +2436,6 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
+ if (!adev->gmc.xgmi.pending_reset)
+ amdgpu_amdkfd_device_init(adev);
+
+- r = amdgpu_amdkfd_resume_iommu(adev);
+- if (r)
+- goto init_failed;
+-
+ amdgpu_fru_get_product_info(adev);
+
+ init_failed:
+@@ -2745,6 +2745,11 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
+ adev->ip_blocks[i].status.hw = false;
+ }
+
++ if (amdgpu_sriov_vf(adev)) {
++ if (amdgpu_virt_release_full_gpu(adev, false))
++ DRM_ERROR("failed to release exclusive mode on fini\n");
++ }
++
+ return 0;
+ }
+
+@@ -2805,10 +2810,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
+
+ amdgpu_ras_fini(adev);
+
+- if (amdgpu_sriov_vf(adev))
+- if (amdgpu_virt_release_full_gpu(adev, false))
+- DRM_ERROR("failed to release exclusive mode on fini\n");
+-
+ return 0;
+ }
+
+@@ -3531,6 +3532,9 @@ int amdgpu_device_init(struct amdgpu_device *adev,
+ adev->rmmio_size = pci_resource_len(adev->pdev, 2);
+ }
+
++ for (i = 0; i < AMD_IP_BLOCK_TYPE_NUM; i++)
++ atomic_set(&adev->pm.pwr_state[i], POWER_STATE_UNKNOWN);
++
+ adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
+ if (adev->rmmio == NULL) {
+ return -ENOMEM;
+@@ -3850,7 +3854,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
+ /* disable all interrupts */
+ amdgpu_irq_disable_all(adev);
+ if (adev->mode_info.mode_config_initialized){
+- if (!amdgpu_device_has_dc_support(adev))
++ if (!drm_drv_uses_atomic_modeset(adev_to_drm(adev)))
+ drm_helper_force_disable_all(adev_to_drm(adev));
+ else
+ drm_atomic_helper_shutdown(adev_to_drm(adev));
+@@ -3876,8 +3880,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
+
+ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
+ {
+- amdgpu_device_ip_fini(adev);
+ amdgpu_fence_driver_sw_fini(adev);
++ amdgpu_device_ip_fini(adev);
+ release_firmware(adev->firmware.gpu_info_fw);
+ adev->firmware.gpu_info_fw = NULL;
+ adev->accel_working = false;
+@@ -4466,10 +4470,6 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
+ if (reset_context->reset_req_dev == adev)
+ job = reset_context->job;
+
+- /* no need to dump if device is not in good state during probe period */
+- if (!adev->gmc.xgmi.pending_reset)
+- amdgpu_debugfs_wait_dump(adev);
+-
+ if (amdgpu_sriov_vf(adev)) {
+ /* stop the data exchange thread */
+ amdgpu_virt_fini_data_exchange(adev);
+@@ -5130,7 +5130,7 @@ skip_hw_reset:
+ drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res);
+ }
+
+- if (!amdgpu_device_has_dc_support(tmp_adev) && !job_signaled) {
++ if (!drm_drv_uses_atomic_modeset(adev_to_drm(tmp_adev)) && !job_signaled) {
+ drm_helper_resume_force_mode(adev_to_drm(tmp_adev));
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+index d6aa032890ee8..a1e63ba4c54a5 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+@@ -61,7 +61,7 @@ static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf)
+ }
+
+ ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
+- TTM_BO_VM_NUM_PREFAULT, 1);
++ TTM_BO_VM_NUM_PREFAULT);
+
+ drm_dev_exit(idx);
+ } else {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
+index f3d62e196901a..0c7963dfacad1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
+@@ -223,7 +223,7 @@ int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
+ */
+ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
+ {
+- unsigned int count = AMDGPU_IH_MAX_NUM_IVS;
++ unsigned int count;
+ u32 wptr;
+
+ if (!ih->enabled || adev->shutdown)
+@@ -232,6 +232,7 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
+ wptr = amdgpu_ih_get_wptr(adev, ih);
+
+ restart_ih:
++ count = AMDGPU_IH_MAX_NUM_IVS;
+ DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, ih->rptr, wptr);
+
+ /* Order reading of wptr vs. reading of IH ring data */
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+index ce982afeff913..ac9a8cd21c4b6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+@@ -504,8 +504,8 @@ static int amdgpu_vkms_sw_fini(void *handle)
+ int i = 0;
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++)
+- if (adev->mode_info.crtcs[i])
+- hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);
++ if (adev->amdgpu_vkms_output[i].vblank_hrtimer.function)
++ hrtimer_cancel(&adev->amdgpu_vkms_output[i].vblank_hrtimer);
+
+ kfree(adev->mode_info.bios_hardcoded_edid);
+ kfree(adev->amdgpu_vkms_output);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+index 978ac927ac11d..a799e0b1ff736 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+@@ -386,6 +386,7 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
+ "%s", "xgmi_hive_info");
+ if (ret) {
+ dev_err(adev->dev, "XGMI: failed initializing kobject for xgmi hive\n");
++ kobject_put(&hive->kobj);
+ kfree(hive);
+ hive = NULL;
+ goto pro_end;
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+index 16dbe593cba2e..970d59a21005a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+@@ -7729,8 +7729,19 @@ static uint64_t gfx_v10_0_get_gpu_clock_counter(struct amdgpu_device *adev)
+ switch (adev->asic_type) {
+ case CHIP_VANGOGH:
+ case CHIP_YELLOW_CARP:
+- clock = (uint64_t)RREG32_SOC15(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Vangogh) |
+- ((uint64_t)RREG32_SOC15(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Vangogh) << 32ULL);
++ preempt_disable();
++ clock_hi = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Vangogh);
++ clock_lo = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Vangogh);
++ hi_check = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Vangogh);
++ /* The SMUIO TSC clock frequency is 100MHz, which sets 32-bit carry over
++ * roughly every 42 seconds.
++ */
++ if (hi_check != clock_hi) {
++ clock_lo = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Vangogh);
++ clock_hi = hi_check;
++ }
++ preempt_enable();
++ clock = clock_lo | (clock_hi << 32ULL);
+ break;
+ default:
+ preempt_disable();
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index 025184a556ee6..c39e53a41f13a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -140,6 +140,11 @@ MODULE_FIRMWARE("amdgpu/aldebaran_rlc.bin");
+ #define mmTCP_CHAN_STEER_5_ARCT 0x0b0c
+ #define mmTCP_CHAN_STEER_5_ARCT_BASE_IDX 0
+
++#define mmGOLDEN_TSC_COUNT_UPPER_Renoir 0x0025
++#define mmGOLDEN_TSC_COUNT_UPPER_Renoir_BASE_IDX 1
++#define mmGOLDEN_TSC_COUNT_LOWER_Renoir 0x0026
++#define mmGOLDEN_TSC_COUNT_LOWER_Renoir_BASE_IDX 1
++
+ enum ta_ras_gfx_subblock {
+ /*CPC*/
+ TA_RAS_BLOCK__GFX_CPC_INDEX_START = 0,
+@@ -3056,8 +3061,8 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev)
+ 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);
+ }
+ }
+@@ -4228,19 +4233,38 @@ failed_kiq_read:
+
+ static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev)
+ {
+- uint64_t clock;
++ uint64_t clock, clock_lo, clock_hi, hi_check;
+
+- amdgpu_gfx_off_ctrl(adev, false);
+- mutex_lock(&adev->gfx.gpu_clock_mutex);
+- if (adev->asic_type == CHIP_VEGA10 && amdgpu_sriov_runtime(adev)) {
+- clock = gfx_v9_0_kiq_read_clock(adev);
+- } else {
+- 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);
++ switch (adev->asic_type) {
++ case CHIP_RENOIR:
++ preempt_disable();
++ clock_hi = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Renoir);
++ clock_lo = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Renoir);
++ hi_check = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Renoir);
++ /* The SMUIO TSC clock frequency is 100MHz, which sets 32-bit carry over
++ * roughly every 42 seconds.
++ */
++ if (hi_check != clock_hi) {
++ clock_lo = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Renoir);
++ clock_hi = hi_check;
++ }
++ preempt_enable();
++ clock = clock_lo | (clock_hi << 32ULL);
++ break;
++ default:
++ amdgpu_gfx_off_ctrl(adev, false);
++ mutex_lock(&adev->gfx.gpu_clock_mutex);
++ if (adev->asic_type == CHIP_VEGA10 && amdgpu_sriov_runtime(adev)) {
++ clock = gfx_v9_0_kiq_read_clock(adev);
++ } else {
++ 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);
++ break;
+ }
+- mutex_unlock(&adev->gfx.gpu_clock_mutex);
+- amdgpu_gfx_off_ctrl(adev, true);
+ return clock;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+index bda1542ef1ddf..f51fd0688eca7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+@@ -162,7 +162,6 @@ static void gfxhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC);/* XXX for emulation. */
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
+index 14c1c1a297dd3..6e0ace2fbfab1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
+@@ -196,7 +196,6 @@ static void gfxhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC); /* UC, uncached */
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
+index 1a374ec0514a5..9328991e8807f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
+@@ -197,7 +197,6 @@ static void gfxhub_v2_1_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC); /* UC, uncached */
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+index 0e81e03e9b498..0fe714f54cca9 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+@@ -841,12 +841,12 @@ static int gmc_v6_0_sw_init(void *handle)
+
+ 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, "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) {
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+index a99953833820e..b3bede1dc41da 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+@@ -145,7 +145,6 @@ static void mmhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC);/* XXX for emulation. */
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
+index f80a14a1b82dc..f5f7181f9af5f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
+@@ -165,7 +165,6 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC);/* XXX for emulation. */
+ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+index 7ded6b2f058ef..2e58ed2caa485 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+@@ -269,7 +269,6 @@ static void mmhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC); /* UC, uncached */
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+index 88e457a150e02..c63b6b9349350 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+@@ -194,7 +194,6 @@ static void mmhub_v2_3_init_tlb_regs(struct amdgpu_device *adev)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC); /* UC, uncached */
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+index c4ef822bbe8c5..ff49eeaf78824 100644
+--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+@@ -189,8 +189,6 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid)
+ ENABLE_ADVANCED_DRIVER_MODEL, 1);
+ tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
+ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
+- tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
+- ECO_BITS, 0);
+ tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
+ MTYPE, MTYPE_UC);/* XXX for emulation. */
+ tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
+diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
+index 7232241e3bfb2..0fef925b66024 100644
+--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
+@@ -698,6 +698,19 @@ static int uvd_v3_1_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->uvd.idle_work);
++
++ if (RREG32(mmUVD_STATUS) != 0)
++ uvd_v3_1_stop(adev);
++
++ return 0;
++}
++
++static int uvd_v3_1_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -722,17 +735,6 @@ static int uvd_v3_1_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- if (RREG32(mmUVD_STATUS) != 0)
+- uvd_v3_1_stop(adev);
+-
+- return 0;
+-}
+-
+-static int uvd_v3_1_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = uvd_v3_1_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+index 52d6de969f462..c108b83817951 100644
+--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+@@ -212,6 +212,19 @@ static int uvd_v4_2_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->uvd.idle_work);
++
++ if (RREG32(mmUVD_STATUS) != 0)
++ uvd_v4_2_stop(adev);
++
++ return 0;
++}
++
++static int uvd_v4_2_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -236,17 +249,6 @@ static int uvd_v4_2_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- if (RREG32(mmUVD_STATUS) != 0)
+- uvd_v4_2_stop(adev);
+-
+- return 0;
+-}
+-
+-static int uvd_v4_2_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = uvd_v4_2_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+index db6d06758e4d4..563493d1f8306 100644
+--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+@@ -210,6 +210,19 @@ static int uvd_v5_0_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->uvd.idle_work);
++
++ if (RREG32(mmUVD_STATUS) != 0)
++ uvd_v5_0_stop(adev);
++
++ return 0;
++}
++
++static int uvd_v5_0_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -234,17 +247,6 @@ static int uvd_v5_0_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- if (RREG32(mmUVD_STATUS) != 0)
+- uvd_v5_0_stop(adev);
+-
+- return 0;
+-}
+-
+-static int uvd_v5_0_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = uvd_v5_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+index bc571833632ea..72f8762907681 100644
+--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+@@ -543,6 +543,19 @@ static int uvd_v6_0_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->uvd.idle_work);
++
++ if (RREG32(mmUVD_STATUS) != 0)
++ uvd_v6_0_stop(adev);
++
++ return 0;
++}
++
++static int uvd_v6_0_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -567,17 +580,6 @@ static int uvd_v6_0_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- if (RREG32(mmUVD_STATUS) != 0)
+- uvd_v6_0_stop(adev);
+-
+- return 0;
+-}
+-
+-static int uvd_v6_0_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = uvd_v6_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
+index b6e82d75561f6..1fd9ca21a091b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
+@@ -606,6 +606,23 @@ static int uvd_v7_0_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->uvd.idle_work);
++
++ if (!amdgpu_sriov_vf(adev))
++ uvd_v7_0_stop(adev);
++ else {
++ /* full access mode, so don't touch any UVD register */
++ DRM_DEBUG("For SRIOV client, shouldn't do anything.\n");
++ }
++
++ return 0;
++}
++
++static int uvd_v7_0_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -630,21 +647,6 @@ static int uvd_v7_0_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- if (!amdgpu_sriov_vf(adev))
+- uvd_v7_0_stop(adev);
+- else {
+- /* full access mode, so don't touch any UVD register */
+- DRM_DEBUG("For SRIOV client, shouldn't do anything.\n");
+- }
+-
+- return 0;
+-}
+-
+-static int uvd_v7_0_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = uvd_v7_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+index b70c17f0c52e8..98952fd387e73 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+@@ -479,6 +479,17 @@ static int vce_v2_0_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->vce.idle_work);
++
++ return 0;
++}
++
++static int vce_v2_0_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -502,14 +513,6 @@ static int vce_v2_0_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- return 0;
+-}
+-
+-static int vce_v2_0_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = vce_v2_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+index 9de66893ccd6d..8fb5df7181e09 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+@@ -490,6 +490,21 @@ static int vce_v3_0_hw_fini(void *handle)
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ cancel_delayed_work_sync(&adev->vce.idle_work);
++
++ r = vce_v3_0_wait_for_idle(handle);
++ if (r)
++ return r;
++
++ vce_v3_0_stop(adev);
++ return vce_v3_0_set_clockgating_state(adev, AMD_CG_STATE_GATE);
++}
++
++static int vce_v3_0_suspend(void *handle)
++{
++ int r;
++ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++
+ /*
+ * Proper cleanups before halting the HW engine:
+ * - cancel the delayed idle work
+@@ -513,19 +528,6 @@ static int vce_v3_0_hw_fini(void *handle)
+ AMD_CG_STATE_GATE);
+ }
+
+- r = vce_v3_0_wait_for_idle(handle);
+- if (r)
+- return r;
+-
+- vce_v3_0_stop(adev);
+- return vce_v3_0_set_clockgating_state(adev, AMD_CG_STATE_GATE);
+-}
+-
+-static int vce_v3_0_suspend(void *handle)
+-{
+- int r;
+- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+-
+ r = vce_v3_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
+index fec902b800c28..70b8c88d30513 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
+@@ -542,29 +542,8 @@ static int vce_v4_0_hw_fini(void *handle)
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+- /*
+- * Proper cleanups before halting the HW engine:
+- * - cancel the delayed idle work
+- * - enable powergating
+- * - enable clockgating
+- * - disable dpm
+- *
+- * TODO: to align with the VCN implementation, move the
+- * jobs for clockgating/powergating/dpm setting to
+- * ->set_powergating_state().
+- */
+ cancel_delayed_work_sync(&adev->vce.idle_work);
+
+- if (adev->pm.dpm_enabled) {
+- amdgpu_dpm_enable_vce(adev, false);
+- } else {
+- amdgpu_asic_set_vce_clocks(adev, 0, 0);
+- amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+- AMD_PG_STATE_GATE);
+- amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+- AMD_CG_STATE_GATE);
+- }
+-
+ if (!amdgpu_sriov_vf(adev)) {
+ /* vce_v4_0_wait_for_idle(handle); */
+ vce_v4_0_stop(adev);
+@@ -594,6 +573,29 @@ static int vce_v4_0_suspend(void *handle)
+ drm_dev_exit(idx);
+ }
+
++ /*
++ * Proper cleanups before halting the HW engine:
++ * - cancel the delayed idle work
++ * - enable powergating
++ * - enable clockgating
++ * - disable dpm
++ *
++ * TODO: to align with the VCN implementation, move the
++ * jobs for clockgating/powergating/dpm setting to
++ * ->set_powergating_state().
++ */
++ cancel_delayed_work_sync(&adev->vce.idle_work);
++
++ if (adev->pm.dpm_enabled) {
++ amdgpu_dpm_enable_vce(adev, false);
++ } else {
++ amdgpu_asic_set_vce_clocks(adev, 0, 0);
++ amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
++ AMD_PG_STATE_GATE);
++ amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
++ AMD_CG_STATE_GATE);
++ }
++
+ r = vce_v4_0_hw_fini(adev);
+ if (r)
+ return r;
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+index f4686e918e0d1..c405075a572c1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+@@ -22,6 +22,7 @@
+ */
+
+ #include <linux/firmware.h>
++#include <drm/drm_drv.h>
+
+ #include "amdgpu.h"
+ #include "amdgpu_vcn.h"
+@@ -192,11 +193,14 @@ static int vcn_v2_0_sw_init(void *handle)
+ */
+ static int vcn_v2_0_sw_fini(void *handle)
+ {
+- int r;
++ int r, idx;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst->fw_shared_cpu_addr;
+
+- fw_shared->present_flag_0 = 0;
++ if (drm_dev_enter(&adev->ddev, &idx)) {
++ fw_shared->present_flag_0 = 0;
++ drm_dev_exit(idx);
++ }
+
+ amdgpu_virt_free_mm_table(adev);
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+index e0c0c3734432e..a0956d8623770 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+@@ -22,6 +22,7 @@
+ */
+
+ #include <linux/firmware.h>
++#include <drm/drm_drv.h>
+
+ #include "amdgpu.h"
+ #include "amdgpu_vcn.h"
+@@ -233,17 +234,21 @@ static int vcn_v2_5_sw_init(void *handle)
+ */
+ static int vcn_v2_5_sw_fini(void *handle)
+ {
+- int i, r;
++ int i, r, idx;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ volatile struct amdgpu_fw_shared *fw_shared;
+
+- for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+- if (adev->vcn.harvest_config & (1 << i))
+- continue;
+- fw_shared = adev->vcn.inst[i].fw_shared_cpu_addr;
+- fw_shared->present_flag_0 = 0;
++ if (drm_dev_enter(&adev->ddev, &idx)) {
++ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
++ if (adev->vcn.harvest_config & (1 << i))
++ continue;
++ fw_shared = adev->vcn.inst[i].fw_shared_cpu_addr;
++ fw_shared->present_flag_0 = 0;
++ }
++ drm_dev_exit(idx);
+ }
+
++
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_virt_free_mm_table(adev);
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index 4a416231b24c8..88c483f699894 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -916,6 +916,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
+ kfd_double_confirm_iommu_support(kfd);
+
+ if (kfd_iommu_device_init(kfd)) {
++ kfd->use_iommu_v2 = false;
+ dev_err(kfd_device, "Error initializing iommuv2\n");
+ goto device_iommu_error;
+ }
+@@ -924,6 +925,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
+
+ svm_migrate_init((struct amdgpu_device *)kfd->kgd);
+
++ if(kgd2kfd_resume_iommu(kfd))
++ goto device_iommu_error;
++
+ if (kfd_resume(kfd))
+ goto kfd_resume_error;
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+index f8fce9d05f50c..4f2e0cc8a51a8 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -1225,6 +1225,11 @@ static int stop_cpsch(struct device_queue_manager *dqm)
+ bool hanging;
+
+ dqm_lock(dqm);
++ if (!dqm->sched_running) {
++ dqm_unlock(dqm);
++ return 0;
++ }
++
+ if (!dqm->is_hws_hang)
+ unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0);
+ hanging = dqm->is_hws_hang || dqm->is_resetting;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+index 9d0f65a90002d..5a674235ae41a 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+@@ -1307,7 +1307,7 @@ struct svm_validate_context {
+ struct svm_range *prange;
+ bool intr;
+ unsigned long bitmap[MAX_GPU_INSTANCE];
+- struct ttm_validate_buffer tv[MAX_GPU_INSTANCE+1];
++ struct ttm_validate_buffer tv[MAX_GPU_INSTANCE];
+ struct list_head validate_list;
+ struct ww_acquire_ctx ticket;
+ };
+@@ -1334,11 +1334,6 @@ static int svm_range_reserve_bos(struct svm_validate_context *ctx)
+ ctx->tv[gpuidx].num_shared = 4;
+ list_add(&ctx->tv[gpuidx].head, &ctx->validate_list);
+ }
+- if (ctx->prange->svm_bo && ctx->prange->ttm_res) {
+- ctx->tv[MAX_GPU_INSTANCE].bo = &ctx->prange->svm_bo->bo->tbo;
+- ctx->tv[MAX_GPU_INSTANCE].num_shared = 1;
+- list_add(&ctx->tv[MAX_GPU_INSTANCE].head, &ctx->validate_list);
+- }
+
+ r = ttm_eu_reserve_buffers(&ctx->ticket, &ctx->validate_list,
+ ctx->intr, NULL);
+@@ -1570,7 +1565,6 @@ retry_flush_work:
+ static void svm_range_restore_work(struct work_struct *work)
+ {
+ struct delayed_work *dwork = to_delayed_work(work);
+- struct amdkfd_process_info *process_info;
+ struct svm_range_list *svms;
+ struct svm_range *prange;
+ struct kfd_process *p;
+@@ -1590,12 +1584,10 @@ static void svm_range_restore_work(struct work_struct *work)
+ * the lifetime of this thread, kfd_process and mm will be valid.
+ */
+ p = container_of(svms, struct kfd_process, svms);
+- process_info = p->kgd_process_info;
+ mm = p->mm;
+ if (!mm)
+ return;
+
+- mutex_lock(&process_info->lock);
+ svm_range_list_lock_and_flush_work(svms, mm);
+ mutex_lock(&svms->lock);
+
+@@ -1648,7 +1640,6 @@ static void svm_range_restore_work(struct work_struct *work)
+ out_reschedule:
+ mutex_unlock(&svms->lock);
+ mmap_write_unlock(mm);
+- mutex_unlock(&process_info->lock);
+
+ /* If validation failed, reschedule another attempt */
+ if (evicted_ranges) {
+@@ -2979,7 +2970,6 @@ static int
+ svm_range_set_attr(struct kfd_process *p, uint64_t start, uint64_t size,
+ uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs)
+ {
+- struct amdkfd_process_info *process_info = p->kgd_process_info;
+ struct mm_struct *mm = current->mm;
+ struct list_head update_list;
+ struct list_head insert_list;
+@@ -2998,8 +2988,6 @@ svm_range_set_attr(struct kfd_process *p, uint64_t start, uint64_t size,
+
+ svms = &p->svms;
+
+- mutex_lock(&process_info->lock);
+-
+ svm_range_list_lock_and_flush_work(svms, mm);
+
+ if (!svm_range_is_valid(mm, start, size)) {
+@@ -3075,8 +3063,6 @@ out_unlock_range:
+ mutex_unlock(&svms->lock);
+ mmap_read_unlock(mm);
+ out:
+- mutex_unlock(&process_info->lock);
+-
+ pr_debug("pasid 0x%x svms 0x%p [0x%llx 0x%llx] done, r=%d\n", p->pasid,
+ &p->svms, start, start + size - 1, r);
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 1ea31dcc7a8b0..fef13e93a99fd 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -1141,8 +1141,15 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
+ case CHIP_RAVEN:
+ case CHIP_RENOIR:
+ init_data.flags.gpu_vm_support = true;
+- if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
++ switch (adev->dm.dmcub_fw_version) {
++ case 0: /* development */
++ case 0x1: /* linux-firmware.git hash 6d9f399 */
++ case 0x01000000: /* linux-firmware.git hash 9a0b0f4 */
++ init_data.flags.disable_dmcu = false;
++ break;
++ default:
+ init_data.flags.disable_dmcu = true;
++ }
+ break;
+ case CHIP_VANGOGH:
+ case CHIP_YELLOW_CARP:
+@@ -2206,6 +2213,9 @@ static int dm_resume(void *handle)
+ if (amdgpu_in_reset(adev)) {
+ dc_state = dm->cached_dc_state;
+
++ if (dc_enable_dmub_notifications(adev->dm.dc))
++ amdgpu_dm_outbox_init(adev);
++
+ r = dm_dmub_hw_init(adev);
+ if (r)
+ DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
+@@ -2217,8 +2227,8 @@ static int dm_resume(void *handle)
+
+ for (i = 0; i < dc_state->stream_count; i++) {
+ dc_state->streams[i]->mode_changed = true;
+- for (j = 0; j < dc_state->stream_status->plane_count; j++) {
+- dc_state->stream_status->plane_states[j]->update_flags.raw
++ for (j = 0; j < dc_state->stream_status[i].plane_count; j++) {
++ dc_state->stream_status[i].plane_states[j]->update_flags.raw
+ = 0xffffffff;
+ }
+ }
+@@ -2253,6 +2263,10 @@ static int dm_resume(void *handle)
+ /* TODO: Remove dc_state->dccg, use dc->dccg directly. */
+ dc_resource_state_construct(dm->dc, dm_state->context);
+
++ /* Re-enable outbox interrupts for DPIA. */
++ if (dc_enable_dmub_notifications(adev->dm.dc))
++ amdgpu_dm_outbox_init(adev);
++
+ /* Before powering on DC we need to re-initialize DMUB. */
+ r = dm_dmub_hw_init(adev);
+ if (r)
+@@ -3839,6 +3853,9 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
+ } else if (dc_link_detect(link, DETECT_REASON_BOOT)) {
+ amdgpu_dm_update_connector_after_detect(aconnector);
+ register_backlight_device(dm, link);
++
++ if (dm->num_of_edps)
++ update_connector_ext_caps(aconnector);
+ if (amdgpu_dc_feature_mask & DC_PSR_MASK)
+ amdgpu_dm_set_psr_caps(link);
+ }
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+index cce062adc4391..8a441a22c46ec 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+@@ -314,6 +314,14 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
+ 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 defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+index 8080bba5b7a76..de9ec5ddb6c72 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+@@ -247,6 +247,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ {
+ struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
+ struct dc_link *link = connector->dc_link;
++ struct dc *dc = (struct dc *)link->dc;
+ struct dc_link_settings prefer_link_settings;
+ char *wr_buf = NULL;
+ const uint32_t wr_buf_size = 40;
+@@ -313,7 +314,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
+ prefer_link_settings.lane_count = param[0];
+ prefer_link_settings.link_rate = param[1];
+
+- dp_retrain_link_dp_test(link, &prefer_link_settings, false);
++ dc_link_set_preferred_training_settings(dc, &prefer_link_settings, NULL, link, true);
+
+ kfree(wr_buf);
+ return size;
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+index 6fee12c91ef59..d793eec69d61e 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+@@ -40,6 +40,39 @@
+
+ #include "dm_helpers.h"
+
++struct monitor_patch_info {
++ unsigned int manufacturer_id;
++ unsigned int product_id;
++ void (*patch_func)(struct dc_edid_caps *edid_caps, unsigned int param);
++ unsigned int patch_param;
++};
++static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param);
++
++static const struct monitor_patch_info monitor_patch_table[] = {
++{0x6D1E, 0x5BBF, set_max_dsc_bpp_limit, 15},
++{0x6D1E, 0x5B9A, set_max_dsc_bpp_limit, 15},
++};
++
++static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param)
++{
++ if (edid_caps)
++ edid_caps->panel_patch.max_dsc_target_bpp_limit = param;
++}
++
++static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps)
++{
++ int i, ret = 0;
++
++ for (i = 0; i < ARRAY_SIZE(monitor_patch_table); i++)
++ if ((edid_caps->manufacturer_id == monitor_patch_table[i].manufacturer_id)
++ && (edid_caps->product_id == monitor_patch_table[i].product_id)) {
++ monitor_patch_table[i].patch_func(edid_caps, monitor_patch_table[i].patch_param);
++ ret++;
++ }
++
++ return ret;
++}
++
+ /* dm_helpers_parse_edid_caps
+ *
+ * Parse edid caps
+@@ -125,6 +158,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
+ kfree(sads);
+ kfree(sadb);
+
++ amdgpu_dm_patch_edid_caps(edid_caps);
++
+ return result;
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+index 7af0d58c231b6..74885ff77f96a 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -36,6 +36,8 @@
+ #include "dm_helpers.h"
+
+ #include "dc_link_ddc.h"
++#include "ddc_service_types.h"
++#include "dpcd_defs.h"
+
+ #include "i2caux_interface.h"
+ #include "dmub_cmd.h"
+@@ -155,6 +157,16 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
+ };
+
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
++static bool needs_dsc_aux_workaround(struct dc_link *link)
++{
++ if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
++ (link->dpcd_caps.dpcd_rev.raw == DPCD_REV_14 || link->dpcd_caps.dpcd_rev.raw == DPCD_REV_12) &&
++ link->dpcd_caps.sink_count.bits.SINK_COUNT >= 2)
++ return true;
++
++ return false;
++}
++
+ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
+ {
+ struct dc_sink *dc_sink = aconnector->dc_sink;
+@@ -164,7 +176,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
+ u8 *dsc_branch_dec_caps = NULL;
+
+ aconnector->dsc_aux = drm_dp_mst_dsc_aux_for_port(port);
+-#if defined(CONFIG_HP_HOOK_WORKAROUND)
++
+ /*
+ * drm_dp_mst_dsc_aux_for_port() will return NULL for certain configs
+ * because it only check the dsc/fec caps of the "port variable" and not the dock
+@@ -174,10 +186,10 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
+ * Workaround: explicitly check the use case above and use the mst dock's aux as dsc_aux
+ *
+ */
+-
+- if (!aconnector->dsc_aux && !port->parent->port_parent)
++ if (!aconnector->dsc_aux && !port->parent->port_parent &&
++ needs_dsc_aux_workaround(aconnector->dc_link))
+ aconnector->dsc_aux = &aconnector->mst_port->dm_dp_aux.aux;
+-#endif
++
+ if (!aconnector->dsc_aux)
+ return false;
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+index 6d655e158267a..61c18637f84dc 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+@@ -4690,7 +4690,7 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready)
+ link_enc->funcs->fec_set_ready(link_enc, true);
+ link->fec_state = dc_link_fec_ready;
+ } else {
+- link_enc->funcs->fec_set_ready(link->link_enc, false);
++ link_enc->funcs->fec_set_ready(link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+ dm_error("dpcd write failed to set fec_ready");
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index a60396d5be445..e94546187cf15 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -1623,6 +1623,10 @@ bool dc_is_stream_unchanged(
+ if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
+ return false;
+
++ // Only Have Audio left to check whether it is same or not. This is a corner case for Tiled sinks
++ if (old_stream->audio_info.mode_count != stream->audio_info.mode_count)
++ return false;
++
+ return true;
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+index df8a7718a85fc..3af49cdf89ebd 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+@@ -1522,7 +1522,7 @@ void dcn10_power_down_on_boot(struct dc *dc)
+ for (i = 0; i < dc->link_count; i++) {
+ struct dc_link *link = dc->links[i];
+
+- if (link->link_enc->funcs->is_dig_enabled &&
++ if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
+ link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
+ dc->hwss.power_down) {
+ dc->hwss.power_down(dc);
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+index e3e01b17c164e..ede11eb120d4f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+@@ -1854,7 +1854,9 @@ static void swizzle_to_dml_params(
+ case DC_SW_VAR_D_X:
+ *sw_mode = dm_sw_var_d_x;
+ break;
+-
++ case DC_SW_VAR_R_X:
++ *sw_mode = dm_sw_var_r_x;
++ break;
+ default:
+ ASSERT(0); /* Not supported */
+ break;
+@@ -3152,7 +3154,7 @@ void dcn20_calculate_dlg_params(
+
+ context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg(&context->bw_ctx.dml,
+ &context->res_ctx.pipe_ctx[i].rq_regs,
+- pipes[pipe_idx].pipe);
++ &pipes[pipe_idx].pipe);
+ pipe_idx++;
+ }
+ }
+@@ -3668,16 +3670,22 @@ static bool init_soc_bounding_box(struct dc *dc,
+ clock_limits_available = (status == PP_SMU_RESULT_OK);
+ }
+
+- if (clock_limits_available && uclk_states_available && num_states)
++ if (clock_limits_available && uclk_states_available && num_states) {
++ DC_FP_START();
+ dcn20_update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states);
+- else if (clock_limits_available)
++ DC_FP_END();
++ } else if (clock_limits_available) {
++ DC_FP_START();
+ dcn20_cap_soc_clocks(loaded_bb, max_clocks);
++ DC_FP_END();
++ }
+ }
+
+ loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator;
+ loaded_ip->max_num_dpp = pool->base.pipe_count;
++ DC_FP_START();
+ dcn20_patch_bounding_box(dc, loaded_bb);
+-
++ DC_FP_END();
+ return true;
+ }
+
+@@ -3697,8 +3705,6 @@ static bool dcn20_resource_construct(
+ enum dml_project dml_project_version =
+ get_dml_project_version(ctx->asic_id.hw_internal_rev);
+
+- DC_FP_START();
+-
+ ctx->dc_bios->regs = &bios_regs;
+ pool->base.funcs = &dcn20_res_pool_funcs;
+
+@@ -4047,12 +4053,10 @@ static bool dcn20_resource_construct(
+ pool->base.oem_device = NULL;
+ }
+
+- DC_FP_END();
+ return true;
+
+ create_fail:
+
+- DC_FP_END();
+ dcn20_resource_destruct(pool);
+
+ return false;
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
+index fafed1e4a998d..0950784bafa49 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
+@@ -1002,7 +1002,8 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc,
+ /* turning off DPG */
+ pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, false);
+ for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
+- mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false);
++ if (mpcc_pipe->plane_res.hubp)
++ mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false);
+
+ stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
+ color_depth, solid_color, width, height, offset);
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+index 40011cd3c8ef0..ac8fb202fd5ee 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+@@ -100,6 +100,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
+ .z10_save_init = dcn31_z10_save_init,
+ .is_abm_supported = dcn31_is_abm_supported,
+ .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
++ .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
+ .update_visual_confirm_color = dcn20_update_visual_confirm_color,
+ };
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c
+index 2091dd8c252da..8c168f348a27f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c
+@@ -768,12 +768,12 @@ static void dml20_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib,
+
+ void dml20_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ display_rq_params_st rq_param = {0};
+
+ memset(rq_regs, 0, sizeof(*rq_regs));
+- dml20_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param.src);
++ dml20_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param->src);
+ extract_rq_regs(mode_lib, rq_regs, rq_param);
+
+ print__rq_regs_st(mode_lib, *rq_regs);
+@@ -1549,7 +1549,7 @@ static void dml20_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib,
+ void dml20_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h
+index d0b90947f5409..8b23867e97c18 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h
+@@ -43,7 +43,7 @@ struct display_mode_lib;
+ void dml20_rq_dlg_get_rq_reg(
+ struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+
+
+ // Function: dml_rq_dlg_get_dlg_reg
+@@ -61,7 +61,7 @@ void dml20_rq_dlg_get_dlg_reg(
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+index 1a0c14e465faa..26ececfd40cdc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+@@ -768,12 +768,12 @@ static void dml20v2_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib,
+
+ void dml20v2_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ display_rq_params_st rq_param = {0};
+
+ memset(rq_regs, 0, sizeof(*rq_regs));
+- dml20v2_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param.src);
++ dml20v2_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param->src);
+ extract_rq_regs(mode_lib, rq_regs, rq_param);
+
+ print__rq_regs_st(mode_lib, *rq_regs);
+@@ -1550,7 +1550,7 @@ static void dml20v2_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib,
+ void dml20v2_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.h
+index 27cf8bed9376f..2b4e46ea1c3df 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.h
+@@ -43,7 +43,7 @@ struct display_mode_lib;
+ void dml20v2_rq_dlg_get_rq_reg(
+ struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+
+
+ // Function: dml_rq_dlg_get_dlg_reg
+@@ -61,7 +61,7 @@ void dml20v2_rq_dlg_get_dlg_reg(
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+index 287e31052b307..736978c4d40a1 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+@@ -694,7 +694,7 @@ static void get_surf_rq_param(
+ display_data_rq_sizing_params_st *rq_sizing_param,
+ display_data_rq_dlg_params_st *rq_dlg_param,
+ display_data_rq_misc_params_st *rq_misc_param,
+- const display_pipe_params_st pipe_param,
++ const display_pipe_params_st *pipe_param,
+ bool is_chroma)
+ {
+ bool mode_422 = false;
+@@ -706,30 +706,30 @@ static void get_surf_rq_param(
+
+ // FIXME check if ppe apply for both luma and chroma in 422 case
+ if (is_chroma) {
+- vp_width = pipe_param.src.viewport_width_c / ppe;
+- vp_height = pipe_param.src.viewport_height_c;
+- data_pitch = pipe_param.src.data_pitch_c;
+- meta_pitch = pipe_param.src.meta_pitch_c;
++ vp_width = pipe_param->src.viewport_width_c / ppe;
++ vp_height = pipe_param->src.viewport_height_c;
++ data_pitch = pipe_param->src.data_pitch_c;
++ meta_pitch = pipe_param->src.meta_pitch_c;
+ } else {
+- vp_width = pipe_param.src.viewport_width / ppe;
+- vp_height = pipe_param.src.viewport_height;
+- data_pitch = pipe_param.src.data_pitch;
+- meta_pitch = pipe_param.src.meta_pitch;
++ vp_width = pipe_param->src.viewport_width / ppe;
++ vp_height = pipe_param->src.viewport_height;
++ data_pitch = pipe_param->src.data_pitch;
++ meta_pitch = pipe_param->src.meta_pitch;
+ }
+
+- if (pipe_param.dest.odm_combine) {
++ if (pipe_param->dest.odm_combine) {
+ unsigned int access_dir;
+ unsigned int full_src_vp_width;
+ unsigned int hactive_half;
+ unsigned int src_hactive_half;
+- access_dir = (pipe_param.src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
+- hactive_half = pipe_param.dest.hactive / 2;
++ access_dir = (pipe_param->src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
++ hactive_half = pipe_param->dest.hactive / 2;
+ if (is_chroma) {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio_c * pipe_param.dest.full_recout_width;
+- src_hactive_half = pipe_param.scale_ratio_depth.hscl_ratio_c * hactive_half;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio_c * pipe_param->dest.full_recout_width;
++ src_hactive_half = pipe_param->scale_ratio_depth.hscl_ratio_c * hactive_half;
+ } else {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio * pipe_param.dest.full_recout_width;
+- src_hactive_half = pipe_param.scale_ratio_depth.hscl_ratio * hactive_half;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio * pipe_param->dest.full_recout_width;
++ src_hactive_half = pipe_param->scale_ratio_depth.hscl_ratio * hactive_half;
+ }
+
+ if (access_dir == 0) {
+@@ -754,7 +754,7 @@ static void get_surf_rq_param(
+ rq_sizing_param->meta_chunk_bytes = 2048;
+ rq_sizing_param->min_meta_chunk_bytes = 256;
+
+- if (pipe_param.src.hostvm)
++ if (pipe_param->src.hostvm)
+ rq_sizing_param->mpte_group_bytes = 512;
+ else
+ rq_sizing_param->mpte_group_bytes = 2048;
+@@ -768,23 +768,23 @@ static void get_surf_rq_param(
+ vp_height,
+ data_pitch,
+ meta_pitch,
+- pipe_param.src.source_format,
+- pipe_param.src.sw_mode,
+- pipe_param.src.macro_tile_size,
+- pipe_param.src.source_scan,
+- pipe_param.src.hostvm,
++ pipe_param->src.source_format,
++ pipe_param->src.sw_mode,
++ pipe_param->src.macro_tile_size,
++ pipe_param->src.source_scan,
++ pipe_param->src.hostvm,
+ is_chroma);
+ }
+
+ static void dml_rq_dlg_get_rq_params(
+ struct display_mode_lib *mode_lib,
+ display_rq_params_st *rq_param,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ // get param for luma surface
+- rq_param->yuv420 = pipe_param.src.source_format == dm_420_8
+- || pipe_param.src.source_format == dm_420_10;
+- rq_param->yuv420_10bpc = pipe_param.src.source_format == dm_420_10;
++ rq_param->yuv420 = pipe_param->src.source_format == dm_420_8
++ || pipe_param->src.source_format == dm_420_10;
++ rq_param->yuv420_10bpc = pipe_param->src.source_format == dm_420_10;
+
+ get_surf_rq_param(
+ mode_lib,
+@@ -794,7 +794,7 @@ static void dml_rq_dlg_get_rq_params(
+ pipe_param,
+ 0);
+
+- if (is_dual_plane((enum source_format_class) (pipe_param.src.source_format))) {
++ if (is_dual_plane((enum source_format_class) (pipe_param->src.source_format))) {
+ // get param for chroma surface
+ get_surf_rq_param(
+ mode_lib,
+@@ -806,14 +806,14 @@ static void dml_rq_dlg_get_rq_params(
+ }
+
+ // calculate how to split the det buffer space between luma and chroma
+- handle_det_buf_split(mode_lib, rq_param, pipe_param.src);
++ handle_det_buf_split(mode_lib, rq_param, pipe_param->src);
+ print__rq_params_st(mode_lib, *rq_param);
+ }
+
+ void dml21_rq_dlg_get_rq_reg(
+ struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ display_rq_params_st rq_param = {0};
+
+@@ -1658,7 +1658,7 @@ void dml21_rq_dlg_get_dlg_reg(
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+@@ -1696,7 +1696,7 @@ void dml21_rq_dlg_get_dlg_reg(
+ // system parameter calculation done
+
+ dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx);
+- dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe);
++ dml_rq_dlg_get_rq_params(mode_lib, &rq_param, &e2e_pipe_param[pipe_idx].pipe);
+ dml_rq_dlg_get_dlg_params(
+ mode_lib,
+ e2e_pipe_param,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h
+index e8f7785e3fc63..af6ad0ca9cf8a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h
+@@ -44,7 +44,7 @@ struct display_mode_lib;
+ void dml21_rq_dlg_get_rq_reg(
+ struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+
+ // Function: dml_rq_dlg_get_dlg_reg
+ // Calculate and return DLG and TTU register struct given the system setting
+@@ -61,7 +61,7 @@ void dml21_rq_dlg_get_dlg_reg(
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c
+index 0d934fae1c3a6..2120e0941a095 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c
+@@ -747,7 +747,7 @@ static void get_surf_rq_param(struct display_mode_lib *mode_lib,
+ display_data_rq_sizing_params_st *rq_sizing_param,
+ display_data_rq_dlg_params_st *rq_dlg_param,
+ display_data_rq_misc_params_st *rq_misc_param,
+- const display_pipe_params_st pipe_param,
++ const display_pipe_params_st *pipe_param,
+ bool is_chroma,
+ bool is_alpha)
+ {
+@@ -761,32 +761,32 @@ static void get_surf_rq_param(struct display_mode_lib *mode_lib,
+
+ // FIXME check if ppe apply for both luma and chroma in 422 case
+ if (is_chroma | is_alpha) {
+- vp_width = pipe_param.src.viewport_width_c / ppe;
+- vp_height = pipe_param.src.viewport_height_c;
+- data_pitch = pipe_param.src.data_pitch_c;
+- meta_pitch = pipe_param.src.meta_pitch_c;
+- surface_height = pipe_param.src.surface_height_y / 2.0;
++ vp_width = pipe_param->src.viewport_width_c / ppe;
++ vp_height = pipe_param->src.viewport_height_c;
++ data_pitch = pipe_param->src.data_pitch_c;
++ meta_pitch = pipe_param->src.meta_pitch_c;
++ surface_height = pipe_param->src.surface_height_y / 2.0;
+ } else {
+- vp_width = pipe_param.src.viewport_width / ppe;
+- vp_height = pipe_param.src.viewport_height;
+- data_pitch = pipe_param.src.data_pitch;
+- meta_pitch = pipe_param.src.meta_pitch;
+- surface_height = pipe_param.src.surface_height_y;
++ vp_width = pipe_param->src.viewport_width / ppe;
++ vp_height = pipe_param->src.viewport_height;
++ data_pitch = pipe_param->src.data_pitch;
++ meta_pitch = pipe_param->src.meta_pitch;
++ surface_height = pipe_param->src.surface_height_y;
+ }
+
+- if (pipe_param.dest.odm_combine) {
++ if (pipe_param->dest.odm_combine) {
+ unsigned int access_dir = 0;
+ unsigned int full_src_vp_width = 0;
+ unsigned int hactive_odm = 0;
+ unsigned int src_hactive_odm = 0;
+- access_dir = (pipe_param.src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
+- hactive_odm = pipe_param.dest.hactive / ((unsigned int)pipe_param.dest.odm_combine*2);
++ access_dir = (pipe_param->src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
++ hactive_odm = pipe_param->dest.hactive / ((unsigned int) pipe_param->dest.odm_combine*2);
+ if (is_chroma) {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio_c * pipe_param.dest.full_recout_width;
+- src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio_c * hactive_odm;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio_c * pipe_param->dest.full_recout_width;
++ src_hactive_odm = pipe_param->scale_ratio_depth.hscl_ratio_c * hactive_odm;
+ } else {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio * pipe_param.dest.full_recout_width;
+- src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio * hactive_odm;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio * pipe_param->dest.full_recout_width;
++ src_hactive_odm = pipe_param->scale_ratio_depth.hscl_ratio * hactive_odm;
+ }
+
+ if (access_dir == 0) {
+@@ -815,7 +815,7 @@ static void get_surf_rq_param(struct display_mode_lib *mode_lib,
+ rq_sizing_param->meta_chunk_bytes = 2048;
+ rq_sizing_param->min_meta_chunk_bytes = 256;
+
+- if (pipe_param.src.hostvm)
++ if (pipe_param->src.hostvm)
+ rq_sizing_param->mpte_group_bytes = 512;
+ else
+ rq_sizing_param->mpte_group_bytes = 2048;
+@@ -828,28 +828,28 @@ static void get_surf_rq_param(struct display_mode_lib *mode_lib,
+ vp_height,
+ data_pitch,
+ meta_pitch,
+- pipe_param.src.source_format,
+- pipe_param.src.sw_mode,
+- pipe_param.src.macro_tile_size,
+- pipe_param.src.source_scan,
+- pipe_param.src.hostvm,
++ pipe_param->src.source_format,
++ pipe_param->src.sw_mode,
++ pipe_param->src.macro_tile_size,
++ pipe_param->src.source_scan,
++ pipe_param->src.hostvm,
+ is_chroma,
+ surface_height);
+ }
+
+ static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib,
+ display_rq_params_st *rq_param,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ // get param for luma surface
+- rq_param->yuv420 = pipe_param.src.source_format == dm_420_8
+- || pipe_param.src.source_format == dm_420_10
+- || pipe_param.src.source_format == dm_rgbe_alpha
+- || pipe_param.src.source_format == dm_420_12;
++ rq_param->yuv420 = pipe_param->src.source_format == dm_420_8
++ || pipe_param->src.source_format == dm_420_10
++ || pipe_param->src.source_format == dm_rgbe_alpha
++ || pipe_param->src.source_format == dm_420_12;
+
+- rq_param->yuv420_10bpc = pipe_param.src.source_format == dm_420_10;
++ rq_param->yuv420_10bpc = pipe_param->src.source_format == dm_420_10;
+
+- rq_param->rgbe_alpha = (pipe_param.src.source_format == dm_rgbe_alpha)?1:0;
++ rq_param->rgbe_alpha = (pipe_param->src.source_format == dm_rgbe_alpha)?1:0;
+
+ get_surf_rq_param(mode_lib,
+ &(rq_param->sizing.rq_l),
+@@ -859,7 +859,7 @@ static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib,
+ 0,
+ 0);
+
+- if (is_dual_plane((enum source_format_class)(pipe_param.src.source_format))) {
++ if (is_dual_plane((enum source_format_class)(pipe_param->src.source_format))) {
+ // get param for chroma surface
+ get_surf_rq_param(mode_lib,
+ &(rq_param->sizing.rq_c),
+@@ -871,13 +871,13 @@ static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib,
+ }
+
+ // calculate how to split the det buffer space between luma and chroma
+- handle_det_buf_split(mode_lib, rq_param, pipe_param.src);
++ handle_det_buf_split(mode_lib, rq_param, pipe_param->src);
+ print__rq_params_st(mode_lib, *rq_param);
+ }
+
+ void dml30_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param)
++ const display_pipe_params_st *pipe_param)
+ {
+ display_rq_params_st rq_param = { 0 };
+
+@@ -1831,7 +1831,7 @@ static void dml_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib,
+ void dml30_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+@@ -1866,7 +1866,7 @@ void dml30_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ // system parameter calculation done
+
+ dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx);
+- dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe);
++ dml_rq_dlg_get_rq_params(mode_lib, &rq_param, &e2e_pipe_param[pipe_idx].pipe);
+ dml_rq_dlg_get_dlg_params(mode_lib,
+ e2e_pipe_param,
+ num_pipes,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.h b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.h
+index c04965cceff35..625e41f8d5751 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.h
+@@ -41,7 +41,7 @@ struct display_mode_lib;
+ // See also: <display_rq_regs_st>
+ void dml30_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+
+ // Function: dml_rq_dlg_get_dlg_reg
+ // Calculate and return DLG and TTU register struct given the system setting
+@@ -57,7 +57,7 @@ void dml30_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ void dml30_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
+index c23905bc733ae..57bd4e3f8a823 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
+@@ -738,7 +738,7 @@ static void get_surf_rq_param(
+ display_data_rq_sizing_params_st *rq_sizing_param,
+ display_data_rq_dlg_params_st *rq_dlg_param,
+ display_data_rq_misc_params_st *rq_misc_param,
+- const display_pipe_params_st pipe_param,
++ const display_pipe_params_st *pipe_param,
+ bool is_chroma,
+ bool is_alpha)
+ {
+@@ -752,33 +752,33 @@ static void get_surf_rq_param(
+
+ // FIXME check if ppe apply for both luma and chroma in 422 case
+ if (is_chroma | is_alpha) {
+- vp_width = pipe_param.src.viewport_width_c / ppe;
+- vp_height = pipe_param.src.viewport_height_c;
+- data_pitch = pipe_param.src.data_pitch_c;
+- meta_pitch = pipe_param.src.meta_pitch_c;
+- surface_height = pipe_param.src.surface_height_y / 2.0;
++ vp_width = pipe_param->src.viewport_width_c / ppe;
++ vp_height = pipe_param->src.viewport_height_c;
++ data_pitch = pipe_param->src.data_pitch_c;
++ meta_pitch = pipe_param->src.meta_pitch_c;
++ surface_height = pipe_param->src.surface_height_y / 2.0;
+ } else {
+- vp_width = pipe_param.src.viewport_width / ppe;
+- vp_height = pipe_param.src.viewport_height;
+- data_pitch = pipe_param.src.data_pitch;
+- meta_pitch = pipe_param.src.meta_pitch;
+- surface_height = pipe_param.src.surface_height_y;
++ vp_width = pipe_param->src.viewport_width / ppe;
++ vp_height = pipe_param->src.viewport_height;
++ data_pitch = pipe_param->src.data_pitch;
++ meta_pitch = pipe_param->src.meta_pitch;
++ surface_height = pipe_param->src.surface_height_y;
+ }
+
+- if (pipe_param.dest.odm_combine) {
++ if (pipe_param->dest.odm_combine) {
+ unsigned int access_dir;
+ unsigned int full_src_vp_width;
+ unsigned int hactive_odm;
+ unsigned int src_hactive_odm;
+
+- access_dir = (pipe_param.src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
+- hactive_odm = pipe_param.dest.hactive / ((unsigned int) pipe_param.dest.odm_combine * 2);
++ access_dir = (pipe_param->src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed
++ hactive_odm = pipe_param->dest.hactive / ((unsigned int) pipe_param->dest.odm_combine * 2);
+ if (is_chroma) {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio_c * pipe_param.dest.full_recout_width;
+- src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio_c * hactive_odm;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio_c * pipe_param->dest.full_recout_width;
++ src_hactive_odm = pipe_param->scale_ratio_depth.hscl_ratio_c * hactive_odm;
+ } else {
+- full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio * pipe_param.dest.full_recout_width;
+- src_hactive_odm = pipe_param.scale_ratio_depth.hscl_ratio * hactive_odm;
++ full_src_vp_width = pipe_param->scale_ratio_depth.hscl_ratio * pipe_param->dest.full_recout_width;
++ src_hactive_odm = pipe_param->scale_ratio_depth.hscl_ratio * hactive_odm;
+ }
+
+ if (access_dir == 0) {
+@@ -808,7 +808,7 @@ static void get_surf_rq_param(
+ rq_sizing_param->meta_chunk_bytes = 2048;
+ rq_sizing_param->min_meta_chunk_bytes = 256;
+
+- if (pipe_param.src.hostvm)
++ if (pipe_param->src.hostvm)
+ rq_sizing_param->mpte_group_bytes = 512;
+ else
+ rq_sizing_param->mpte_group_bytes = 2048;
+@@ -822,38 +822,38 @@ static void get_surf_rq_param(
+ vp_height,
+ data_pitch,
+ meta_pitch,
+- pipe_param.src.source_format,
+- pipe_param.src.sw_mode,
+- pipe_param.src.macro_tile_size,
+- pipe_param.src.source_scan,
+- pipe_param.src.hostvm,
++ pipe_param->src.source_format,
++ pipe_param->src.sw_mode,
++ pipe_param->src.macro_tile_size,
++ pipe_param->src.source_scan,
++ pipe_param->src.hostvm,
+ is_chroma,
+ surface_height);
+ }
+
+-static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib, display_rq_params_st *rq_param, const display_pipe_params_st pipe_param)
++static void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib, display_rq_params_st *rq_param, const display_pipe_params_st *pipe_param)
+ {
+ // get param for luma surface
+- rq_param->yuv420 = pipe_param.src.source_format == dm_420_8 || pipe_param.src.source_format == dm_420_10 || pipe_param.src.source_format == dm_rgbe_alpha
+- || pipe_param.src.source_format == dm_420_12;
++ rq_param->yuv420 = pipe_param->src.source_format == dm_420_8 || pipe_param->src.source_format == dm_420_10 || pipe_param->src.source_format == dm_rgbe_alpha
++ || pipe_param->src.source_format == dm_420_12;
+
+- rq_param->yuv420_10bpc = pipe_param.src.source_format == dm_420_10;
++ rq_param->yuv420_10bpc = pipe_param->src.source_format == dm_420_10;
+
+- rq_param->rgbe_alpha = (pipe_param.src.source_format == dm_rgbe_alpha) ? 1 : 0;
++ rq_param->rgbe_alpha = (pipe_param->src.source_format == dm_rgbe_alpha) ? 1 : 0;
+
+ get_surf_rq_param(mode_lib, &(rq_param->sizing.rq_l), &(rq_param->dlg.rq_l), &(rq_param->misc.rq_l), pipe_param, 0, 0);
+
+- if (is_dual_plane((enum source_format_class) (pipe_param.src.source_format))) {
++ if (is_dual_plane((enum source_format_class) (pipe_param->src.source_format))) {
+ // get param for chroma surface
+ get_surf_rq_param(mode_lib, &(rq_param->sizing.rq_c), &(rq_param->dlg.rq_c), &(rq_param->misc.rq_c), pipe_param, 1, rq_param->rgbe_alpha);
+ }
+
+ // calculate how to split the det buffer space between luma and chroma
+- handle_det_buf_split(mode_lib, rq_param, pipe_param.src);
++ handle_det_buf_split(mode_lib, rq_param, pipe_param->src);
+ print__rq_params_st(mode_lib, *rq_param);
+ }
+
+-void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, display_rq_regs_st *rq_regs, const display_pipe_params_st pipe_param)
++void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, display_rq_regs_st *rq_regs, const display_pipe_params_st *pipe_param)
+ {
+ display_rq_params_st rq_param = {0};
+
+@@ -1677,7 +1677,7 @@ void dml31_rq_dlg_get_dlg_reg(
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+@@ -1704,7 +1704,7 @@ void dml31_rq_dlg_get_dlg_reg(
+ // system parameter calculation done
+
+ dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx);
+- dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe);
++ dml_rq_dlg_get_rq_params(mode_lib, &rq_param, &e2e_pipe_param[pipe_idx].pipe);
+ dml_rq_dlg_get_dlg_params(
+ mode_lib,
+ e2e_pipe_param,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h
+index adf8518f761f9..8ee991351699d 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.h
+@@ -41,7 +41,7 @@ struct display_mode_lib;
+ // See also: <display_rq_regs_st>
+ void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+
+ // Function: dml_rq_dlg_get_dlg_reg
+ // Calculate and return DLG and TTU register struct given the system setting
+@@ -57,7 +57,7 @@ void dml31_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib,
+ void dml31_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
+index 1051ca1a23b8a..edb9f7567d6d9 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h
+@@ -80,11 +80,11 @@ enum dm_swizzle_mode {
+ dm_sw_SPARE_13 = 24,
+ dm_sw_64kb_s_x = 25,
+ dm_sw_64kb_d_x = 26,
+- dm_sw_SPARE_14 = 27,
++ dm_sw_64kb_r_x = 27,
+ dm_sw_SPARE_15 = 28,
+ dm_sw_var_s_x = 29,
+ dm_sw_var_d_x = 30,
+- dm_sw_64kb_r_x,
++ dm_sw_var_r_x = 31,
+ dm_sw_gfx7_2d_thin_l_vp,
+ dm_sw_gfx7_2d_thin_gl,
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
+index d42a0aeca6be2..72b1957022aa2 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
+@@ -49,7 +49,7 @@ struct dml_funcs {
+ struct display_mode_lib *mode_lib,
+ display_dlg_regs_st *dlg_regs,
+ display_ttu_regs_st *ttu_regs,
+- display_e2e_pipe_params_st *e2e_pipe_param,
++ const display_e2e_pipe_params_st *e2e_pipe_param,
+ const unsigned int num_pipes,
+ const unsigned int pipe_idx,
+ const bool cstate_en,
+@@ -60,7 +60,7 @@ struct dml_funcs {
+ void (*rq_dlg_get_rq_reg)(
+ struct display_mode_lib *mode_lib,
+ display_rq_regs_st *rq_regs,
+- const display_pipe_params_st pipe_param);
++ const display_pipe_params_st *pipe_param);
+ void (*recalculate)(struct display_mode_lib *mode_lib);
+ void (*validate)(struct display_mode_lib *mode_lib);
+ };
+diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
+index 257f280d3d53f..bd077ea224a40 100644
+--- a/drivers/gpu/drm/amd/include/amd_shared.h
++++ b/drivers/gpu/drm/amd/include/amd_shared.h
+@@ -98,7 +98,8 @@ enum amd_ip_block_type {
+ AMD_IP_BLOCK_TYPE_ACP,
+ AMD_IP_BLOCK_TYPE_VCN,
+ AMD_IP_BLOCK_TYPE_MES,
+- AMD_IP_BLOCK_TYPE_JPEG
++ AMD_IP_BLOCK_TYPE_JPEG,
++ AMD_IP_BLOCK_TYPE_NUM,
+ };
+
+ enum amd_clockgating_state {
+diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+index 03581d5b18360..08362d506534b 100644
+--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
++++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+@@ -927,6 +927,13 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
+ {
+ int ret = 0;
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
++ enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON;
++
++ if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state) {
++ dev_dbg(adev->dev, "IP block%d already in the target %s state!",
++ block_type, gate ? "gate" : "ungate");
++ return 0;
++ }
+
+ switch (block_type) {
+ case AMD_IP_BLOCK_TYPE_UVD:
+@@ -979,6 +986,9 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
+ break;
+ }
+
++ if (!ret)
++ atomic_set(&adev->pm.pwr_state[block_type], pwr_state);
++
+ return ret;
+ }
+
+diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+index 98f1b3d8c1d59..16e3f72d31b9f 100644
+--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
++++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+@@ -417,6 +417,12 @@ struct amdgpu_dpm {
+ enum amd_dpm_forced_level forced_level;
+ };
+
++enum ip_power_state {
++ POWER_STATE_UNKNOWN,
++ POWER_STATE_ON,
++ POWER_STATE_OFF,
++};
++
+ struct amdgpu_pm {
+ struct mutex mutex;
+ u32 current_sclk;
+@@ -452,6 +458,8 @@ struct amdgpu_pm {
+ struct i2c_adapter smu_i2c;
+ struct mutex smu_i2c_mutex;
+ struct list_head pm_attr_list;
++
++ atomic_t pwr_state[AMD_IP_BLOCK_TYPE_NUM];
+ };
+
+ #define R600_SSTU_DFLT 0
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
+index 1de3ae77e03ed..1f406f21b452f 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
+@@ -1036,13 +1036,13 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ else
+ i = 1;
+
+- size += sysfs_emit_at(buf, size, "0: %uMhz %s\n",
++ size += sprintf(buf + size, "0: %uMhz %s\n",
+ data->gfx_min_freq_limit/100,
+ i == 0 ? "*" : "");
+- size += sysfs_emit_at(buf, size, "1: %uMhz %s\n",
++ size += sprintf(buf + size, "1: %uMhz %s\n",
+ i == 1 ? now : SMU10_UMD_PSTATE_GFXCLK,
+ i == 1 ? "*" : "");
+- size += sysfs_emit_at(buf, size, "2: %uMhz %s\n",
++ size += sprintf(buf + size, "2: %uMhz %s\n",
+ data->gfx_max_freq_limit/100,
+ i == 2 ? "*" : "");
+ break;
+@@ -1050,7 +1050,7 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency, &now);
+
+ for (i = 0; i < mclk_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i,
+ mclk_table->entries[i].clk / 100,
+ ((mclk_table->entries[i].clk / 100)
+@@ -1065,10 +1065,10 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ if (ret)
+ return ret;
+
+- size = sysfs_emit(buf, "%s:\n", "OD_SCLK");
+- size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_SCLK");
++ size += sprintf(buf + size, "0: %10uMhz\n",
+ (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : min_freq);
+- size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
++ size += sprintf(buf + size, "1: %10uMhz\n",
+ (data->gfx_actual_soft_max_freq > 0) ? data->gfx_actual_soft_max_freq : max_freq);
+ }
+ break;
+@@ -1081,8 +1081,8 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ if (ret)
+ return ret;
+
+- size = sysfs_emit(buf, "%s:\n", "OD_RANGE");
+- size += sysfs_emit_at(buf, size, "SCLK: %7uMHz %10uMHz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_RANGE");
++ size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
+ min_freq, max_freq);
+ }
+ break;
+@@ -1456,6 +1456,8 @@ static int smu10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
+ if (!buf)
+ return -EINVAL;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ size += sysfs_emit_at(buf, size, "%s %16s %s %s %s %s\n",title[0],
+ title[1], title[2], title[3], title[4], title[5]);
+
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+index e7803ce8f67aa..611969bf45207 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+@@ -4926,7 +4926,7 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
+ now = i;
+
+ for (i = 0; i < sclk_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, sclk_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -4941,7 +4941,7 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
+ now = i;
+
+ for (i = 0; i < mclk_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, mclk_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -4955,7 +4955,7 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
+ now = i;
+
+ for (i = 0; i < pcie_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %s %s\n", i,
++ size += sprintf(buf + size, "%d: %s %s\n", i,
+ (pcie_table->dpm_levels[i].value == 0) ? "2.5GT/s, x8" :
+ (pcie_table->dpm_levels[i].value == 1) ? "5.0GT/s, x16" :
+ (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "",
+@@ -4963,32 +4963,32 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr,
+ break;
+ case OD_SCLK:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_SCLK");
++ size += sprintf(buf + size, "%s:\n", "OD_SCLK");
+ for (i = 0; i < odn_sclk_table->num_of_pl; i++)
+- size += sysfs_emit_at(buf, size, "%d: %10uMHz %10umV\n",
++ size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
+ i, odn_sclk_table->entries[i].clock/100,
+ odn_sclk_table->entries[i].vddc);
+ }
+ break;
+ case OD_MCLK:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_MCLK");
++ size += sprintf(buf + size, "%s:\n", "OD_MCLK");
+ for (i = 0; i < odn_mclk_table->num_of_pl; i++)
+- size += sysfs_emit_at(buf, size, "%d: %10uMHz %10umV\n",
++ size += sprintf(buf + size, "%d: %10uMHz %10umV\n",
+ i, odn_mclk_table->entries[i].clock/100,
+ odn_mclk_table->entries[i].vddc);
+ }
+ break;
+ case OD_RANGE:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_RANGE");
+- size += sysfs_emit_at(buf, size, "SCLK: %7uMHz %10uMHz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_RANGE");
++ size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.sclk_table.dpm_levels[0].value/100,
+ hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
+- size += sysfs_emit_at(buf, size, "MCLK: %7uMHz %10uMHz\n",
++ size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.mclk_table.dpm_levels[0].value/100,
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
+- size += sysfs_emit_at(buf, size, "VDDC: %7umV %11umV\n",
++ size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
+ data->odn_dpm_table.min_vddc,
+ data->odn_dpm_table.max_vddc);
+ }
+@@ -5518,6 +5518,8 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
+ if (!buf)
+ return -EINVAL;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ size += sysfs_emit_at(buf, size, "%s %16s %16s %16s %16s %16s %16s %16s\n",
+ title[0], title[1], title[2], title[3],
+ title[4], title[5], title[6], title[7]);
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
+index b94a77e4e7147..03bf8f0692228 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
+@@ -1559,7 +1559,7 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
+ CURR_SCLK_INDEX);
+
+ for (i = 0; i < sclk_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, sclk_table->entries[i].clk / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -1571,7 +1571,7 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
+ CURR_MCLK_INDEX);
+
+ for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100,
+ (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : "");
+ break;
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
+index ad33983a8064e..2a75da1e9f035 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h
+@@ -109,6 +109,19 @@ int phm_irq_process(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry);
+
++/*
++ * Helper function to make sysfs_emit_at() happy. Align buf to
++ * the current page boundary and record the offset.
++ */
++static inline void phm_get_sysfs_buf(char **buf, int *offset)
++{
++ if (!*buf || !offset)
++ return;
++
++ *offset = offset_in_page(*buf);
++ *buf -= *offset;
++}
++
+ int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr);
+
+ void *smu_atom_get_data_table(void *dev, uint32_t table, uint16_t *size,
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+index c152a61ddd2c9..e6336654c5655 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+@@ -4548,6 +4548,8 @@ static int vega10_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+ int ret = 0;
+ int size = 0;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ ret = vega10_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+@@ -4650,7 +4652,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ else
+ count = sclk_table->count;
+ for (i = 0; i < count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, sclk_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -4661,7 +4663,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now);
+
+ for (i = 0; i < mclk_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, mclk_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -4672,7 +4674,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now);
+
+ for (i = 0; i < soc_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, soc_table->dpm_levels[i].value / 100,
+ (i == now) ? "*" : "");
+ break;
+@@ -4684,7 +4686,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK, &now);
+
+ for (i = 0; i < dcef_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, dcef_table->dpm_levels[i].value / 100,
+ (dcef_table->dpm_levels[i].value / 100 == now) ?
+ "*" : "");
+@@ -4698,7 +4700,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+ gen_speed = pptable->PcieGenSpeed[i];
+ lane_width = pptable->PcieLaneCount[i];
+
+- size += sysfs_emit_at(buf, size, "%d: %s %s %s\n", i,
++ size += sprintf(buf + size, "%d: %s %s %s\n", i,
+ (gen_speed == 0) ? "2.5GT/s," :
+ (gen_speed == 1) ? "5.0GT/s," :
+ (gen_speed == 2) ? "8.0GT/s," :
+@@ -4717,34 +4719,34 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr,
+
+ case OD_SCLK:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_SCLK");
++ size += sprintf(buf + size, "%s:\n", "OD_SCLK");
+ podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk;
+ for (i = 0; i < podn_vdd_dep->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %10uMhz %10umV\n",
++ size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
+ i, podn_vdd_dep->entries[i].clk / 100,
+ podn_vdd_dep->entries[i].vddc);
+ }
+ break;
+ case OD_MCLK:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_MCLK");
++ size += sprintf(buf + size, "%s:\n", "OD_MCLK");
+ podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk;
+ for (i = 0; i < podn_vdd_dep->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %10uMhz %10umV\n",
++ size += sprintf(buf + size, "%d: %10uMhz %10umV\n",
+ i, podn_vdd_dep->entries[i].clk/100,
+ podn_vdd_dep->entries[i].vddc);
+ }
+ break;
+ case OD_RANGE:
+ if (hwmgr->od_enabled) {
+- size = sysfs_emit(buf, "%s:\n", "OD_RANGE");
+- size += sysfs_emit_at(buf, size, "SCLK: %7uMHz %10uMHz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_RANGE");
++ size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.gfx_table.dpm_levels[0].value/100,
+ hwmgr->platform_descriptor.overdriveLimit.engineClock/100);
+- size += sysfs_emit_at(buf, size, "MCLK: %7uMHz %10uMHz\n",
++ size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n",
+ data->golden_dpm_table.mem_table.dpm_levels[0].value/100,
+ hwmgr->platform_descriptor.overdriveLimit.memoryClock/100);
+- size += sysfs_emit_at(buf, size, "VDDC: %7umV %11umV\n",
++ size += sprintf(buf + size, "VDDC: %7umV %11umV\n",
+ data->odn_dpm_table.min_vddc,
+ data->odn_dpm_table.max_vddc);
+ }
+@@ -5112,6 +5114,8 @@ static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
+ if (!buf)
+ return -EINVAL;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ size += sysfs_emit_at(buf, size, "%s %16s %s %s %s %s\n",title[0],
+ title[1], title[2], title[3], title[4], title[5]);
+
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+index 8558718e15a8f..a2f4d6773d458 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+@@ -2141,6 +2141,8 @@ static int vega12_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+ int ret = 0;
+ int size = 0;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ ret = vega12_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+@@ -2256,7 +2258,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
+ "Attempt to get gfx clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : "");
+ break;
+@@ -2272,7 +2274,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
+ "Attempt to get memory clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : "");
+ break;
+@@ -2290,7 +2292,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
+ "Attempt to get soc clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ break;
+@@ -2308,7 +2310,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr,
+ "Attempt to get dcef clk levels Failed!",
+ return -1);
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : "");
+ break;
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+index 0cf39c1244b1c..85d55ab4e369f 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+@@ -3238,6 +3238,8 @@ static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+ int ret = 0;
+ int size = 0;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+ PP_ASSERT_WITH_CODE(!ret,
+ "[EnableAllSmuFeatures] Failed to get enabled smc features!",
+@@ -3372,13 +3374,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ return ret);
+
+ if (vega20_get_sclks(hwmgr, &clocks)) {
+- size += sysfs_emit_at(buf, size, "0: %uMhz * (DPM disabled)\n",
++ size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
+ now / 100);
+ break;
+ }
+
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+@@ -3390,13 +3392,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ return ret);
+
+ if (vega20_get_memclocks(hwmgr, &clocks)) {
+- size += sysfs_emit_at(buf, size, "0: %uMhz * (DPM disabled)\n",
++ size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
+ now / 100);
+ break;
+ }
+
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+@@ -3408,13 +3410,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ return ret);
+
+ if (vega20_get_socclocks(hwmgr, &clocks)) {
+- size += sysfs_emit_at(buf, size, "0: %uMhz * (DPM disabled)\n",
++ size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
+ now / 100);
+ break;
+ }
+
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+@@ -3426,7 +3428,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ return ret);
+
+ for (i = 0; i < fclk_dpm_table->count; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, fclk_dpm_table->dpm_levels[i].value,
+ fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : "");
+ break;
+@@ -3438,13 +3440,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ return ret);
+
+ if (vega20_get_dcefclocks(hwmgr, &clocks)) {
+- size += sysfs_emit_at(buf, size, "0: %uMhz * (DPM disabled)\n",
++ size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n",
+ now / 100);
+ break;
+ }
+
+ for (i = 0; i < clocks.num_levels; i++)
+- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
++ size += sprintf(buf + size, "%d: %uMhz %s\n",
+ i, clocks.data[i].clocks_in_khz / 1000,
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
+ break;
+@@ -3458,7 +3460,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ gen_speed = pptable->PcieGenSpeed[i];
+ lane_width = pptable->PcieLaneCount[i];
+
+- size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
++ size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
+ (gen_speed == 0) ? "2.5GT/s," :
+ (gen_speed == 1) ? "5.0GT/s," :
+ (gen_speed == 2) ? "8.0GT/s," :
+@@ -3479,18 +3481,18 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ case OD_SCLK:
+ if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
+- size = sysfs_emit(buf, "%s:\n", "OD_SCLK");
+- size += sysfs_emit_at(buf, size, "0: %10uMhz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_SCLK");
++ size += sprintf(buf + size, "0: %10uMhz\n",
+ od_table->GfxclkFmin);
+- size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
++ size += sprintf(buf + size, "1: %10uMhz\n",
+ od_table->GfxclkFmax);
+ }
+ break;
+
+ case OD_MCLK:
+ if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
+- size = sysfs_emit(buf, "%s:\n", "OD_MCLK");
+- size += sysfs_emit_at(buf, size, "1: %10uMhz\n",
++ size += sprintf(buf + size, "%s:\n", "OD_MCLK");
++ size += sprintf(buf + size, "1: %10uMhz\n",
+ od_table->UclkFmax);
+ }
+
+@@ -3503,14 +3505,14 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
+- size = sysfs_emit(buf, "%s:\n", "OD_VDDC_CURVE");
+- size += sysfs_emit_at(buf, size, "0: %10uMhz %10dmV\n",
++ size += sprintf(buf + size, "%s:\n", "OD_VDDC_CURVE");
++ size += sprintf(buf + size, "0: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq1,
+ od_table->GfxclkVolt1 / VOLTAGE_SCALE);
+- size += sysfs_emit_at(buf, size, "1: %10uMhz %10dmV\n",
++ size += sprintf(buf + size, "1: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq2,
+ od_table->GfxclkVolt2 / VOLTAGE_SCALE);
+- size += sysfs_emit_at(buf, size, "2: %10uMhz %10dmV\n",
++ size += sprintf(buf + size, "2: %10uMhz %10dmV\n",
+ od_table->GfxclkFreq3,
+ od_table->GfxclkVolt3 / VOLTAGE_SCALE);
+ }
+@@ -3518,17 +3520,17 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ break;
+
+ case OD_RANGE:
+- size = sysfs_emit(buf, "%s:\n", "OD_RANGE");
++ size += sprintf(buf + size, "%s:\n", "OD_RANGE");
+
+ if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) {
+- size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
++ size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value);
+ }
+
+ if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) {
+- size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n",
++ size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_UCLK_FMAX].min_value,
+ od8_settings[OD8_SETTING_UCLK_FMAX].max_value);
+ }
+@@ -3539,22 +3541,22 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id &&
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) {
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value);
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
++ size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value);
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value);
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
++ size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value);
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
++ size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n",
+ od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value);
+- size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
++ size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n",
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value,
+ od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value);
+ }
+@@ -4003,6 +4005,8 @@ static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf)
+ if (!buf)
+ return -EINVAL;
+
++ phm_get_sysfs_buf(&buf, &size);
++
+ size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
+ title[0], title[1], title[2], title[3], title[4], title[5],
+ title[6], title[7], title[8], title[9], title[10]);
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+index b1ad451af06bd..dfba0bc732073 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+@@ -1265,7 +1265,7 @@ static int navi10_print_clk_levels(struct smu_context *smu,
+ enum smu_clk_type clk_type, char *buf)
+ {
+ uint16_t *curve_settings;
+- int i, size = 0, ret = 0;
++ int i, levels, size = 0, ret = 0;
+ uint32_t cur_value = 0, value = 0, count = 0;
+ uint32_t freq_values[3] = {0};
+ uint32_t mark_index = 0;
+@@ -1319,14 +1319,17 @@ static int navi10_print_clk_levels(struct smu_context *smu,
+ freq_values[1] = cur_value;
+ mark_index = cur_value == freq_values[0] ? 0 :
+ cur_value == freq_values[2] ? 2 : 1;
+- if (mark_index != 1)
+- freq_values[1] = (freq_values[0] + freq_values[2]) / 2;
+
+- for (i = 0; i < 3; i++) {
++ levels = 3;
++ if (mark_index != 1) {
++ levels = 2;
++ freq_values[1] = freq_values[2];
++ }
++
++ for (i = 0; i < levels; i++) {
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i],
+ i == mark_index ? "*" : "");
+ }
+-
+ }
+ break;
+ case SMU_PCIE:
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+index f6ef0ce6e9e2c..a9dceef4a7011 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+@@ -1386,52 +1386,38 @@ static int vangogh_set_performance_level(struct smu_context *smu,
+ uint32_t soc_mask, mclk_mask, fclk_mask;
+ uint32_t vclk_mask = 0, dclk_mask = 0;
+
++ smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
++ smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
++
+ switch (level) {
+ case AMD_DPM_FORCED_LEVEL_HIGH:
+- smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
++ smu->gfx_actual_hard_min_freq = smu->gfx_default_soft_max_freq;
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+
+ ret = vangogh_force_dpm_limit_value(smu, true);
++ if (ret)
++ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_LOW:
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+- smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+-
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
++ smu->gfx_actual_soft_max_freq = smu->gfx_default_hard_min_freq;
+
+ ret = vangogh_force_dpm_limit_value(smu, false);
++ if (ret)
++ return ret;
+ break;
+ case AMD_DPM_FORCED_LEVEL_AUTO:
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+-
+ ret = vangogh_unforce_dpm_levels(smu);
+- break;
+- case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
+- smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+- smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+-
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu,
+- SMU_MSG_SetHardMinGfxClk,
+- VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
+- if (ret)
+- return ret;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu,
+- SMU_MSG_SetSoftMaxGfxClk,
+- VANGOGH_UMD_PSTATE_STANDARD_GFXCLK, NULL);
+ if (ret)
+ return ret;
++ break;
++ case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
++ smu->gfx_actual_hard_min_freq = VANGOGH_UMD_PSTATE_STANDARD_GFXCLK;
++ smu->gfx_actual_soft_max_freq = VANGOGH_UMD_PSTATE_STANDARD_GFXCLK;
+
+ ret = vangogh_get_profiling_clk_mask(smu, level,
+ &vclk_mask,
+@@ -1446,32 +1432,15 @@ static int vangogh_set_performance_level(struct smu_context *smu,
+ vangogh_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask);
+ vangogh_force_clk_levels(smu, SMU_VCLK, 1 << vclk_mask);
+ vangogh_force_clk_levels(smu, SMU_DCLK, 1 << dclk_mask);
+-
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+- smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+-
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn,
+- VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
+- if (ret)
+- return ret;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn,
+- VANGOGH_UMD_PSTATE_PEAK_DCLK, NULL);
+- if (ret)
+- return ret;
++ smu->gfx_actual_soft_max_freq = smu->gfx_default_hard_min_freq;
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
+ smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+ smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+-
+ ret = vangogh_get_profiling_clk_mask(smu, level,
+ NULL,
+ NULL,
+@@ -1484,29 +1453,29 @@ static int vangogh_set_performance_level(struct smu_context *smu,
+ vangogh_force_clk_levels(smu, SMU_FCLK, 1 << fclk_mask);
+ break;
+ case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
+- smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq;
+- smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq;
+-
+- smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq;
+- smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
+- VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
+- if (ret)
+- return ret;
++ smu->gfx_actual_hard_min_freq = VANGOGH_UMD_PSTATE_PEAK_GFXCLK;
++ smu->gfx_actual_soft_max_freq = VANGOGH_UMD_PSTATE_PEAK_GFXCLK;
+
+- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
+- VANGOGH_UMD_PSTATE_PEAK_GFXCLK, NULL);
++ ret = vangogh_set_peak_clock_by_device(smu);
+ if (ret)
+ return ret;
+-
+- ret = vangogh_set_peak_clock_by_device(smu);
+ break;
+ case AMD_DPM_FORCED_LEVEL_MANUAL:
+ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
+ default:
+- break;
++ return 0;
+ }
++
++ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
++ smu->gfx_actual_hard_min_freq, NULL);
++ if (ret)
++ return ret;
++
++ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
++ smu->gfx_actual_soft_max_freq, NULL);
++ if (ret)
++ return ret;
++
+ return ret;
+ }
+
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
+index d60b8c5e87157..43028f2cd28b5 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
+@@ -191,6 +191,9 @@ int smu_v12_0_fini_smc_tables(struct smu_context *smu)
+ kfree(smu_table->watermarks_table);
+ smu_table->watermarks_table = NULL;
+
++ kfree(smu_table->gpu_metrics_table);
++ smu_table->gpu_metrics_table = NULL;
++
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+index a0e50f23b1dd7..8d4aa16b2ae7c 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+@@ -197,6 +197,7 @@ int smu_v13_0_check_fw_status(struct smu_context *smu)
+
+ int smu_v13_0_check_fw_version(struct smu_context *smu)
+ {
++ struct amdgpu_device *adev = smu->adev;
+ uint32_t if_version = 0xff, smu_version = 0xff;
+ uint16_t smu_major;
+ uint8_t smu_minor, smu_debug;
+@@ -209,6 +210,8 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
+ smu_major = (smu_version >> 16) & 0xffff;
+ smu_minor = (smu_version >> 8) & 0xff;
+ smu_debug = (smu_version >> 0) & 0xff;
++ if (smu->is_apu)
++ adev->pm.fw_version = smu_version;
+
+ switch (smu->adev->asic_type) {
+ case CHIP_ALDEBARAN:
+diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+index b53fee6f1c170..65f172807a0d5 100644
+--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+@@ -291,7 +291,7 @@ vga_pw_show(struct device *dev, struct device_attribute *attr, char *buf)
+ if (rc)
+ return rc;
+
+- return sprintf(buf, "%u\n", reg & 1);
++ return sprintf(buf, "%u\n", reg);
+ }
+ static DEVICE_ATTR_RO(vga_pw);
+
+diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
+index 1e30eaeb0e1b3..d5c98f79d58d3 100644
+--- a/drivers/gpu/drm/ast/ast_mode.c
++++ b/drivers/gpu/drm/ast/ast_mode.c
+@@ -1121,7 +1121,10 @@ static void ast_crtc_reset(struct drm_crtc *crtc)
+ if (crtc->state)
+ crtc->funcs->atomic_destroy_state(crtc, crtc->state);
+
+- __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
++ if (ast_state)
++ __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
++ else
++ __drm_atomic_helper_crtc_reset(crtc, NULL);
+ }
+
+ static struct drm_crtc_state *
+diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
+index 14d73fb1dd15b..ea414cd349b5c 100644
+--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
+@@ -720,7 +720,7 @@ static int edid_read(struct anx7625_data *ctx,
+ ret = sp_tx_aux_rd(ctx, 0xf1);
+
+ if (ret) {
+- sp_tx_rst_aux(ctx);
++ ret = sp_tx_rst_aux(ctx);
+ DRM_DEV_DEBUG_DRIVER(dev, "edid read fail, reset!\n");
+ } else {
+ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
+@@ -735,7 +735,7 @@ static int edid_read(struct anx7625_data *ctx,
+ if (cnt > EDID_TRY_CNT)
+ return -EIO;
+
+- return 0;
++ return ret;
+ }
+
+ static int segments_edid_read(struct anx7625_data *ctx,
+@@ -785,7 +785,7 @@ static int segments_edid_read(struct anx7625_data *ctx,
+ if (cnt > EDID_TRY_CNT)
+ return -EIO;
+
+- return 0;
++ return ret;
+ }
+
+ static int sp_tx_edid_read(struct anx7625_data *ctx,
+@@ -887,7 +887,11 @@ static int sp_tx_edid_read(struct anx7625_data *ctx,
+ }
+
+ /* Reset aux channel */
+- sp_tx_rst_aux(ctx);
++ ret = sp_tx_rst_aux(ctx);
++ if (ret < 0) {
++ DRM_DEV_ERROR(dev, "Failed to reset aux channel!\n");
++ return ret;
++ }
+
+ return (blocks_num + 1);
+ }
+diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
+index 2f2a09adb4bc8..06b59b422c696 100644
+--- a/drivers/gpu/drm/bridge/ite-it66121.c
++++ b/drivers/gpu/drm/bridge/ite-it66121.c
+@@ -889,7 +889,7 @@ unlock:
+ static int it66121_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+ {
+- u32 vendor_ids[2], device_ids[2], revision_id;
++ u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
+ struct device_node *ep;
+ int ret;
+ struct it66121_ctx *ctx;
+@@ -918,11 +918,26 @@ static int it66121_probe(struct i2c_client *client,
+ return -EINVAL;
+
+ ep = of_graph_get_remote_node(dev->of_node, 1, -1);
+- if (!ep)
+- return -EPROBE_DEFER;
++ if (!ep) {
++ dev_err(ctx->dev, "The endpoint is unconnected\n");
++ return -EINVAL;
++ }
++
++ if (!of_device_is_available(ep)) {
++ of_node_put(ep);
++ dev_err(ctx->dev, "The remote device is disabled\n");
++ return -ENODEV;
++ }
+
+ ctx->next_bridge = of_drm_find_bridge(ep);
+ of_node_put(ep);
++ if (!ctx->next_bridge) {
++ dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n");
++ return -EPROBE_DEFER;
++ }
++
++ if (!ctx->next_bridge)
++ return -EPROBE_DEFER;
+
+ i2c_set_clientdata(client, ctx);
+ mutex_init(&ctx->lock);
+diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+index 3cac16db970f0..010657ea7af78 100644
+--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
++++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+@@ -167,9 +167,10 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
+ struct lt9611uxc *lt9611uxc = container_of(work, struct lt9611uxc, work);
+ bool connected;
+
+- if (lt9611uxc->connector.dev)
+- drm_kms_helper_hotplug_event(lt9611uxc->connector.dev);
+- else {
++ if (lt9611uxc->connector.dev) {
++ if (lt9611uxc->connector.dev->mode_config.funcs)
++ drm_kms_helper_hotplug_event(lt9611uxc->connector.dev);
++ } else {
+
+ mutex_lock(&lt9611uxc->ocm_lock);
+ connected = lt9611uxc->hdmi_connected;
+@@ -339,6 +340,8 @@ static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc
+ return -ENODEV;
+ }
+
++ lt9611uxc->connector.polled = DRM_CONNECTOR_POLL_HPD;
++
+ drm_connector_helper_add(&lt9611uxc->connector,
+ &lt9611uxc_bridge_connector_helper_funcs);
+ ret = drm_connector_init(bridge->dev, &lt9611uxc->connector,
+diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
+index ed8ac5059cd26..a7389a0facfb4 100644
+--- a/drivers/gpu/drm/bridge/nwl-dsi.c
++++ b/drivers/gpu/drm/bridge/nwl-dsi.c
+@@ -939,6 +939,40 @@ static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
+ drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
+ }
+
++static u32 *nwl_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
++ struct drm_bridge_state *bridge_state,
++ struct drm_crtc_state *crtc_state,
++ struct drm_connector_state *conn_state,
++ u32 output_fmt,
++ unsigned int *num_input_fmts)
++{
++ u32 *input_fmts, input_fmt;
++
++ *num_input_fmts = 0;
++
++ switch (output_fmt) {
++ /* If MEDIA_BUS_FMT_FIXED is tested, return default bus format */
++ case MEDIA_BUS_FMT_FIXED:
++ input_fmt = MEDIA_BUS_FMT_RGB888_1X24;
++ break;
++ case MEDIA_BUS_FMT_RGB888_1X24:
++ case MEDIA_BUS_FMT_RGB666_1X18:
++ case MEDIA_BUS_FMT_RGB565_1X16:
++ input_fmt = output_fmt;
++ break;
++ default:
++ return NULL;
++ }
++
++ input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL);
++ if (!input_fmts)
++ return NULL;
++ input_fmts[0] = input_fmt;
++ *num_input_fmts = 1;
++
++ return input_fmts;
++}
++
+ static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+@@ -946,6 +980,7 @@ static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
+ .atomic_check = nwl_dsi_bridge_atomic_check,
+ .atomic_enable = nwl_dsi_bridge_atomic_enable,
+ .atomic_disable = nwl_dsi_bridge_atomic_disable,
++ .atomic_get_input_bus_fmts = nwl_bridge_atomic_get_input_bus_fmts,
+ .mode_set = nwl_dsi_bridge_mode_set,
+ .mode_valid = nwl_dsi_bridge_mode_valid,
+ .attach = nwl_dsi_bridge_attach,
+diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
+index 8e7a124d6c5a3..22bf690910b25 100644
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -1743,7 +1743,13 @@ void drm_fb_helper_fill_info(struct fb_info *info,
+ sizes->fb_width, sizes->fb_height);
+
+ info->par = fb_helper;
+- snprintf(info->fix.id, sizeof(info->fix.id), "%s",
++ /*
++ * The DRM drivers fbdev emulation device name can be confusing if the
++ * driver name also has a "drm" suffix on it. Leading to names such as
++ * "simpledrmdrmfb" in /proc/fb. Unfortunately, it's an uAPI and can't
++ * be changed due user-space tools (e.g: pm-utils) matching against it.
++ */
++ snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb",
+ fb_helper->dev->driver->name);
+
+ }
+diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
+index d53388199f34c..9d05674550a4f 100644
+--- a/drivers/gpu/drm/drm_gem_cma_helper.c
++++ b/drivers/gpu/drm/drm_gem_cma_helper.c
+@@ -210,8 +210,13 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
+ dma_buf_vunmap(gem_obj->import_attach->dmabuf, &map);
+ drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
+ } else if (cma_obj->vaddr) {
+- dma_free_wc(gem_obj->dev->dev, cma_obj->base.size,
+- cma_obj->vaddr, cma_obj->paddr);
++ if (cma_obj->map_noncoherent)
++ dma_free_noncoherent(gem_obj->dev->dev, cma_obj->base.size,
++ cma_obj->vaddr, cma_obj->paddr,
++ DMA_TO_DEVICE);
++ else
++ dma_free_wc(gem_obj->dev->dev, cma_obj->base.size,
++ cma_obj->vaddr, cma_obj->paddr);
+ }
+
+ drm_gem_object_release(gem_obj);
+diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
+index e1b2ce4921ae7..a950d5db211c5 100644
+--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
+@@ -109,6 +109,12 @@ static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = {
+ .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 dmi_system_id orientation_data[] = {
+ { /* Acer One 10 (S1003) */
+ .matches = {
+@@ -205,6 +211,13 @@ static const struct dmi_system_id orientation_data[] = {
+ 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
+@@ -223,10 +236,15 @@ static const struct dmi_system_id orientation_data[] = {
+ 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,
+@@ -237,6 +255,19 @@ static const struct dmi_system_id orientation_data[] = {
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Default string"),
+ },
+ .driver_data = (void *)&onegx1_pro,
++ }, { /* 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"),
+diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
+index 5b2d0ca03705c..838b32b70bce6 100644
+--- a/drivers/gpu/drm/drm_plane_helper.c
++++ b/drivers/gpu/drm/drm_plane_helper.c
+@@ -123,7 +123,6 @@ static int drm_plane_helper_check_update(struct drm_plane *plane,
+ .crtc_w = drm_rect_width(dst),
+ .crtc_h = drm_rect_height(dst),
+ .rotation = rotation,
+- .visible = *visible,
+ };
+ struct drm_crtc_state crtc_state = {
+ .crtc = crtc,
+diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
+index deb23dbec8b52..d6c7f4f9a7a29 100644
+--- a/drivers/gpu/drm/drm_prime.c
++++ b/drivers/gpu/drm/drm_prime.c
+@@ -719,11 +719,13 @@ int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+ if (obj->funcs && obj->funcs->mmap) {
+ vma->vm_ops = obj->funcs->vm_ops;
+
++ drm_gem_object_get(obj);
+ ret = obj->funcs->mmap(obj, vma);
+- if (ret)
++ if (ret) {
++ drm_gem_object_put(obj);
+ return ret;
++ }
+ vma->vm_private_data = obj;
+- drm_gem_object_get(obj);
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
+index c9a9d74f338c1..c313a5b4549c4 100644
+--- a/drivers/gpu/drm/drm_syncobj.c
++++ b/drivers/gpu/drm/drm_syncobj.c
+@@ -404,8 +404,17 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
+
+ if (*fence) {
+ ret = dma_fence_chain_find_seqno(fence, point);
+- if (!ret)
++ 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;
+diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
+index cd818a6291835..00e53de4812bb 100644
+--- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
++++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
+@@ -225,12 +225,29 @@ static int hyperv_vmbus_remove(struct hv_device *hdev)
+ {
+ struct drm_device *dev = hv_get_drvdata(hdev);
+ struct hyperv_drm_device *hv = to_hv(dev);
++ struct pci_dev *pdev;
+
+ drm_dev_unplug(dev);
+ drm_atomic_helper_shutdown(dev);
+ vmbus_close(hdev->channel);
+ hv_set_drvdata(hdev, NULL);
+- vmbus_free_mmio(hv->mem->start, hv->fb_size);
++
++ /*
++ * Free allocated MMIO memory only on Gen2 VMs.
++ * On Gen1 VMs, release the PCI device
++ */
++ if (efi_enabled(EFI_BOOT)) {
++ vmbus_free_mmio(hv->mem->start, hv->fb_size);
++ } else {
++ pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
++ PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
++ if (!pdev) {
++ drm_err(dev, "Unable to find PCI Hyper-V video\n");
++ return -ENODEV;
++ }
++ pci_release_region(pdev, 0);
++ pci_dev_put(pdev);
++ }
+
+ return 0;
+ }
+diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
+index be352e9f0afc1..63baaf6988ade 100644
+--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
++++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
+@@ -584,6 +584,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv,
+ else
+ intel_encoder->enable = g4x_enable_hdmi;
+ }
++ intel_encoder->shutdown = intel_hdmi_encoder_shutdown;
+
+ intel_encoder->type = INTEL_OUTPUT_HDMI;
+ intel_encoder->power_domain = intel_port_to_power_domain(port);
+diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
+index a3eae3f3eadce..638a00b2dc2d2 100644
+--- a/drivers/gpu/drm/i915/display/icl_dsi.c
++++ b/drivers/gpu/drm/i915/display/icl_dsi.c
+@@ -711,10 +711,7 @@ static void gen11_dsi_map_pll(struct intel_encoder *encoder,
+ intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val);
+
+ for_each_dsi_phy(phy, intel_dsi->phys) {
+- if (DISPLAY_VER(dev_priv) >= 12)
+- val |= ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+- else
+- val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
++ val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ }
+ intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val);
+
+@@ -1150,8 +1147,6 @@ static void
+ gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+ {
+- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+-
+ /* step 4a: power up all lanes of the DDI used by DSI */
+ gen11_dsi_power_up_lanes(encoder);
+
+@@ -1177,8 +1172,7 @@ gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder,
+ gen11_dsi_configure_transcoder(encoder, crtc_state);
+
+ /* Step 4l: Gate DDI clocks */
+- if (DISPLAY_VER(dev_priv) == 11)
+- gen11_dsi_gate_clocks(encoder);
++ gen11_dsi_gate_clocks(encoder);
+ }
+
+ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
+diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
+index fd71346aac7bc..32d5a556b7eac 100644
+--- a/drivers/gpu/drm/i915/display/intel_bios.c
++++ b/drivers/gpu/drm/i915/display/intel_bios.c
+@@ -1692,6 +1692,39 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin)
+ return 0;
+ }
+
++static u8 dvo_port_type(u8 dvo_port)
++{
++ switch (dvo_port) {
++ case DVO_PORT_HDMIA:
++ case DVO_PORT_HDMIB:
++ case DVO_PORT_HDMIC:
++ case DVO_PORT_HDMID:
++ case DVO_PORT_HDMIE:
++ case DVO_PORT_HDMIF:
++ case DVO_PORT_HDMIG:
++ case DVO_PORT_HDMIH:
++ case DVO_PORT_HDMII:
++ return DVO_PORT_HDMIA;
++ case DVO_PORT_DPA:
++ case DVO_PORT_DPB:
++ case DVO_PORT_DPC:
++ case DVO_PORT_DPD:
++ case DVO_PORT_DPE:
++ case DVO_PORT_DPF:
++ case DVO_PORT_DPG:
++ case DVO_PORT_DPH:
++ case DVO_PORT_DPI:
++ return DVO_PORT_DPA;
++ case DVO_PORT_MIPIA:
++ case DVO_PORT_MIPIB:
++ case DVO_PORT_MIPIC:
++ case DVO_PORT_MIPID:
++ return DVO_PORT_MIPIA;
++ default:
++ return dvo_port;
++ }
++}
++
+ static enum port __dvo_port_to_port(int n_ports, int n_dvo,
+ const int port_mapping[][3], u8 dvo_port)
+ {
+@@ -2622,35 +2655,17 @@ bool intel_bios_is_port_edp(struct drm_i915_private *i915, enum port port)
+ return false;
+ }
+
+-static bool child_dev_is_dp_dual_mode(const struct child_device_config *child,
+- enum port port)
++static bool child_dev_is_dp_dual_mode(const struct child_device_config *child)
+ {
+- static const struct {
+- u16 dp, hdmi;
+- } port_mapping[] = {
+- /*
+- * Buggy VBTs may declare DP ports as having
+- * HDMI type dvo_port :( So let's check both.
+- */
+- [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, },
+- [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
+- [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
+- [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
+- [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, },
+- };
+-
+- if (port == PORT_A || port >= ARRAY_SIZE(port_mapping))
+- return false;
+-
+ if ((child->device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) !=
+ (DEVICE_TYPE_DP_DUAL_MODE & DEVICE_TYPE_DP_DUAL_MODE_BITS))
+ return false;
+
+- if (child->dvo_port == port_mapping[port].dp)
++ if (dvo_port_type(child->dvo_port) == DVO_PORT_DPA)
+ return true;
+
+ /* Only accept a HDMI dvo_port as DP++ if it has an AUX channel */
+- if (child->dvo_port == port_mapping[port].hdmi &&
++ if (dvo_port_type(child->dvo_port) == DVO_PORT_HDMIA &&
+ child->aux_channel != 0)
+ return true;
+
+@@ -2660,10 +2675,36 @@ static bool child_dev_is_dp_dual_mode(const struct child_device_config *child,
+ bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *i915,
+ enum port port)
+ {
++ static const struct {
++ u16 dp, hdmi;
++ } port_mapping[] = {
++ /*
++ * Buggy VBTs may declare DP ports as having
++ * HDMI type dvo_port :( So let's check both.
++ */
++ [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, },
++ [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
++ [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
++ [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
++ [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, },
++ };
+ const struct intel_bios_encoder_data *devdata;
+
++ if (HAS_DDI(i915)) {
++ const struct intel_bios_encoder_data *devdata;
++
++ devdata = intel_bios_encoder_data_lookup(i915, port);
++
++ return devdata && child_dev_is_dp_dual_mode(&devdata->child);
++ }
++
++ if (port == PORT_A || port >= ARRAY_SIZE(port_mapping))
++ return false;
++
+ list_for_each_entry(devdata, &i915->vbt.display_devices, node) {
+- if (child_dev_is_dp_dual_mode(&devdata->child, port))
++ if ((devdata->child.dvo_port == port_mapping[port].dp ||
++ devdata->child.dvo_port == port_mapping[port].hdmi) &&
++ child_dev_is_dp_dual_mode(&devdata->child))
+ return true;
+ }
+
+diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
+index bd184325d0c75..82e5064b4ce7b 100644
+--- a/drivers/gpu/drm/i915/display/intel_ddi.c
++++ b/drivers/gpu/drm/i915/display/intel_ddi.c
+@@ -4432,6 +4432,7 @@ static void intel_ddi_encoder_shutdown(struct intel_encoder *encoder)
+ enum phy phy = intel_port_to_phy(i915, encoder->port);
+
+ intel_dp_encoder_shutdown(encoder);
++ intel_hdmi_encoder_shutdown(encoder);
+
+ if (!intel_phy_is_tc(i915, phy))
+ return;
+diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
+index 6beeeeba1bed2..b56850d964919 100644
+--- a/drivers/gpu/drm/i915/display/intel_display_types.h
++++ b/drivers/gpu/drm/i915/display/intel_display_types.h
+@@ -1639,6 +1639,9 @@ struct intel_dp {
+ struct intel_dp_pcon_frl frl;
+
+ struct intel_psr psr;
++
++ /* When we last wrote the OUI for eDP */
++ unsigned long last_oui_write;
+ };
+
+ enum lspcon_vendor {
+diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
+index b3c8e1c450efb..73076737add75 100644
+--- a/drivers/gpu/drm/i915/display/intel_dmc.c
++++ b/drivers/gpu/drm/i915/display/intel_dmc.c
+@@ -606,7 +606,7 @@ static void parse_dmc_fw(struct drm_i915_private *dev_priv,
+ continue;
+
+ offset = readcount + dmc->dmc_info[id].dmc_offset * 4;
+- if (fw->size - offset < 0) {
++ if (offset > fw->size) {
+ drm_err(&dev_priv->drm, "Reading beyond the fw_size\n");
+ continue;
+ }
+diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
+index 5cf152be44877..d55363f1fa102 100644
+--- a/drivers/gpu/drm/i915/display/intel_dp.c
++++ b/drivers/gpu/drm/i915/display/intel_dp.c
+@@ -29,6 +29,7 @@
+ #include <linux/i2c.h>
+ #include <linux/notifier.h>
+ #include <linux/slab.h>
++#include <linux/timekeeping.h>
+ #include <linux/types.h>
+
+ #include <asm/byteorder.h>
+@@ -111,6 +112,12 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp)
+ static void intel_dp_unset_edid(struct intel_dp *intel_dp);
+ static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc);
+
++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)
+ {
+@@ -1767,6 +1774,12 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
+ intel_dp->lane_count = lane_count;
+ }
+
++static void intel_dp_reset_max_link_params(struct intel_dp *intel_dp)
++{
++ intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
++ intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
++}
++
+ /* Enable backlight PWM and backlight PP control. */
+ void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state)
+@@ -1852,6 +1865,16 @@ intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful)
+
+ if (drm_dp_dpcd_write(&intel_dp->aux, DP_SOURCE_OUI, oui, sizeof(oui)) < 0)
+ drm_err(&i915->drm, "Failed to write source OUI\n");
++
++ intel_dp->last_oui_write = jiffies;
++}
++
++void intel_dp_wait_source_oui(struct intel_dp *intel_dp)
++{
++ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
++
++ drm_dbg_kms(&i915->drm, "Performing OUI wait\n");
++ wait_remaining_ms_from_jiffies(intel_dp->last_oui_write, 30);
+ }
+
+ /* If the device supports it, try to set the power state appropriately */
+@@ -1926,8 +1949,7 @@ void intel_dp_sync_state(struct intel_encoder *encoder,
+ if (intel_dp->dpcd[DP_DPCD_REV] == 0)
+ intel_dp_get_dpcd(intel_dp);
+
+- intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+- intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
++ intel_dp_reset_max_link_params(intel_dp);
+ }
+
+ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
+@@ -2462,6 +2484,9 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
+ */
+ 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];
+@@ -2497,6 +2522,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
+ intel_dp_set_sink_rates(intel_dp);
+
+ intel_dp_set_common_rates(intel_dp);
++ intel_dp_reset_max_link_params(intel_dp);
+
+ /* Read the eDP DSC DPCD registers */
+ if (DISPLAY_VER(dev_priv) >= 10)
+@@ -4240,12 +4266,7 @@ intel_dp_detect(struct drm_connector *connector,
+ * supports link training fallback params.
+ */
+ if (intel_dp->reset_link_params || intel_dp->is_mst) {
+- /* Initial max link lane count */
+- intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp);
+-
+- /* Initial max link rate */
+- intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
+-
++ intel_dp_reset_max_link_params(intel_dp);
+ intel_dp->reset_link_params = false;
+ }
+
+@@ -5296,6 +5317,9 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
+ 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_max_link_params(intel_dp);
+
+ intel_dp->reset_link_params = true;
+ intel_dp->pps.pps_pipe = INVALID_PIPE;
+diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
+index 680631b5b4378..2121aaa9b8db0 100644
+--- a/drivers/gpu/drm/i915/display/intel_dp.h
++++ b/drivers/gpu/drm/i915/display/intel_dp.h
+@@ -129,4 +129,6 @@ void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+ void intel_dp_phy_test(struct intel_encoder *encoder);
+
++void intel_dp_wait_source_oui(struct intel_dp *intel_dp);
++
+ #endif /* __INTEL_DP_H__ */
+diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+index 6ac568617ef37..c82f8febe7303 100644
+--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+@@ -35,6 +35,7 @@
+ */
+
+ #include "intel_display_types.h"
++#include "intel_dp.h"
+ #include "intel_dp_aux_backlight.h"
+ #include "intel_panel.h"
+
+@@ -106,6 +107,8 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
+ int ret;
+ u8 tcon_cap[4];
+
++ intel_dp_wait_source_oui(intel_dp);
++
+ ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
+ if (ret != sizeof(tcon_cap))
+ return false;
+@@ -204,6 +207,8 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
+ int ret;
+ u8 old_ctrl, ctrl;
+
++ intel_dp_wait_source_oui(intel_dp);
++
+ ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
+ if (ret != 1) {
+ drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret);
+diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
+index c60a81a81c09c..c6413c5409420 100644
+--- a/drivers/gpu/drm/i915/display/intel_fb.c
++++ b/drivers/gpu/drm/i915/display/intel_fb.c
+@@ -172,8 +172,9 @@ static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_pl
+
+ intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane);
+ intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane);
+- *w = fb->base.width / main_hsub / hsub;
+- *h = fb->base.height / main_vsub / vsub;
++
++ *w = DIV_ROUND_UP(fb->base.width, main_hsub * hsub);
++ *h = DIV_ROUND_UP(fb->base.height, main_vsub * vsub);
+ }
+
+ static u32 intel_adjust_tile_offset(int *x, int *y,
+diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
+index b04685bb6439c..c3787512295dd 100644
+--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
++++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
+@@ -53,21 +53,20 @@
+ #include "intel_panel.h"
+ #include "intel_snps_phy.h"
+
+-static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
++static struct drm_i915_private *intel_hdmi_to_i915(struct intel_hdmi *intel_hdmi)
+ {
+- return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
++ return to_i915(hdmi_to_dig_port(intel_hdmi)->base.base.dev);
+ }
+
+ static void
+ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
+ {
+- struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
+- struct drm_i915_private *dev_priv = to_i915(dev);
++ struct drm_i915_private *dev_priv = intel_hdmi_to_i915(intel_hdmi);
+ u32 enabled_bits;
+
+ enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
+
+- drm_WARN(dev,
++ drm_WARN(&dev_priv->drm,
+ intel_de_read(dev_priv, intel_hdmi->hdmi_reg) & enabled_bits,
+ "HDMI port enabled, expecting disabled\n");
+ }
+@@ -1246,13 +1245,14 @@ static void hsw_set_infoframes(struct intel_encoder *encoder,
+
+ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
+ {
+- struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
+- struct i2c_adapter *adapter =
+- intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
++ struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi);
++ struct i2c_adapter *adapter;
+
+ if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
+ return;
+
++ adapter = intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
++
+ drm_dbg_kms(&dev_priv->drm, "%s DP dual mode adaptor TMDS output\n",
+ enable ? "Enabling" : "Disabling");
+
+@@ -1830,7 +1830,7 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi,
+ int clock, bool respect_downstream_limits,
+ bool has_hdmi_sink)
+ {
+- struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
++ struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi);
+
+ if (clock < 25000)
+ return MODE_CLOCK_LOW;
+@@ -1946,8 +1946,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+ {
+ struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector));
+- struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+- struct drm_i915_private *dev_priv = to_i915(dev);
++ struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi);
+ enum drm_mode_status status;
+ int clock = mode->clock;
+ int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+@@ -2260,6 +2259,17 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
+ return 0;
+ }
+
++void intel_hdmi_encoder_shutdown(struct intel_encoder *encoder)
++{
++ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
++
++ /*
++ * Give a hand to buggy BIOSen which forget to turn
++ * the TMDS output buffers back on after a reboot.
++ */
++ intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
++}
++
+ static void
+ intel_hdmi_unset_edid(struct drm_connector *connector)
+ {
+diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h
+index b43a180d007e0..2bf440eb400ab 100644
+--- a/drivers/gpu/drm/i915/display/intel_hdmi.h
++++ b/drivers/gpu/drm/i915/display/intel_hdmi.h
+@@ -28,6 +28,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
+ int intel_hdmi_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config,
+ struct drm_connector_state *conn_state);
++void intel_hdmi_encoder_shutdown(struct intel_encoder *encoder);
+ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
+ struct drm_connector *connector,
+ bool high_tmds_clock_ratio,
+diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+index de5f9c86b9a44..cafb0608ffb46 100644
+--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+@@ -2140,10 +2140,6 @@ static void __execlists_unhold(struct i915_request *rq)
+ if (p->flags & I915_DEPENDENCY_WEAK)
+ continue;
+
+- /* Propagate any change in error status */
+- if (rq->fence.error)
+- i915_request_set_error_once(w, rq->fence.error);
+-
+ if (w->engine != rq->engine)
+ continue;
+
+diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
+index aae609d7d85dd..6b5ab19a2ada9 100644
+--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
++++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
+@@ -621,13 +621,6 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
+ FF_MODE2_GS_TIMER_MASK,
+ FF_MODE2_GS_TIMER_224,
+ 0, false);
+-
+- /*
+- * Wa_14012131227:dg1
+- * Wa_1508744258:tgl,rkl,dg1,adl-s,adl-p
+- */
+- wa_masked_en(wal, GEN7_COMMON_SLICE_CHICKEN1,
+- GEN9_RHWO_OPTIMIZATION_DISABLE);
+ }
+
+ static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine,
+diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+index 87d8dc8f51b96..93c9de8f43e8e 100644
+--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+@@ -148,11 +148,12 @@ static inline void clr_context_registered(struct intel_context *ce)
+ #define SCHED_STATE_BLOCKED_SHIFT 4
+ #define SCHED_STATE_BLOCKED BIT(SCHED_STATE_BLOCKED_SHIFT)
+ #define SCHED_STATE_BLOCKED_MASK (0xfff << SCHED_STATE_BLOCKED_SHIFT)
++
+ static inline void init_sched_state(struct intel_context *ce)
+ {
+ /* Only should be called from guc_lrc_desc_pin() */
+ atomic_set(&ce->guc_sched_state_no_lock, 0);
+- ce->guc_state.sched_state = 0;
++ ce->guc_state.sched_state &= SCHED_STATE_BLOCKED_MASK;
+ }
+
+ static inline bool
+@@ -352,20 +353,29 @@ static inline void set_lrc_desc_registered(struct intel_guc *guc, u32 id,
+ xa_unlock_irqrestore(&guc->context_lookup, flags);
+ }
+
++static void decr_outstanding_submission_g2h(struct intel_guc *guc)
++{
++ if (atomic_dec_and_test(&guc->outstanding_submission_g2h))
++ wake_up_all(&guc->ct.wq);
++}
++
+ static int guc_submission_send_busy_loop(struct intel_guc *guc,
+ const u32 *action,
+ u32 len,
+ u32 g2h_len_dw,
+ bool loop)
+ {
+- int err;
+-
+- err = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop);
++ /*
++ * We always loop when a send requires a reply (i.e. g2h_len_dw > 0),
++ * so we don't handle the case where we don't get a reply because we
++ * aborted the send due to the channel being busy.
++ */
++ GEM_BUG_ON(g2h_len_dw && !loop);
+
+- if (!err && g2h_len_dw)
++ if (g2h_len_dw)
+ atomic_inc(&guc->outstanding_submission_g2h);
+
+- return err;
++ return intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop);
+ }
+
+ int intel_guc_wait_for_pending_msg(struct intel_guc *guc,
+@@ -616,7 +626,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc)
+ init_sched_state(ce);
+
+ if (pending_enable || destroyed || deregister) {
+- atomic_dec(&guc->outstanding_submission_g2h);
++ decr_outstanding_submission_g2h(guc);
+ if (deregister)
+ guc_signal_context_fence(ce);
+ if (destroyed) {
+@@ -635,7 +645,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc)
+ intel_engine_signal_breadcrumbs(ce->engine);
+ }
+ intel_context_sched_disable_unpin(ce);
+- atomic_dec(&guc->outstanding_submission_g2h);
++ decr_outstanding_submission_g2h(guc);
+ spin_lock_irqsave(&ce->guc_state.lock, flags);
+ guc_blocked_fence_complete(ce);
+ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+@@ -797,15 +807,13 @@ __unwind_incomplete_requests(struct intel_context *ce)
+
+ spin_lock_irqsave(&sched_engine->lock, flags);
+ spin_lock(&ce->guc_active.lock);
+- list_for_each_entry_safe(rq, rn,
+- &ce->guc_active.requests,
+- sched.link) {
++ list_for_each_entry_safe_reverse(rq, rn,
++ &ce->guc_active.requests,
++ sched.link) {
+ if (i915_request_completed(rq))
+ continue;
+
+ list_del_init(&rq->sched.link);
+- spin_unlock(&ce->guc_active.lock);
+-
+ __i915_request_unsubmit(rq);
+
+ /* Push the request back into the queue for later resubmission. */
+@@ -816,10 +824,8 @@ __unwind_incomplete_requests(struct intel_context *ce)
+ }
+ GEM_BUG_ON(i915_sched_engine_is_empty(sched_engine));
+
+- list_add_tail(&rq->sched.link, pl);
++ list_add(&rq->sched.link, pl);
+ set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
+-
+- spin_lock(&ce->guc_active.lock);
+ }
+ spin_unlock(&ce->guc_active.lock);
+ spin_unlock_irqrestore(&sched_engine->lock, flags);
+@@ -828,17 +834,33 @@ __unwind_incomplete_requests(struct intel_context *ce)
+ static void __guc_reset_context(struct intel_context *ce, bool stalled)
+ {
+ struct i915_request *rq;
++ unsigned long flags;
+ u32 head;
++ bool skip = false;
+
+ intel_context_get(ce);
+
+ /*
+- * GuC will implicitly mark the context as non-schedulable
+- * when it sends the reset notification. Make sure our state
+- * reflects this change. The context will be marked enabled
+- * on resubmission.
++ * GuC will implicitly mark the context as non-schedulable when it sends
++ * the reset notification. Make sure our state reflects this change. The
++ * context will be marked enabled on resubmission.
++ *
++ * XXX: If the context is reset as a result of the request cancellation
++ * this G2H is received after the schedule disable complete G2H which is
++ * wrong as this creates a race between the request cancellation code
++ * re-submitting the context and this G2H handler. This is a bug in the
++ * GuC but can be worked around in the meantime but converting this to a
++ * NOP if a pending enable is in flight as this indicates that a request
++ * cancellation has occurred.
+ */
+- clr_context_enabled(ce);
++ spin_lock_irqsave(&ce->guc_state.lock, flags);
++ if (likely(!context_pending_enable(ce)))
++ clr_context_enabled(ce);
++ else
++ skip = true;
++ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
++ if (unlikely(skip))
++ goto out_put;
+
+ rq = intel_context_find_active_request(ce);
+ if (!rq) {
+@@ -857,6 +879,7 @@ static void __guc_reset_context(struct intel_context *ce, bool stalled)
+ out_replay:
+ guc_reset_state(ce, head, stalled);
+ __unwind_incomplete_requests(ce);
++out_put:
+ intel_context_put(ce);
+ }
+
+@@ -1233,8 +1256,7 @@ static int register_context(struct intel_context *ce, bool loop)
+ }
+
+ static int __guc_action_deregister_context(struct intel_guc *guc,
+- u32 guc_id,
+- bool loop)
++ u32 guc_id)
+ {
+ u32 action[] = {
+ INTEL_GUC_ACTION_DEREGISTER_CONTEXT,
+@@ -1243,16 +1265,16 @@ static int __guc_action_deregister_context(struct intel_guc *guc,
+
+ return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action),
+ G2H_LEN_DW_DEREGISTER_CONTEXT,
+- loop);
++ true);
+ }
+
+-static int deregister_context(struct intel_context *ce, u32 guc_id, bool loop)
++static int deregister_context(struct intel_context *ce, u32 guc_id)
+ {
+ struct intel_guc *guc = ce_to_guc(ce);
+
+ trace_intel_context_deregister(ce);
+
+- return __guc_action_deregister_context(guc, guc_id, loop);
++ return __guc_action_deregister_context(guc, guc_id);
+ }
+
+ static intel_engine_mask_t adjust_engine_mask(u8 class, intel_engine_mask_t mask)
+@@ -1340,26 +1362,23 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop)
+ * registering this context.
+ */
+ if (context_registered) {
++ bool disabled;
++ unsigned long flags;
++
+ trace_intel_context_steal_guc_id(ce);
+- if (!loop) {
++ GEM_BUG_ON(!loop);
++
++ /* Seal race with Reset */
++ spin_lock_irqsave(&ce->guc_state.lock, flags);
++ disabled = submission_disabled(guc);
++ if (likely(!disabled)) {
+ set_context_wait_for_deregister_to_register(ce);
+ intel_context_get(ce);
+- } else {
+- bool disabled;
+- unsigned long flags;
+-
+- /* Seal race with Reset */
+- spin_lock_irqsave(&ce->guc_state.lock, flags);
+- disabled = submission_disabled(guc);
+- if (likely(!disabled)) {
+- set_context_wait_for_deregister_to_register(ce);
+- intel_context_get(ce);
+- }
+- spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+- if (unlikely(disabled)) {
+- reset_lrc_desc(guc, desc_idx);
+- return 0; /* Will get registered later */
+- }
++ }
++ spin_unlock_irqrestore(&ce->guc_state.lock, flags);
++ if (unlikely(disabled)) {
++ reset_lrc_desc(guc, desc_idx);
++ return 0; /* Will get registered later */
+ }
+
+ /*
+@@ -1367,13 +1386,9 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop)
+ * context whose guc_id was stolen.
+ */
+ with_intel_runtime_pm(runtime_pm, wakeref)
+- ret = deregister_context(ce, ce->guc_id, loop);
+- if (unlikely(ret == -EBUSY)) {
+- clr_context_wait_for_deregister_to_register(ce);
+- intel_context_put(ce);
+- } else if (unlikely(ret == -ENODEV)) {
++ ret = deregister_context(ce, ce->guc_id);
++ if (unlikely(ret == -ENODEV))
+ ret = 0; /* Will get registered later */
+- }
+ } else {
+ with_intel_runtime_pm(runtime_pm, wakeref)
+ ret = register_context(ce, loop);
+@@ -1548,6 +1563,23 @@ static struct i915_sw_fence *guc_context_block(struct intel_context *ce)
+ return &ce->guc_blocked;
+ }
+
++#define SCHED_STATE_MULTI_BLOCKED_MASK \
++ (SCHED_STATE_BLOCKED_MASK & ~SCHED_STATE_BLOCKED)
++#define SCHED_STATE_NO_UNBLOCK \
++ (SCHED_STATE_MULTI_BLOCKED_MASK | \
++ SCHED_STATE_PENDING_DISABLE | \
++ SCHED_STATE_BANNED)
++
++static bool context_cant_unblock(struct intel_context *ce)
++{
++ lockdep_assert_held(&ce->guc_state.lock);
++
++ return (ce->guc_state.sched_state & SCHED_STATE_NO_UNBLOCK) ||
++ context_guc_id_invalid(ce) ||
++ !lrc_desc_registered(ce_to_guc(ce), ce->guc_id) ||
++ !intel_context_is_pinned(ce);
++}
++
+ static void guc_context_unblock(struct intel_context *ce)
+ {
+ struct intel_guc *guc = ce_to_guc(ce);
+@@ -1562,9 +1594,7 @@ static void guc_context_unblock(struct intel_context *ce)
+ spin_lock_irqsave(&ce->guc_state.lock, flags);
+
+ if (unlikely(submission_disabled(guc) ||
+- !intel_context_is_pinned(ce) ||
+- context_pending_disable(ce) ||
+- context_blocked(ce) > 1)) {
++ context_cant_unblock(ce))) {
+ enable = false;
+ } else {
+ enable = true;
+@@ -1601,6 +1631,13 @@ static void guc_context_cancel_request(struct intel_context *ce,
+ guc_reset_state(ce, intel_ring_wrap(ce->ring, rq->head),
+ true);
+ }
++
++ /*
++ * XXX: Racey if context is reset, see comment in
++ * __guc_reset_context().
++ */
++ flush_work(&ce_to_guc(ce)->ct.requests.worker);
++
+ guc_context_unblock(ce);
+ }
+ }
+@@ -1730,7 +1767,7 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce)
+ GEM_BUG_ON(context_enabled(ce));
+
+ clr_context_registered(ce);
+- deregister_context(ce, ce->guc_id, true);
++ deregister_context(ce, ce->guc_id);
+ }
+
+ static void __guc_context_destroy(struct intel_context *ce)
+@@ -2583,12 +2620,6 @@ g2h_context_lookup(struct intel_guc *guc, u32 desc_idx)
+ return ce;
+ }
+
+-static void decr_outstanding_submission_g2h(struct intel_guc *guc)
+-{
+- if (atomic_dec_and_test(&guc->outstanding_submission_g2h))
+- wake_up_all(&guc->ct.wq);
+-}
+-
+ int intel_guc_deregister_done_process_msg(struct intel_guc *guc,
+ const u32 *msg,
+ u32 len)
+@@ -2721,7 +2752,12 @@ static void guc_handle_context_reset(struct intel_guc *guc,
+ {
+ trace_intel_context_reset(ce);
+
+- if (likely(!intel_context_is_banned(ce))) {
++ /*
++ * XXX: Racey if request cancellation has occurred, see comment in
++ * __guc_reset_context().
++ */
++ if (likely(!intel_context_is_banned(ce) &&
++ !context_blocked(ce))) {
+ capture_error_state(guc, ce);
+ guc_context_replay(ce);
+ }
+diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
+index 9558e9e1b431b..cb685fe2039b4 100644
+--- a/drivers/gpu/drm/imx/imx-drm-core.c
++++ b/drivers/gpu/drm/imx/imx-drm-core.c
+@@ -81,7 +81,6 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
+ struct drm_plane_state *old_plane_state, *new_plane_state;
+ bool plane_disabling = false;
+ int i;
+- bool fence_cookie = dma_fence_begin_signalling();
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+@@ -112,7 +111,6 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
+ }
+
+ drm_atomic_helper_commit_hw_done(state);
+- dma_fence_end_signalling(fence_cookie);
+ }
+
+ static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
+diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+index 8b73f70766a47..4347a104755a9 100644
+--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+@@ -516,11 +516,11 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
+ struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct platform_device *pdev = to_platform_device(gmu->dev);
+ void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc");
+- void __iomem *seqptr;
++ void __iomem *seqptr = NULL;
+ uint32_t pdc_address_offset;
+ bool pdc_in_aop = false;
+
+- if (!pdcptr)
++ if (IS_ERR(pdcptr))
+ goto err;
+
+ if (adreno_is_a650(adreno_gpu) || adreno_is_a660_family(adreno_gpu))
+@@ -532,7 +532,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
+
+ if (!pdc_in_aop) {
+ seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq");
+- if (!seqptr)
++ if (IS_ERR(seqptr))
+ goto err;
+ }
+
+diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+index 267a880811d65..723074aae5b63 100644
+--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+@@ -1424,17 +1424,24 @@ static void a6xx_llc_activate(struct a6xx_gpu *a6xx_gpu)
+ {
+ struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+ struct msm_gpu *gpu = &adreno_gpu->base;
+- u32 gpu_scid, cntl1_regval = 0;
++ u32 cntl1_regval = 0;
+
+ if (IS_ERR(a6xx_gpu->llc_mmio))
+ return;
+
+ if (!llcc_slice_activate(a6xx_gpu->llc_slice)) {
+- gpu_scid = llcc_get_slice_id(a6xx_gpu->llc_slice);
++ u32 gpu_scid = llcc_get_slice_id(a6xx_gpu->llc_slice);
+
+ gpu_scid &= 0x1f;
+ cntl1_regval = (gpu_scid << 0) | (gpu_scid << 5) | (gpu_scid << 10) |
+ (gpu_scid << 15) | (gpu_scid << 20);
++
++ /* On A660, the SCID programming for UCHE traffic is done in
++ * A6XX_GBIF_SCACHE_CNTL0[14:10]
++ */
++ if (adreno_is_a660_family(adreno_gpu))
++ gpu_rmw(gpu, REG_A6XX_GBIF_SCACHE_CNTL0, (0x1f << 10) |
++ (1 << 8), (gpu_scid << 10) | (1 << 8));
+ }
+
+ /*
+@@ -1471,13 +1478,6 @@ static void a6xx_llc_activate(struct a6xx_gpu *a6xx_gpu)
+ }
+
+ gpu_rmw(gpu, REG_A6XX_GBIF_SCACHE_CNTL1, GENMASK(24, 0), cntl1_regval);
+-
+- /* On A660, the SCID programming for UCHE traffic is done in
+- * A6XX_GBIF_SCACHE_CNTL0[14:10]
+- */
+- if (adreno_is_a660_family(adreno_gpu))
+- gpu_rmw(gpu, REG_A6XX_GBIF_SCACHE_CNTL0, (0x1f << 10) |
+- (1 << 8), (gpu_scid << 10) | (1 << 8));
+ }
+
+ static void a6xx_llc_slices_destroy(struct a6xx_gpu *a6xx_gpu)
+diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+index e8f65cd8eca6e..bfac7e47cb396 100644
+--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+@@ -777,12 +777,12 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
+ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+
+ a6xx_state->gmu_registers = state_kcalloc(a6xx_state,
+- 2, sizeof(*a6xx_state->gmu_registers));
++ 3, sizeof(*a6xx_state->gmu_registers));
+
+ if (!a6xx_state->gmu_registers)
+ return;
+
+- a6xx_state->nr_gmu_registers = 2;
++ a6xx_state->nr_gmu_registers = 3;
+
+ /* Get the CX GMU registers from AHB */
+ _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[0],
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
+index 69eed79324865..f9460672176aa 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
+@@ -138,11 +138,13 @@ static int _sspp_subblk_offset(struct dpu_hw_pipe *ctx,
+ 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;
+@@ -419,7 +421,7 @@ static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe *ctx,
+
+ (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,
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+index ae48f41821cfe..ad247c06e198f 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+@@ -908,6 +908,10 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)
+ return 0;
+
+ mmu = msm_iommu_new(dpu_kms->dev->dev, domain);
++ if (IS_ERR(mmu)) {
++ iommu_domain_free(domain);
++ return PTR_ERR(mmu);
++ }
+ aspace = msm_gem_address_space_create(mmu, "dpu1",
+ 0x1000, 0x100000000 - 0x1000);
+
+diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
+index eb40d8413bca9..6d36f63c33388 100644
+--- a/drivers/gpu/drm/msm/dp/dp_aux.c
++++ b/drivers/gpu/drm/msm/dp/dp_aux.c
+@@ -33,6 +33,7 @@ struct dp_aux_private {
+ bool read;
+ bool no_send_addr;
+ bool no_send_stop;
++ bool initted;
+ u32 offset;
+ u32 segment;
+
+@@ -331,6 +332,10 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
+ }
+
+ mutex_lock(&aux->mutex);
++ if (!aux->initted) {
++ ret = -EIO;
++ goto exit;
++ }
+
+ dp_aux_update_offset_and_segment(aux, msg);
+ dp_aux_transfer_helper(aux, msg, true);
+@@ -380,6 +385,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
+ }
+
+ aux->cmd_busy = false;
++
++exit:
+ mutex_unlock(&aux->mutex);
+
+ return ret;
+@@ -431,8 +438,13 @@ void dp_aux_init(struct drm_dp_aux *dp_aux)
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
++ mutex_lock(&aux->mutex);
++
+ dp_catalog_aux_enable(aux->catalog, true);
+ aux->retry_cnt = 0;
++ aux->initted = true;
++
++ mutex_unlock(&aux->mutex);
+ }
+
+ void dp_aux_deinit(struct drm_dp_aux *dp_aux)
+@@ -441,7 +453,12 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)
+
+ aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
++ mutex_lock(&aux->mutex);
++
++ aux->initted = false;
+ dp_catalog_aux_enable(aux->catalog, false);
++
++ mutex_unlock(&aux->mutex);
+ }
+
+ int dp_aux_register(struct drm_dp_aux *dp_aux)
+diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
+index b50db91cb8a7e..569c8ff062ba4 100644
+--- a/drivers/gpu/drm/msm/dsi/dsi.h
++++ b/drivers/gpu/drm/msm/dsi/dsi.h
+@@ -107,6 +107,8 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
+ u32 dma_base, u32 len);
+ int msm_dsi_host_enable(struct mipi_dsi_host *host);
+ int msm_dsi_host_disable(struct mipi_dsi_host *host);
++void msm_dsi_host_enable_irq(struct mipi_dsi_host *host);
++void msm_dsi_host_disable_irq(struct mipi_dsi_host *host);
+ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
+ struct msm_dsi_phy_shared_timings *phy_shared_timings,
+ bool is_bonded_dsi, struct msm_dsi_phy *phy);
+diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
+index c86b5090fae60..dc85974c78975 100644
+--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
+@@ -115,16 +115,16 @@ struct msm_dsi_host {
+ struct clk *pixel_clk_src;
+ struct clk *byte_intf_clk;
+
+- u32 byte_clk_rate;
+- u32 pixel_clk_rate;
+- u32 esc_clk_rate;
++ unsigned long byte_clk_rate;
++ unsigned long pixel_clk_rate;
++ unsigned long esc_clk_rate;
+
+ /* DSI v2 specific clocks */
+ struct clk *src_clk;
+ struct clk *esc_clk_src;
+ struct clk *dsi_clk_src;
+
+- u32 src_clk_rate;
++ unsigned long src_clk_rate;
+
+ struct gpio_desc *disp_en_gpio;
+ struct gpio_desc *te_gpio;
+@@ -498,10 +498,10 @@ int msm_dsi_runtime_resume(struct device *dev)
+
+ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
+ {
+- u32 byte_intf_rate;
++ unsigned long byte_intf_rate;
+ int ret;
+
+- DBG("Set clk rates: pclk=%d, byteclk=%d",
++ DBG("Set clk rates: pclk=%d, byteclk=%lu",
+ msm_host->mode->clock, msm_host->byte_clk_rate);
+
+ ret = dev_pm_opp_set_rate(&msm_host->pdev->dev,
+@@ -583,7 +583,7 @@ int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host)
+ {
+ int ret;
+
+- DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d",
++ DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu",
+ msm_host->mode->clock, msm_host->byte_clk_rate,
+ msm_host->esc_clk_rate, msm_host->src_clk_rate);
+
+@@ -673,10 +673,10 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host)
+ clk_disable_unprepare(msm_host->byte_clk);
+ }
+
+-static u32 dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
++static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+ {
+ struct drm_display_mode *mode = msm_host->mode;
+- u32 pclk_rate;
++ unsigned long pclk_rate;
+
+ pclk_rate = mode->clock * 1000;
+
+@@ -696,7 +696,7 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+ {
+ u8 lanes = msm_host->lanes;
+ u32 bpp = dsi_get_bpp(msm_host->format);
+- u32 pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi);
++ unsigned long pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi);
+ u64 pclk_bpp = (u64)pclk_rate * bpp;
+
+ if (lanes == 0) {
+@@ -713,7 +713,7 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+ msm_host->pixel_clk_rate = pclk_rate;
+ msm_host->byte_clk_rate = pclk_bpp;
+
+- DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate,
++ DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate,
+ msm_host->byte_clk_rate);
+
+ }
+@@ -772,7 +772,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+
+ msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div;
+
+- DBG("esc=%d, src=%d", msm_host->esc_clk_rate,
++ DBG("esc=%lu, src=%lu", msm_host->esc_clk_rate,
+ msm_host->src_clk_rate);
+
+ return 0;
+@@ -1696,6 +1696,8 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
+ 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;
+ }
+
+@@ -1898,6 +1900,23 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
+ return ret;
+ }
+
++ msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
++ if (msm_host->irq < 0) {
++ ret = msm_host->irq;
++ dev_err(&pdev->dev, "failed to get irq: %d\n", ret);
++ return ret;
++ }
++
++ /* do not autoenable, will be enabled later */
++ ret = devm_request_irq(&pdev->dev, msm_host->irq, dsi_host_irq,
++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN,
++ "dsi_isr", msm_host);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "failed to request IRQ%u: %d\n",
++ msm_host->irq, ret);
++ return ret;
++ }
++
+ init_completion(&msm_host->dma_comp);
+ init_completion(&msm_host->video_comp);
+ mutex_init(&msm_host->dev_mutex);
+@@ -1941,25 +1960,8 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
+ {
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+ const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+- struct platform_device *pdev = msm_host->pdev;
+ int ret;
+
+- msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+- if (msm_host->irq < 0) {
+- ret = msm_host->irq;
+- DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret);
+- return ret;
+- }
+-
+- ret = devm_request_irq(&pdev->dev, msm_host->irq,
+- dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+- "dsi_isr", msm_host);
+- if (ret < 0) {
+- DRM_DEV_ERROR(&pdev->dev, "failed to request IRQ%u: %d\n",
+- msm_host->irq, ret);
+- return ret;
+- }
+-
+ msm_host->dev = dev;
+ ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
+ if (ret) {
+@@ -2315,6 +2317,20 @@ void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host,
+ clk_req->escclk_rate = msm_host->esc_clk_rate;
+ }
+
++void msm_dsi_host_enable_irq(struct mipi_dsi_host *host)
++{
++ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
++
++ enable_irq(msm_host->irq);
++}
++
++void msm_dsi_host_disable_irq(struct mipi_dsi_host *host)
++{
++ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
++
++ disable_irq(msm_host->irq);
++}
++
+ int msm_dsi_host_enable(struct mipi_dsi_host *host)
+ {
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
+index c41d39f5b7cf4..fb4ccffdcfe13 100644
+--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
++++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
+@@ -377,6 +377,14 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
+ }
+ }
+
++ /*
++ * Enable before preparing the panel, disable after unpreparing, so
++ * that the panel can communicate over the DSI link.
++ */
++ msm_dsi_host_enable_irq(host);
++ if (is_bonded_dsi && msm_dsi1)
++ msm_dsi_host_enable_irq(msm_dsi1->host);
++
+ /* Always call panel functions once, because even for dual panels,
+ * there is only one drm_panel instance.
+ */
+@@ -411,6 +419,10 @@ host_en_fail:
+ if (panel)
+ drm_panel_unprepare(panel);
+ panel_prep_fail:
++ msm_dsi_host_disable_irq(host);
++ if (is_bonded_dsi && msm_dsi1)
++ msm_dsi_host_disable_irq(msm_dsi1->host);
++
+ if (is_bonded_dsi && msm_dsi1)
+ msm_dsi_host_power_off(msm_dsi1->host);
+ host1_on_fail:
+@@ -523,6 +535,10 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
+ id, ret);
+ }
+
++ msm_dsi_host_disable_irq(host);
++ if (is_bonded_dsi && msm_dsi1)
++ msm_dsi_host_disable_irq(msm_dsi1->host);
++
+ /* Save PHY status if it is a clock source */
+ msm_dsi_phy_pll_save_state(msm_dsi->phy);
+
+diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
+index 09d2d279c30ae..dee13fedee3b5 100644
+--- a/drivers/gpu/drm/msm/msm_debugfs.c
++++ b/drivers/gpu/drm/msm/msm_debugfs.c
+@@ -77,6 +77,7 @@ static int msm_gpu_open(struct inode *inode, struct file *file)
+ 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);
+
+diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
+index d4e09703a87db..27f737a253c77 100644
+--- a/drivers/gpu/drm/msm/msm_drv.c
++++ b/drivers/gpu/drm/msm/msm_drv.c
+@@ -938,29 +938,18 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
+ return ret;
+ }
+
+-static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
+- struct drm_file *file)
++static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id,
++ ktime_t timeout)
+ {
+- struct msm_drm_private *priv = dev->dev_private;
+- struct drm_msm_wait_fence *args = data;
+- ktime_t timeout = to_ktime(args->timeout);
+- struct msm_gpu_submitqueue *queue;
+- struct msm_gpu *gpu = priv->gpu;
+ struct dma_fence *fence;
+ int ret;
+
+- if (args->pad) {
+- DRM_ERROR("invalid pad: %08x\n", args->pad);
++ if (fence_id > queue->last_fence) {
++ DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n",
++ fence_id, queue->last_fence);
+ return -EINVAL;
+ }
+
+- if (!gpu)
+- return 0;
+-
+- queue = msm_submitqueue_get(file->driver_priv, args->queueid);
+- if (!queue)
+- return -ENOENT;
+-
+ /*
+ * Map submitqueue scoped "seqno" (which is actually an idr key)
+ * back to underlying dma-fence
+@@ -972,7 +961,7 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
+ ret = mutex_lock_interruptible(&queue->lock);
+ if (ret)
+ return ret;
+- fence = idr_find(&queue->fence_idr, args->fence);
++ fence = idr_find(&queue->fence_idr, fence_id);
+ if (fence)
+ fence = dma_fence_get_rcu(fence);
+ mutex_unlock(&queue->lock);
+@@ -988,6 +977,32 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
+ }
+
+ dma_fence_put(fence);
++
++ return ret;
++}
++
++static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
++ struct drm_file *file)
++{
++ struct msm_drm_private *priv = dev->dev_private;
++ struct drm_msm_wait_fence *args = data;
++ struct msm_gpu_submitqueue *queue;
++ int ret;
++
++ if (args->pad) {
++ DRM_ERROR("invalid pad: %08x\n", args->pad);
++ return -EINVAL;
++ }
++
++ if (!priv->gpu)
++ return 0;
++
++ queue = msm_submitqueue_get(file->driver_priv, args->queueid);
++ if (!queue)
++ return -ENOENT;
++
++ ret = wait_fence(queue, args->fence, to_ktime(args->timeout));
++
+ msm_submitqueue_put(queue);
+
+ return ret;
+diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
+index 22308a1b66fc3..cb52ac01e5122 100644
+--- a/drivers/gpu/drm/msm/msm_gem.c
++++ b/drivers/gpu/drm/msm/msm_gem.c
+@@ -1055,8 +1055,7 @@ static int msm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
+ {
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+- vma->vm_flags &= ~VM_PFNMAP;
+- vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
++ vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_page_prot = msm_gem_pgprot(msm_obj, vm_get_page_prot(vma->vm_flags));
+
+ return 0;
+@@ -1132,6 +1131,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
+ msm_obj->flags = flags;
+ msm_obj->madv = MSM_MADV_WILLNEED;
+
++ INIT_LIST_HEAD(&msm_obj->node);
+ INIT_LIST_HEAD(&msm_obj->vmas);
+
+ *obj = &msm_obj->base;
+@@ -1166,7 +1166,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32
+
+ ret = msm_gem_new_impl(dev, size, flags, &obj);
+ if (ret)
+- goto fail;
++ return ERR_PTR(ret);
+
+ msm_obj = to_msm_bo(obj);
+
+@@ -1250,7 +1250,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
+
+ 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);
+
+diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
+index 151d19e4453cd..d9aef97eb93ad 100644
+--- a/drivers/gpu/drm/msm/msm_gem_submit.c
++++ b/drivers/gpu/drm/msm/msm_gem_submit.c
+@@ -780,6 +780,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
+ args->nr_cmds);
+ if (IS_ERR(submit)) {
+ ret = PTR_ERR(submit);
++ submit = NULL;
+ goto out_unlock;
+ }
+
+@@ -911,6 +912,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
+ drm_sched_entity_push_job(&submit->base, queue->entity);
+
+ args->fence = submit->fence_id;
++ queue->last_fence = submit->fence_id;
+
+ msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs);
+ msm_process_post_deps(post_deps, args->nr_out_syncobjs,
+diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
+index 8a3a592da3a4d..2c46cd968ac4c 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.c
++++ b/drivers/gpu/drm/msm/msm_gpu.c
+@@ -296,7 +296,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu,
+ state->bos = kcalloc(nr,
+ sizeof(struct msm_gpu_state_bo), GFP_KERNEL);
+
+- for (i = 0; i < submit->nr_bos; i++) {
++ for (i = 0; state->bos && i < submit->nr_bos; i++) {
+ if (should_dump(submit, i)) {
+ msm_gpu_crashstate_get_bo(state, submit->bos[i].obj,
+ submit->bos[i].iova, submit->bos[i].flags);
+diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
+index ee25d556c8a10..2e2424066e701 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.h
++++ b/drivers/gpu/drm/msm/msm_gpu.h
+@@ -352,6 +352,8 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio,
+ * @ring_nr: the ringbuffer used by this submitqueue, which is determined
+ * by the submitqueue's priority
+ * @faults: the number of GPU hangs associated with this submitqueue
++ * @last_fence: the sequence number of the last allocated fence (for error
++ * checking)
+ * @ctx: the per-drm_file context associated with the submitqueue (ie.
+ * which set of pgtables do submits jobs associated with the
+ * submitqueue use)
+@@ -367,6 +369,7 @@ struct msm_gpu_submitqueue {
+ u32 flags;
+ u32 ring_nr;
+ int faults;
++ uint32_t last_fence;
+ struct msm_file_private *ctx;
+ struct list_head node;
+ struct idr fence_idr;
+diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
+index 20006d060b5b5..4ac2a4eb984d8 100644
+--- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c
++++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
+@@ -20,6 +20,10 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
+ struct msm_gpu *gpu = dev_to_gpu(dev);
+ struct dev_pm_opp *opp;
+
++ /*
++ * Note that devfreq_recommended_opp() can modify the freq
++ * to something that actually is in the opp table:
++ */
+ opp = devfreq_recommended_opp(dev, freq, flags);
+
+ /*
+@@ -28,6 +32,7 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
+ */
+ if (gpu->devfreq.idle_freq) {
+ gpu->devfreq.idle_freq = *freq;
++ dev_pm_opp_put(opp);
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c
+index b8621c6e05546..7cb158bcbcf67 100644
+--- a/drivers/gpu/drm/msm/msm_submitqueue.c
++++ b/drivers/gpu/drm/msm/msm_submitqueue.c
+@@ -101,6 +101,7 @@ get_sched_entity(struct msm_file_private *ctx, struct msm_ringbuffer *ring,
+
+ ret = drm_sched_entity_init(entity, sched_prio, &sched, 1, NULL);
+ if (ret) {
++ mutex_unlock(&entity_lock);
+ kfree(entity);
+ return ERR_PTR(ret);
+ }
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
+index 6109cd9e33991..e7efd9ede8e4b 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
+@@ -562,6 +562,7 @@ nouveau_drm_device_init(struct drm_device *dev)
+ 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
+@@ -632,6 +633,7 @@ fail_alloc:
+ 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()) {
+@@ -656,9 +658,28 @@ nouveau_drm_device_fini(struct drm_device *dev)
+ 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);
+ nvif_parent_dtor(&drm->parent);
++ mutex_destroy(&drm->clients_lock);
+ kfree(drm);
+ }
+
+@@ -796,7 +817,7 @@ nouveau_drm_device_remove(struct drm_device *dev)
+ struct nvkm_client *client;
+ struct nvkm_device *device;
+
+- drm_dev_unregister(dev);
++ drm_dev_unplug(dev);
+
+ client = nvxx_client(&drm->client.base);
+ device = nvkm_device_find(client->device);
+@@ -1090,9 +1111,9 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
+
+ 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) {
+@@ -1110,6 +1131,16 @@ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
+ {
+ 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);
+
+@@ -1118,14 +1149,15 @@ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
+ 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
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
+index ba65f136cf481..b2a970aa9bf4b 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
+@@ -139,6 +139,11 @@ struct nouveau_drm {
+
+ 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 {
+diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
+index 8c2ecc2827232..c89d5964148fd 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
+@@ -56,7 +56,7 @@ static vm_fault_t nouveau_ttm_fault(struct vm_fault *vmf)
+
+ nouveau_bo_del_io_reserve_lru(bo);
+ prot = vm_get_page_prot(vma->vm_flags);
+- ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT, 1);
++ ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
+ nouveau_bo_add_io_reserve_lru(bo);
+ if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+ return ret;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
+index b0c3422cb01fa..9985bfde015a6 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
+@@ -162,10 +162,14 @@ nouveau_svmm_bind(struct drm_device *dev, void *data,
+ */
+
+ mm = get_task_mm(current);
++ if (!mm) {
++ return -EINVAL;
++ }
+ mmap_read_lock(mm);
+
+ if (!cli->svm.svmm) {
+ mmap_read_unlock(mm);
++ mmput(mm);
+ return -EINVAL;
+ }
+
+diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
+index 704df0f2d1f16..09a112af2f893 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
+@@ -78,6 +78,6 @@ int
+ gt215_ce_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
+ struct nvkm_engine **pengine)
+ {
+- return nvkm_falcon_new_(&gt215_ce, device, type, inst,
++ return nvkm_falcon_new_(&gt215_ce, device, type, -1,
+ (device->chipset != 0xaf), 0x104000, pengine);
+ }
+diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+index ca75c5f6ecaf8..88d262ba648cf 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+@@ -2626,6 +2626,27 @@ nv174_chipset = {
+ .fifo = { 0x00000001, ga102_fifo_new },
+ };
+
++static const struct nvkm_device_chip
++nv176_chipset = {
++ .name = "GA106",
++ .bar = { 0x00000001, tu102_bar_new },
++ .bios = { 0x00000001, nvkm_bios_new },
++ .devinit = { 0x00000001, ga100_devinit_new },
++ .fb = { 0x00000001, ga102_fb_new },
++ .gpio = { 0x00000001, ga102_gpio_new },
++ .i2c = { 0x00000001, gm200_i2c_new },
++ .imem = { 0x00000001, nv50_instmem_new },
++ .mc = { 0x00000001, ga100_mc_new },
++ .mmu = { 0x00000001, tu102_mmu_new },
++ .pci = { 0x00000001, gp100_pci_new },
++ .privring = { 0x00000001, gm200_privring_new },
++ .timer = { 0x00000001, gk20a_timer_new },
++ .top = { 0x00000001, ga100_top_new },
++ .disp = { 0x00000001, ga102_disp_new },
++ .dma = { 0x00000001, gv100_dma_new },
++ .fifo = { 0x00000001, ga102_fifo_new },
++};
++
+ static const struct nvkm_device_chip
+ nv177_chipset = {
+ .name = "GA107",
+@@ -3072,6 +3093,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
+ case 0x168: device->chip = &nv168_chipset; break;
+ case 0x172: device->chip = &nv172_chipset; break;
+ case 0x174: device->chip = &nv174_chipset; break;
++ case 0x176: device->chip = &nv176_chipset; break;
+ case 0x177: device->chip = &nv177_chipset; break;
+ default:
+ if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) {
+@@ -3147,8 +3169,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
+ WARN_ON(device->chip->ptr.inst & ~((1 << ARRAY_SIZE(device->ptr)) - 1)); \
+ for (j = 0; device->chip->ptr.inst && j < ARRAY_SIZE(device->ptr); j++) { \
+ if ((device->chip->ptr.inst & BIT(j)) && (subdev_mask & BIT_ULL(type))) { \
+- int inst = (device->chip->ptr.inst == 1) ? -1 : (j); \
+- ret = device->chip->ptr.ctor(device, (type), inst, &device->ptr[j]); \
++ ret = device->chip->ptr.ctor(device, (type), (j), &device->ptr[j]); \
+ subdev = nvkm_device_subdev(device, (type), (j)); \
+ if (ret) { \
+ nvkm_subdev_del(&subdev); \
+diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c
+index 6e3c450eaacef..3ff49344abc77 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigv100.c
+@@ -62,7 +62,6 @@ gv100_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
+ 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);
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
+index cdb1ead26d84f..82b4c8e1457c2 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gm200.c
+@@ -207,11 +207,13 @@ int
+ gm200_acr_wpr_parse(struct nvkm_acr *acr)
+ {
+ const struct wpr_header *hdr = (void *)acr->wpr_fw->data;
++ struct nvkm_acr_lsfw *lsfw;
+
+ while (hdr->falcon_id != WPR_HEADER_V0_FALCON_ID_INVALID) {
+ wpr_header_dump(&acr->subdev, hdr);
+- if (!nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->falcon_id))
+- return -ENOMEM;
++ lsfw = nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->falcon_id);
++ if (IS_ERR(lsfw))
++ return PTR_ERR(lsfw);
+ }
+
+ return 0;
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
+index fb9132a39bb1a..fd97a935a380e 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/gp102.c
+@@ -161,11 +161,13 @@ int
+ gp102_acr_wpr_parse(struct nvkm_acr *acr)
+ {
+ const struct wpr_header_v1 *hdr = (void *)acr->wpr_fw->data;
++ struct nvkm_acr_lsfw *lsfw;
+
+ while (hdr->falcon_id != WPR_HEADER_V1_FALCON_ID_INVALID) {
+ wpr_header_v1_dump(&acr->subdev, hdr);
+- if (!nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->falcon_id))
+- return -ENOMEM;
++ lsfw = nvkm_acr_lsfw_add(NULL, acr, NULL, (hdr++)->falcon_id);
++ if (IS_ERR(lsfw))
++ return PTR_ERR(lsfw);
+ }
+
+ return 0;
+diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
+index 458f92a708879..a36a4f2c76b09 100644
+--- a/drivers/gpu/drm/radeon/radeon_gem.c
++++ b/drivers/gpu/drm/radeon/radeon_gem.c
+@@ -61,7 +61,7 @@ static vm_fault_t radeon_gem_fault(struct vm_fault *vmf)
+ goto unlock_resv;
+
+ ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
+- TTM_BO_VM_NUM_PREFAULT, 1);
++ TTM_BO_VM_NUM_PREFAULT);
+ if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+ goto unlock_mclk;
+
+diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
+index 5755f0432e774..8c796de53222c 100644
+--- a/drivers/gpu/drm/sun4i/Kconfig
++++ b/drivers/gpu/drm/sun4i/Kconfig
+@@ -46,6 +46,7 @@ config DRM_SUN6I_DSI
+ 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
+diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
+index a55a38ad849c1..022cafa6c06cb 100644
+--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
++++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
+@@ -16,8 +16,8 @@ struct sun8i_mixer;
+ #define CCSC10_OFFSET 0xA0000
+ #define CCSC11_OFFSET 0xF0000
+
+-#define SUN8I_CSC_CTRL(base) (base + 0x0)
+-#define SUN8I_CSC_COEFF(base, i) (base + 0x10 + 4 * i)
++#define SUN8I_CSC_CTRL(base) ((base) + 0x0)
++#define SUN8I_CSC_COEFF(base, i) ((base) + 0x10 + 4 * (i))
+
+ #define SUN8I_CSC_CTRL_EN BIT(0)
+
+diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
+index 481b48bde0473..5a6e89825bc2f 100644
+--- a/drivers/gpu/drm/tiny/simpledrm.c
++++ b/drivers/gpu/drm/tiny/simpledrm.c
+@@ -458,7 +458,7 @@ static struct drm_display_mode simpledrm_mode(unsigned int width,
+ {
+ struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
+
+- mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay;
++ mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */;
+ drm_mode_set_name(&mode);
+
+ return mode;
+diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
+index f56be5bc0861e..4a655ab23c89d 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
++++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
+@@ -171,89 +171,6 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
+ }
+ EXPORT_SYMBOL(ttm_bo_vm_reserve);
+
+-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+-/**
+- * ttm_bo_vm_insert_huge - Insert a pfn for PUD or PMD faults
+- * @vmf: Fault data
+- * @bo: The buffer object
+- * @page_offset: Page offset from bo start
+- * @fault_page_size: The size of the fault in pages.
+- * @pgprot: The page protections.
+- * Does additional checking whether it's possible to insert a PUD or PMD
+- * pfn and performs the insertion.
+- *
+- * Return: VM_FAULT_NOPAGE on successful insertion, VM_FAULT_FALLBACK if
+- * a huge fault was not possible, or on insertion error.
+- */
+-static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf,
+- struct ttm_buffer_object *bo,
+- pgoff_t page_offset,
+- pgoff_t fault_page_size,
+- pgprot_t pgprot)
+-{
+- pgoff_t i;
+- vm_fault_t ret;
+- unsigned long pfn;
+- pfn_t pfnt;
+- struct ttm_tt *ttm = bo->ttm;
+- bool write = vmf->flags & FAULT_FLAG_WRITE;
+-
+- /* Fault should not cross bo boundary. */
+- page_offset &= ~(fault_page_size - 1);
+- if (page_offset + fault_page_size > bo->resource->num_pages)
+- goto out_fallback;
+-
+- if (bo->resource->bus.is_iomem)
+- pfn = ttm_bo_io_mem_pfn(bo, page_offset);
+- else
+- pfn = page_to_pfn(ttm->pages[page_offset]);
+-
+- /* pfn must be fault_page_size aligned. */
+- if ((pfn & (fault_page_size - 1)) != 0)
+- goto out_fallback;
+-
+- /* Check that memory is contiguous. */
+- if (!bo->resource->bus.is_iomem) {
+- for (i = 1; i < fault_page_size; ++i) {
+- if (page_to_pfn(ttm->pages[page_offset + i]) != pfn + i)
+- goto out_fallback;
+- }
+- } else if (bo->bdev->funcs->io_mem_pfn) {
+- for (i = 1; i < fault_page_size; ++i) {
+- if (ttm_bo_io_mem_pfn(bo, page_offset + i) != pfn + i)
+- goto out_fallback;
+- }
+- }
+-
+- pfnt = __pfn_to_pfn_t(pfn, PFN_DEV);
+- if (fault_page_size == (HPAGE_PMD_SIZE >> PAGE_SHIFT))
+- ret = vmf_insert_pfn_pmd_prot(vmf, pfnt, pgprot, write);
+-#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+- else if (fault_page_size == (HPAGE_PUD_SIZE >> PAGE_SHIFT))
+- ret = vmf_insert_pfn_pud_prot(vmf, pfnt, pgprot, write);
+-#endif
+- else
+- WARN_ON_ONCE(ret = VM_FAULT_FALLBACK);
+-
+- if (ret != VM_FAULT_NOPAGE)
+- goto out_fallback;
+-
+- return VM_FAULT_NOPAGE;
+-out_fallback:
+- count_vm_event(THP_FAULT_FALLBACK);
+- return VM_FAULT_FALLBACK;
+-}
+-#else
+-static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf,
+- struct ttm_buffer_object *bo,
+- pgoff_t page_offset,
+- pgoff_t fault_page_size,
+- pgprot_t pgprot)
+-{
+- return VM_FAULT_FALLBACK;
+-}
+-#endif
+-
+ /**
+ * ttm_bo_vm_fault_reserved - TTM fault helper
+ * @vmf: The struct vm_fault given as argument to the fault callback
+@@ -261,7 +178,6 @@ static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf,
+ * @num_prefault: Maximum number of prefault pages. The caller may want to
+ * specify this based on madvice settings and the size of the GPU object
+ * backed by the memory.
+- * @fault_page_size: The size of the fault in pages.
+ *
+ * This function inserts one or more page table entries pointing to the
+ * memory backing the buffer object, and then returns a return code
+@@ -275,8 +191,7 @@ static vm_fault_t ttm_bo_vm_insert_huge(struct vm_fault *vmf,
+ */
+ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
+ pgprot_t prot,
+- pgoff_t num_prefault,
+- pgoff_t fault_page_size)
++ pgoff_t num_prefault)
+ {
+ struct vm_area_struct *vma = vmf->vma;
+ struct ttm_buffer_object *bo = vma->vm_private_data;
+@@ -327,11 +242,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
+ prot = pgprot_decrypted(prot);
+ }
+
+- /* We don't prefault on huge faults. Yet. */
+- if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && fault_page_size != 1)
+- return ttm_bo_vm_insert_huge(vmf, bo, page_offset,
+- fault_page_size, prot);
+-
+ /*
+ * Speculatively prefault a number of pages. Only error on
+ * first page.
+@@ -429,7 +339,7 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
+
+ prot = vma->vm_page_prot;
+ if (drm_dev_enter(ddev, &idx)) {
+- ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT, 1);
++ ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
+ drm_dev_exit(idx);
+ } else {
+ ret = ttm_bo_vm_dummy_page(vmf, prot);
+@@ -519,11 +429,6 @@ int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
+
+ switch (bo->resource->mem_type) {
+ case TTM_PL_SYSTEM:
+- if (unlikely(bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
+- ret = ttm_tt_swapin(bo->ttm);
+- if (unlikely(ret != 0))
+- return ret;
+- }
+ fallthrough;
+ case TTM_PL_TT:
+ ret = ttm_bo_vm_access_kmap(bo, offset, buf, len, write);
+diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
+index 3750fd2161317..930574ad2bca9 100644
+--- a/drivers/gpu/drm/udl/udl_connector.c
++++ b/drivers/gpu/drm/udl/udl_connector.c
+@@ -30,7 +30,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block,
+ int bval = (i + block * EDID_LENGTH) << 8;
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(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);
+diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
+index 5689da118197e..772b5831bcc6f 100644
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -197,8 +197,8 @@ v3d_clean_caches(struct v3d_dev *v3d)
+
+ 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);
+diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
+index fddaeb0b09c11..f642bd6e71ff4 100644
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -391,7 +391,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
+
+ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+ if (!bo)
+- return ERR_PTR(-ENOMEM);
++ return NULL;
+
+ bo->madv = VC4_MADV_WILLNEED;
+ refcount_set(&bo->usecnt, 0);
+diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
+index f0b3e4cf5bceb..b61792d2aa657 100644
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -337,10 +337,10 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
+ struct drm_device *dev = state->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_hvs *hvs = vc4->hvs;
+- struct drm_crtc_state *old_crtc_state;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_crtc *crtc;
+ struct vc4_hvs_state *old_hvs_state;
++ unsigned int channel;
+ int i;
+
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+@@ -353,30 +353,32 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
+ vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
+ }
+
+- if (vc4->hvs->hvs5)
+- clk_set_min_rate(hvs->core_clk, 500000000);
+-
+ old_hvs_state = vc4_hvs_get_old_global_state(state);
+- if (!old_hvs_state)
++ if (IS_ERR(old_hvs_state))
+ return;
+
+- for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
+- struct vc4_crtc_state *vc4_crtc_state =
+- to_vc4_crtc_state(old_crtc_state);
+- unsigned int channel = vc4_crtc_state->assigned_channel;
++ for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
++ struct drm_crtc_commit *commit;
+ int ret;
+
+- if (channel == VC4_HVS_CHANNEL_DISABLED)
++ if (!old_hvs_state->fifo_state[channel].in_use)
+ continue;
+
+- if (!old_hvs_state->fifo_state[channel].in_use)
++ commit = old_hvs_state->fifo_state[channel].pending_commit;
++ if (!commit)
+ continue;
+
+- ret = drm_crtc_commit_wait(old_hvs_state->fifo_state[channel].pending_commit);
++ ret = drm_crtc_commit_wait(commit);
+ if (ret)
+ drm_err(dev, "Timed out waiting for commit\n");
++
++ drm_crtc_commit_put(commit);
++ old_hvs_state->fifo_state[channel].pending_commit = NULL;
+ }
+
++ if (vc4->hvs->hvs5)
++ clk_set_min_rate(hvs->core_clk, 500000000);
++
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ vc4_ctm_commit(vc4, state);
+@@ -410,8 +412,8 @@ static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
+ unsigned int i;
+
+ hvs_state = vc4_hvs_get_new_global_state(state);
+- if (!hvs_state)
+- return -EINVAL;
++ if (WARN_ON(IS_ERR(hvs_state)))
++ return PTR_ERR(hvs_state);
+
+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+ struct vc4_crtc_state *vc4_crtc_state =
+@@ -668,12 +670,6 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
+
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+ state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
+-
+- if (!old_state->fifo_state[i].pending_commit)
+- continue;
+-
+- state->fifo_state[i].pending_commit =
+- drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
+ }
+
+ return &state->base;
+@@ -762,8 +758,8 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
+ unsigned int i;
+
+ hvs_new_state = vc4_hvs_get_global_state(state);
+- if (!hvs_new_state)
+- return -EINVAL;
++ if (IS_ERR(hvs_new_state))
++ return PTR_ERR(hvs_new_state);
+
+ for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++)
+ if (!hvs_new_state->fifo_state[i].in_use)
+diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
+index 2e71e91278b45..93a41d018dca6 100644
+--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
+@@ -91,9 +91,7 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
+ {
+ 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 ||
+ size < sizeof(struct virtio_gpu_ctrl_hdr));
+@@ -147,10 +145,6 @@ static void *virtio_gpu_alloc_cmd_resp(struct virtio_gpu_device *vgdev,
+
+ 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;
+ }
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+index a833751099b55..858aff99a3fe5 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+@@ -1550,10 +1550,6 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
+ pgoff_t start, pgoff_t end);
+ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf);
+ vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf);
+-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+-vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
+- enum page_entry_size pe_size);
+-#endif
+
+ /* Transparent hugepage support - vmwgfx_thp.c */
+ #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+index e5a9a5cbd01a7..922317d1acc8a 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+@@ -477,7 +477,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
+ else
+ prot = vm_get_page_prot(vma->vm_flags);
+
+- ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault, 1);
++ ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault);
+ if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+ return ret;
+
+@@ -486,73 +486,3 @@ out_unlock:
+
+ return ret;
+ }
+-
+-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+-vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
+- enum page_entry_size pe_size)
+-{
+- struct vm_area_struct *vma = vmf->vma;
+- struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
+- vma->vm_private_data;
+- struct vmw_buffer_object *vbo =
+- container_of(bo, struct vmw_buffer_object, base);
+- pgprot_t prot;
+- vm_fault_t ret;
+- pgoff_t fault_page_size;
+- bool write = vmf->flags & FAULT_FLAG_WRITE;
+-
+- switch (pe_size) {
+- case PE_SIZE_PMD:
+- fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT;
+- break;
+-#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+- case PE_SIZE_PUD:
+- fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT;
+- break;
+-#endif
+- default:
+- WARN_ON_ONCE(1);
+- return VM_FAULT_FALLBACK;
+- }
+-
+- /* Always do write dirty-tracking and COW on PTE level. */
+- if (write && (READ_ONCE(vbo->dirty) || is_cow_mapping(vma->vm_flags)))
+- return VM_FAULT_FALLBACK;
+-
+- ret = ttm_bo_vm_reserve(bo, vmf);
+- if (ret)
+- return ret;
+-
+- if (vbo->dirty) {
+- pgoff_t allowed_prefault;
+- unsigned long page_offset;
+-
+- page_offset = vmf->pgoff -
+- drm_vma_node_start(&bo->base.vma_node);
+- if (page_offset >= bo->resource->num_pages ||
+- vmw_resources_clean(vbo, page_offset,
+- page_offset + PAGE_SIZE,
+- &allowed_prefault)) {
+- ret = VM_FAULT_SIGBUS;
+- goto out_unlock;
+- }
+-
+- /*
+- * Write protect, so we get a new fault on write, and can
+- * split.
+- */
+- prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED);
+- } else {
+- prot = vm_get_page_prot(vma->vm_flags);
+- }
+-
+- ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size);
+- if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+- return ret;
+-
+-out_unlock:
+- dma_resv_unlock(bo->base.resv);
+-
+- return ret;
+-}
+-#endif
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+index e6b1f98ec99f0..0a4c340252ec4 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+@@ -61,9 +61,6 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
+ .fault = vmw_bo_vm_fault,
+ .open = ttm_bo_vm_open,
+ .close = ttm_bo_vm_close,
+-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+- .huge_fault = vmw_bo_vm_huge_fault,
+-#endif
+ };
+ struct drm_file *file_priv = filp->private_data;
+ struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev);
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index 3c33bf572d6d3..9235ab7161e3a 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -207,14 +207,14 @@ config HID_CHERRY
+
+ 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.
+@@ -245,7 +245,7 @@ config HID_MACALLY
+
+ 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.
+@@ -553,7 +553,7 @@ config HID_LENOVO
+
+ config HID_LOGITECH
+ tristate "Logitech devices"
+- depends on HID
++ depends on USB_HID
+ depends on LEDS_CLASS
+ default !EXPERT
+ help
+@@ -919,7 +919,7 @@ config HID_SAITEK
+
+ 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.
+
+diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
+index f3ecddc519ee8..08c9a9a60ae47 100644
+--- a/drivers/hid/hid-asus.c
++++ b/drivers/hid/hid-asus.c
+@@ -1028,8 +1028,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
+ drvdata->tp = &asus_i2c_tp;
+
+- if ((drvdata->quirks & QUIRK_T100_KEYBOARD) &&
+- hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
++ 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) {
+@@ -1057,8 +1056,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ drvdata->tp = &asus_t100chi_tp;
+ }
+
+- if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
+- hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
++ if ((drvdata->quirks & QUIRK_MEDION_E1239T) && hid_is_usb(hdev)) {
+ struct usb_host_interface *alt =
+ to_usb_interface(hdev->dev.parent)->altsetting;
+
+diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c
+index db6da21ade063..74ad8bf98bfd5 100644
+--- a/drivers/hid/hid-bigbenff.c
++++ b/drivers/hid/hid-bigbenff.c
+@@ -191,7 +191,7 @@ static void bigben_worker(struct work_struct *work)
+ struct bigben_device, worker);
+ struct hid_field *report_field = bigben->report->field[0];
+
+- if (bigben->removed)
++ if (bigben->removed || !report_field)
+ return;
+
+ if (bigben->work_led) {
+diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
+index ca556d39da2ae..f04d2aa23efe4 100644
+--- a/drivers/hid/hid-chicony.c
++++ b/drivers/hid/hid-chicony.c
+@@ -114,6 +114,9 @@ static int ch_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ {
+ int ret;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+ ret = hid_parse(hdev);
+ if (ret) {
+diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
+index 902a60e249ed2..8c895c820b672 100644
+--- a/drivers/hid/hid-corsair.c
++++ b/drivers/hid/hid-corsair.c
+@@ -553,7 +553,12 @@ static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id)
+ 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);
+diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c
+index 021049805bb71..3091355d48df6 100644
+--- a/drivers/hid/hid-elan.c
++++ b/drivers/hid/hid-elan.c
+@@ -50,7 +50,7 @@ struct elan_drvdata {
+
+ 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 !=
+diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c
+index 383dfda8c12fc..8e960d7b233b3 100644
+--- a/drivers/hid/hid-elo.c
++++ b/drivers/hid/hid-elo.c
+@@ -230,6 +230,9 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ int ret;
+ struct usb_device *udev;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
+index 4ef1c3b8094ea..183eeb3863b38 100644
+--- a/drivers/hid/hid-ft260.c
++++ b/drivers/hid/hid-ft260.c
+@@ -915,6 +915,9 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ struct ft260_get_chip_version_report version;
+ int ret;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
+index 8123b871a3ebf..0403beb3104b9 100644
+--- a/drivers/hid/hid-google-hammer.c
++++ b/drivers/hid/hid-google-hammer.c
+@@ -585,6 +585,8 @@ static void hammer_remove(struct hid_device *hdev)
+ 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,
+diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c
+index 0a38e8e9bc783..403506b9697e7 100644
+--- a/drivers/hid/hid-holtek-kbd.c
++++ b/drivers/hid/hid-holtek-kbd.c
+@@ -140,12 +140,17 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
+ 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) {
+diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
+index 195b735b001d0..b7172c48ef9f0 100644
+--- a/drivers/hid/hid-holtek-mouse.c
++++ b/drivers/hid/hid-holtek-mouse.c
+@@ -62,6 +62,14 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ return rdesc;
+ }
+
++static int holtek_mouse_probe(struct hid_device *hdev,
++ const struct hid_device_id *id)
++{
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++ 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 +91,7 @@ static struct hid_driver holtek_mouse_driver = {
+ .name = "holtek_mouse",
+ .id_table = holtek_mouse_devices,
+ .report_fixup = holtek_mouse_report_fixup,
++ .probe = holtek_mouse_probe,
+ };
+
+ module_hid_driver(holtek_mouse_driver);
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 29564b370341e..70e65eb1b868d 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -394,6 +394,7 @@
+ #define USB_DEVICE_ID_HP_X2 0x074d
+ #define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
+ #define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817
++#define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
+ #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
+ #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A
+
+@@ -496,6 +497,7 @@
+ #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_VENDOR_ID_GOTOP 0x08f2
+ #define USB_DEVICE_ID_SUPER_Q2 0x007f
+@@ -881,6 +883,7 @@
+ #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
+@@ -1276,6 +1279,9 @@
+ #define USB_DEVICE_ID_WEIDA_8752 0xC300
+ #define USB_DEVICE_ID_WEIDA_8755 0xC301
+
++#define USB_VENDOR_ID_WINBOND 0x0416
++#define USB_DEVICE_ID_TSTP_MTOUCH 0xc168
++
+ #define USB_VENDOR_ID_WISEGROUP 0x0925
+ #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
+ #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index 4b5ebeacd2836..55017db98d896 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -160,6 +160,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
+ if (usage) {
+ *old_keycode = usage->type == EV_KEY ?
+ usage->code : KEY_RESERVED;
++ usage->type = EV_KEY;
+ usage->code = ke->keycode;
+
+ clear_bit(*old_keycode, dev->keybit);
+@@ -324,6 +325,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
+ HID_BATTERY_QUIRK_IGNORE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
+ HID_BATTERY_QUIRK_IGNORE },
++ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
++ HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
+ HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
+@@ -650,10 +653,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ code += KEY_MACRO1;
+ else
+ code += BTN_TRIGGER_HAPPY - 0x1e;
+- } else {
+- goto ignore;
++ break;
+ }
+- break;
++ fallthrough;
+ default:
+ switch (field->physical) {
+ case HID_GD_MOUSE:
+diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
+index d40af911df635..fb3f7258009c2 100644
+--- a/drivers/hid/hid-lg.c
++++ b/drivers/hid/hid-lg.c
+@@ -749,12 +749,18 @@ static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
+
+ 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)) {
+diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
+index a0017b010c342..7106b921b53cf 100644
+--- a/drivers/hid/hid-logitech-dj.c
++++ b/drivers/hid/hid-logitech-dj.c
+@@ -1777,7 +1777,7 @@ static int logi_dj_probe(struct hid_device *hdev,
+ case recvr_type_bluetooth: no_dj_interfaces = 2; break;
+ case recvr_type_dinovo: 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) {
+diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
+index 686788ebf3e1e..d7687ce706144 100644
+--- a/drivers/hid/hid-magicmouse.c
++++ b/drivers/hid/hid-magicmouse.c
+@@ -256,8 +256,11 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
+ unsigned long now = jiffies;
+ int step_x = msc->touches[id].scroll_x - x;
+ int step_y = msc->touches[id].scroll_y - y;
+- int step_hr = ((64 - (int)scroll_speed) * msc->scroll_accel) /
+- SCROLL_HR_STEPS;
++ int step_hr =
++ max_t(int,
++ ((64 - (int)scroll_speed) * msc->scroll_accel) /
++ SCROLL_HR_STEPS,
++ 1);
+ int step_x_hr = msc->touches[id].scroll_x_hr - x;
+ int step_y_hr = msc->touches[id].scroll_y_hr - y;
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 3ea7cb1cda84c..e1afddb7b33d8 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -193,6 +193,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
+ /* reserved 0x0014 */
+ #define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015
+ #define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016
++#define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017
+
+ /* vendor specific classes */
+ #define MT_CLS_3M 0x0101
+@@ -294,6 +295,13 @@ static const struct mt_class mt_classes[] = {
+ MT_QUIRK_WIN8_PTP_BUTTONS |
+ MT_QUIRK_DISABLE_WAKEUP,
+ .export_all_inputs = true },
++ { .name = MT_CLS_WIN_8_NO_STICKY_FINGERS,
++ .quirks = MT_QUIRK_ALWAYS_VALID |
++ MT_QUIRK_IGNORE_DUPLICATES |
++ MT_QUIRK_HOVERING |
++ MT_QUIRK_CONTACT_CNT_ACCURATE |
++ MT_QUIRK_WIN8_PTP_BUTTONS,
++ .export_all_inputs = true },
+
+ /*
+ * vendor specific classes
+@@ -2120,6 +2128,11 @@ static const struct hid_device_id mt_devices[] = {
+ MT_USB_DEVICE(USB_VENDOR_ID_VTL,
+ USB_DEVICE_ID_VTL_MULTITOUCH_FF3F) },
+
++ /* Winbond Electronics Corp. */
++ { .driver_data = MT_CLS_WIN_8_NO_STICKY_FINGERS,
++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
++ USB_VENDOR_ID_WINBOND, USB_DEVICE_ID_TSTP_MTOUCH) },
++
+ /* Wistron panels */
+ { .driver_data = MT_CLS_NSMU,
+ MT_USB_DEVICE(USB_VENDOR_ID_WISTRON,
+diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
+index 2666af02d5c1a..e4e9471d0f1e9 100644
+--- a/drivers/hid/hid-prodikeys.c
++++ b/drivers/hid/hid-prodikeys.c
+@@ -798,12 +798,18 @@ static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,
+ 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");
+diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
+index 2e104682c22b9..65b7114761749 100644
+--- a/drivers/hid/hid-quirks.c
++++ b/drivers/hid/hid-quirks.c
+@@ -124,6 +124,7 @@ static const struct hid_device_id hid_quirks[] = {
+ { 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_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 },
+diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
+index 4556d2a50f754..d94ee0539421e 100644
+--- a/drivers/hid/hid-roccat-arvo.c
++++ b/drivers/hid/hid-roccat-arvo.c
+@@ -344,6 +344,9 @@ static int arvo_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
+index ce5f22519956a..e95d59cd8d075 100644
+--- a/drivers/hid/hid-roccat-isku.c
++++ b/drivers/hid/hid-roccat-isku.c
+@@ -324,6 +324,9 @@ static int isku_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
+index 1ca64481145ee..e8522eacf7973 100644
+--- a/drivers/hid/hid-roccat-kone.c
++++ b/drivers/hid/hid-roccat-kone.c
+@@ -749,6 +749,9 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
+index 0316edf8c5bb4..1896c69ea512f 100644
+--- a/drivers/hid/hid-roccat-koneplus.c
++++ b/drivers/hid/hid-roccat-koneplus.c
+@@ -431,6 +431,9 @@ static int koneplus_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
+index 5248b3c7cf785..cf8eeb33a1257 100644
+--- a/drivers/hid/hid-roccat-konepure.c
++++ b/drivers/hid/hid-roccat-konepure.c
+@@ -133,6 +133,9 @@ static int konepure_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
+index 9600128815705..6fb9b9563769d 100644
+--- a/drivers/hid/hid-roccat-kovaplus.c
++++ b/drivers/hid/hid-roccat-kovaplus.c
+@@ -501,6 +501,9 @@ static int kovaplus_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
+index 4a88a76d5c622..d5ddf0d68346b 100644
+--- a/drivers/hid/hid-roccat-lua.c
++++ b/drivers/hid/hid-roccat-lua.c
+@@ -160,6 +160,9 @@ static int lua_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
+index 989927defe8db..4fcc8e7d276f2 100644
+--- a/drivers/hid/hid-roccat-pyra.c
++++ b/drivers/hid/hid-roccat-pyra.c
+@@ -449,6 +449,9 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c
+index 3956a6c9c5217..5bf1971a2b14d 100644
+--- a/drivers/hid/hid-roccat-ryos.c
++++ b/drivers/hid/hid-roccat-ryos.c
+@@ -141,6 +141,9 @@ static int ryos_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
+index 818701f7a0281..a784bb4ee6512 100644
+--- a/drivers/hid/hid-roccat-savu.c
++++ b/drivers/hid/hid-roccat-savu.c
+@@ -113,6 +113,9 @@ static int savu_probe(struct hid_device *hdev,
+ {
+ int retval;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
+index 2e1c31156eca0..cf5992e970940 100644
+--- a/drivers/hid/hid-samsung.c
++++ b/drivers/hid/hid-samsung.c
+@@ -152,6 +152,9 @@ static int samsung_probe(struct hid_device *hdev,
+ 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");
+diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
+index d1b107d547f54..60ec2b29d54de 100644
+--- a/drivers/hid/hid-sony.c
++++ b/drivers/hid/hid-sony.c
+@@ -3000,7 +3000,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ sc->quirks = quirks;
+ hid_set_drvdata(hdev, sc);
+ sc->hdev = hdev;
+- usbdev = to_usb_device(sc->hdev->dev.parent->parent);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+@@ -3038,14 +3037,23 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ */
+ if (!(hdev->claimed & HID_CLAIMED_INPUT)) {
+ hid_err(hdev, "failed to claim input\n");
+- hid_hw_stop(hdev);
+- return -ENODEV;
++ ret = -ENODEV;
++ goto err;
+ }
+
+ if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
++ if (!hid_is_usb(hdev)) {
++ ret = -EINVAL;
++ goto err;
++ }
++
++ usbdev = to_usb_device(sc->hdev->dev.parent->parent);
++
+ sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
+- if (!sc->ghl_urb)
+- return -ENOMEM;
++ if (!sc->ghl_urb) {
++ ret = -ENOMEM;
++ goto err;
++ }
+
+ if (sc->quirks & GHL_GUITAR_PS3WIIU)
+ ret = ghl_init_urb(sc, usbdev, ghl_ps3wiiu_magic_data,
+@@ -3055,7 +3063,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ ARRAY_SIZE(ghl_ps4_magic_data));
+ if (ret) {
+ hid_err(hdev, "error preparing URB\n");
+- return ret;
++ goto err;
+ }
+
+ timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
+@@ -3064,6 +3072,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ }
+
+ return ret;
++
++err:
++ hid_hw_stop(hdev);
++ return ret;
+ }
+
+ static void sony_remove(struct hid_device *hdev)
+diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c
+index d44550aa88057..0c92b7f9b8b81 100644
+--- a/drivers/hid/hid-thrustmaster.c
++++ b/drivers/hid/hid-thrustmaster.c
+@@ -274,6 +274,9 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i
+ int ret = 0;
+ struct tm_wheel *tm_wheel = 0;
+
++ if (!hid_is_usb(hdev))
++ return -EINVAL;
++
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed with error %d\n", ret);
+diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c
+index d70cd3d7f583b..ac3fd870673d2 100644
+--- a/drivers/hid/hid-u2fzero.c
++++ b/drivers/hid/hid-u2fzero.c
+@@ -132,7 +132,7 @@ static int u2fzero_recv(struct u2fzero_device *dev,
+
+ 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 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data,
+ 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");
+@@ -200,12 +202,12 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data,
+ ret = u2fzero_recv(dev, &req, &resp);
+
+ /* ignore errors or packets without data */
+- if (ret < offsetof(struct u2f_hid_msg, init.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);
+
+@@ -288,7 +290,7 @@ static int u2fzero_probe(struct hid_device *hdev,
+ 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);
+diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
+index 6a9865dd703c0..d8ab0139e5cda 100644
+--- a/drivers/hid/hid-uclogic-core.c
++++ b/drivers/hid/hid-uclogic-core.c
+@@ -164,6 +164,9 @@ static int uclogic_probe(struct hid_device *hdev,
+ 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.
+diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
+index 3d67b748a3b95..adff1bd68d9f8 100644
+--- a/drivers/hid/hid-uclogic-params.c
++++ b/drivers/hid/hid-uclogic-params.c
+@@ -843,8 +843,7 @@ int uclogic_params_init(struct uclogic_params *params,
+ 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;
+ }
+diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+index 1c5039081db27..8e9d9450cb835 100644
+--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
++++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+@@ -266,7 +266,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
+
+ if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
+ && IPC_IS_ISH_ILUP(fwsts)) {
+- disable_irq_wake(pdev->irq);
++ if (device_may_wakeup(&pdev->dev))
++ disable_irq_wake(pdev->irq);
+
+ ish_set_host_ready(dev);
+
+@@ -337,7 +338,8 @@ static int __maybe_unused ish_suspend(struct device *device)
+ */
+ pci_save_state(pdev);
+
+- enable_irq_wake(pdev->irq);
++ if (device_may_wakeup(&pdev->dev))
++ enable_irq_wake(pdev->irq);
+ }
+ } else {
+ /*
+diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c
+index a3a70e4f3f6c9..d4aa8c81903ae 100644
+--- a/drivers/hid/surface-hid/surface_hid.c
++++ b/drivers/hid/surface-hid/surface_hid.c
+@@ -209,7 +209,7 @@ static int surface_hid_probe(struct ssam_device *sdev)
+
+ shid->notif.base.priority = 1;
+ shid->notif.base.fn = ssam_hid_event_fn;
+- shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG;
++ shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG(sdev->uid.target);
+ shid->notif.event.id.target_category = sdev->uid.category;
+ shid->notif.event.id.instance = sdev->uid.instance;
+ shid->notif.event.mask = SSAM_EVENT_MASK_STRICT;
+@@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev)
+ }
+
+ static const struct ssam_device_id surface_hid_match[] = {
+- { SSAM_SDEV(HID, 0x02, SSAM_ANY_IID, 0x00) },
++ { SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) },
+ { },
+ };
+ MODULE_DEVICE_TABLE(ssam, surface_hid_match);
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index 93f49b766376e..b1bbf297f66b0 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -726,7 +726,7 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
+ * 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
+@@ -2217,7 +2217,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
+ 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;
+@@ -2454,6 +2454,9 @@ static void wacom_wireless_work(struct work_struct *work)
+
+ wacom_destroy_battery(wacom);
+
++ if (!usbdev)
++ return;
++
+ /* Stylus interface */
+ hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
+ wacom1 = hid_get_drvdata(hdev1);
+@@ -2733,8 +2736,6 @@ static void wacom_mode_change_work(struct work_struct *work)
+ 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;
+@@ -2769,8 +2770,14 @@ static int wacom_probe(struct hid_device *hdev,
+ 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);
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 33a6908995b1b..2a4cc39962e76 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -2603,6 +2603,9 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
+ 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;
+@@ -2635,7 +2638,8 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
+ }
+
+ if (usage->usage_index + 1 == field->report_count) {
+- if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
++ if (equivalent_usage == wacom_wac->hid_data.last_slot_field &&
++ wacom_wac->hid_data.confidence)
+ wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
+ }
+ }
+@@ -2653,6 +2657,8 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
+
+ wacom_wac->is_invalid_bt_frame = false;
+
++ hid_data->confidence = true;
++
+ for (i = 0; i < report->maxfield; i++) {
+ struct hid_field *field = report->field[i];
+ int j;
+diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
+index 8b2d4e5b2303c..466b62cc16dc1 100644
+--- a/drivers/hid/wacom_wac.h
++++ b/drivers/hid/wacom_wac.h
+@@ -301,6 +301,7 @@ struct hid_data {
+ bool barrelswitch;
+ bool barrelswitch2;
+ bool serialhi;
++ bool confidence;
+ int x;
+ int y;
+ int pressure;
+diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
+index 7f11ea07d698f..ca873a3b98dbe 100644
+--- a/drivers/hv/hv_balloon.c
++++ b/drivers/hv/hv_balloon.c
+@@ -480,7 +480,7 @@ module_param(pressure_report_delay, uint, (S_IRUGO | S_IWUSR));
+ MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure");
+ static atomic_t trans_id = ATOMIC_INIT(0);
+
+-static int dm_ring_size = 20 * 1024;
++static int dm_ring_size = VMBUS_RING_SIZE(16 * 1024);
+
+ /*
+ * Driver specific state.
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 731d5117f9f10..14389fd7afb89 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -729,7 +729,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
+ corsairpsu_check_cmd_support(priv);
+
+ priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
+- &corsairpsu_chip_info, 0);
++ &corsairpsu_chip_info, NULL);
+
+ if (IS_ERR(priv->hwmon_dev)) {
+ ret = PTR_ERR(priv->hwmon_dev);
+diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
+index 774c1b0715d91..47fce97996de2 100644
+--- a/drivers/hwmon/dell-smm-hwmon.c
++++ b/drivers/hwmon/dell-smm-hwmon.c
+@@ -623,10 +623,9 @@ static void __init i8k_init_procfs(struct device *dev)
+ {
+ struct dell_smm_data *data = dev_get_drvdata(dev);
+
+- /* Register the proc entry */
+- proc_create_data("i8k", 0, NULL, &i8k_proc_ops, data);
+-
+- devm_add_action_or_reset(dev, i8k_exit_procfs, NULL);
++ /* Only register exit function if creation was successful */
++ if (proc_create_data("i8k", 0, NULL, &i8k_proc_ops, data))
++ devm_add_action_or_reset(dev, i8k_exit_procfs, NULL);
+ }
+
+ #else
+diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
+index 8d3b1dae31df1..3501a3ead4ba6 100644
+--- a/drivers/hwmon/hwmon.c
++++ b/drivers/hwmon/hwmon.c
+@@ -796,8 +796,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
+ 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;
++ }
+
+ INIT_LIST_HEAD(&hwdev->tzdata);
+
+diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
+index d209e0afc2caa..66d3e88b54172 100644
+--- a/drivers/hwmon/pmbus/lm25066.c
++++ b/drivers/hwmon/pmbus/lm25066.c
+@@ -51,26 +51,31 @@ struct __coeff {
+ #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 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
+ [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 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
+ [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 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
+ [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] = {
+diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
+index 17518b4cab1b0..f12b9a28a232d 100644
+--- a/drivers/hwmon/pwm-fan.c
++++ b/drivers/hwmon/pwm-fan.c
+@@ -336,8 +336,6 @@ static int pwm_fan_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+- ctx->pwm_value = MAX_PWM;
+-
+ pwm_init_state(ctx->pwm, &ctx->pwm_state);
+
+ /*
+diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
+index e2a3620cbf489..8988b2ed2ea6f 100644
+--- a/drivers/hwtracing/coresight/coresight-cti-core.c
++++ b/drivers/hwtracing/coresight/coresight-cti-core.c
+@@ -175,7 +175,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
+ coresight_disclaim_device_unlocked(csdev);
+ CS_LOCK(drvdata->base);
+ spin_unlock(&drvdata->spinlock);
+- pm_runtime_put(dev);
++ pm_runtime_put(dev->parent);
+ return 0;
+
+ /* not disabled this call */
+diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
+index 1768684968797..7dddb85b90591 100644
+--- a/drivers/hwtracing/coresight/coresight-trbe.c
++++ b/drivers/hwtracing/coresight/coresight-trbe.c
+@@ -366,7 +366,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
+
+ static unsigned long trbe_normal_offset(struct perf_output_handle *handle)
+ {
+- struct trbe_buf *buf = perf_get_aux(handle);
++ struct trbe_buf *buf = etm_perf_sink_config(handle);
+ u64 limit = __trbe_normal_offset(handle);
+ u64 head = PERF_IDX2OFF(handle->head, buf);
+
+@@ -869,6 +869,10 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
+ if (WARN_ON(trbe_csdev))
+ return;
+
++ /* If the TRBE was not probed on the CPU, we shouldn't be here */
++ if (WARN_ON(!cpudata->drvdata))
++ return;
++
+ dev = &cpudata->drvdata->pdev->dev;
+ desc.name = devm_kasprintf(dev, GFP_KERNEL, "trbe%d", cpu);
+ if (!desc.name)
+@@ -950,7 +954,9 @@ static int arm_trbe_probe_coresight(struct trbe_drvdata *drvdata)
+ return -ENOMEM;
+
+ for_each_cpu(cpu, &drvdata->supported_cpus) {
+- smp_call_function_single(cpu, arm_trbe_probe_cpu, drvdata, 1);
++ /* If we fail to probe the CPU, let us defer it to hotplug callbacks */
++ if (smp_call_function_single(cpu, arm_trbe_probe_cpu, drvdata, 1))
++ continue;
+ if (cpumask_test_cpu(cpu, &drvdata->supported_cpus))
+ arm_trbe_register_coresight_cpu(drvdata, cpu);
+ if (cpumask_test_cpu(cpu, &drvdata->supported_cpus))
+diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c
+index 72df563477b1c..f8639a4457d23 100644
+--- a/drivers/i2c/busses/i2c-cbus-gpio.c
++++ b/drivers/i2c/busses/i2c-cbus-gpio.c
+@@ -195,8 +195,9 @@ static u32 cbus_i2c_func(struct i2c_adapter *adapter)
+ }
+
+ 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)
+diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
+index 89ae78ef1a1cc..1f929e6c30bea 100644
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -1493,7 +1493,6 @@ static struct platform_device *
+ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
+ struct resource *tco_res)
+ {
+- static DEFINE_MUTEX(p2sb_mutex);
+ struct resource *res;
+ unsigned int devfn;
+ u64 base64_addr;
+@@ -1506,7 +1505,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
+ * enumerated by the PCI subsystem, so we need to unhide/hide it
+ * to lookup the P2SB BAR.
+ */
+- mutex_lock(&p2sb_mutex);
++ pci_lock_rescan_remove();
+
+ devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1);
+
+@@ -1524,7 +1523,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
+ /* Hide the P2SB device, if it was hidden before */
+ if (hidden)
+ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
+- mutex_unlock(&p2sb_mutex);
++ pci_unlock_rescan_remove();
+
+ res = &tco_res[1];
+ if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
+diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
+index a6ea1eb1394e1..53b8da6dbb23f 100644
+--- a/drivers/i2c/busses/i2c-mpc.c
++++ b/drivers/i2c/busses/i2c-mpc.c
+@@ -636,7 +636,7 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+ status = readb(i2c->base + MPC_I2C_SR);
+ if (status & CSR_MIF) {
+ /* Wait up to 100us for transfer to properly complete */
+- readb_poll_timeout(i2c->base + MPC_I2C_SR, status, !(status & CSR_MCF), 0, 100);
++ readb_poll_timeout_atomic(i2c->base + MPC_I2C_SR, status, status & CSR_MCF, 0, 100);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ mpc_i2c_do_intr(i2c, status);
+ return IRQ_HANDLED;
+diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
+index 7d4b3eb7077ad..72acda59eb399 100644
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -195,7 +195,7 @@ static const u16 mt_i2c_regs_v2[] = {
+ [OFFSET_CLOCK_DIV] = 0x48,
+ [OFFSET_SOFTRESET] = 0x50,
+ [OFFSET_SCL_MIS_COMP_POINT] = 0x90,
+- [OFFSET_DEBUGSTAT] = 0xe0,
++ [OFFSET_DEBUGSTAT] = 0xe4,
+ [OFFSET_DEBUGCTRL] = 0xe8,
+ [OFFSET_FIFO_STAT] = 0xf4,
+ [OFFSET_FIFO_THRESH] = 0xf8,
+diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
+index 819ab4ee517e1..02ddb237f69af 100644
+--- a/drivers/i2c/busses/i2c-rk3x.c
++++ b/drivers/i2c/busses/i2c-rk3x.c
+@@ -423,8 +423,8 @@ static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
+ 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)
+diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
+index b9b19a2a2ffa0..50d5ae81d2271 100644
+--- a/drivers/i2c/busses/i2c-stm32f7.c
++++ b/drivers/i2c/busses/i2c-stm32f7.c
+@@ -1493,6 +1493,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
+ {
+ 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;
+@@ -1518,6 +1519,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
+ dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n",
+ __func__, f7_msg->addr);
+ 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;
+ }
+
+@@ -1533,7 +1538,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
+ /* 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;
+@@ -1546,7 +1551,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
+ 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);
+@@ -1696,12 +1701,23 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
+ 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;
+ }
+
+@@ -1744,13 +1760,22 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ 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;
+ }
+diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
+index f10a603b13fb0..5cb21d7da05b6 100644
+--- a/drivers/i2c/busses/i2c-virtio.c
++++ b/drivers/i2c/busses/i2c-virtio.c
+@@ -22,24 +22,24 @@
+ /**
+ * struct virtio_i2c - virtio I2C data
+ * @vdev: virtio device for this controller
+- * @completion: completion of virtio I2C message
+ * @adap: I2C adapter for this controller
+ * @vq: the virtio virtqueue for communication
+ */
+ struct virtio_i2c {
+ struct virtio_device *vdev;
+- struct completion completion;
+ struct i2c_adapter adap;
+ struct virtqueue *vq;
+ };
+
+ /**
+ * struct virtio_i2c_req - the virtio I2C request structure
++ * @completion: completion of virtio I2C message
+ * @out_hdr: the OUT header of the virtio I2C message
+ * @buf: the buffer into which data is read, or from which it's written
+ * @in_hdr: the IN header of the virtio I2C message
+ */
+ struct virtio_i2c_req {
++ struct completion completion;
+ struct virtio_i2c_out_hdr out_hdr ____cacheline_aligned;
+ uint8_t *buf ____cacheline_aligned;
+ struct virtio_i2c_in_hdr in_hdr ____cacheline_aligned;
+@@ -47,9 +47,11 @@ struct virtio_i2c_req {
+
+ static void virtio_i2c_msg_done(struct virtqueue *vq)
+ {
+- struct virtio_i2c *vi = vq->vdev->priv;
++ struct virtio_i2c_req *req;
++ unsigned int len;
+
+- complete(&vi->completion);
++ while ((req = virtqueue_get_buf(vq, &len)))
++ complete(&req->completion);
+ }
+
+ static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
+@@ -62,6 +64,8 @@ static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
+ for (i = 0; i < num; i++) {
+ int outcnt = 0, incnt = 0;
+
++ init_completion(&reqs[i].completion);
++
+ /*
+ * We don't support 0 length messages and so filter out
+ * 0 length transfers by using i2c_adapter_quirks.
+@@ -106,24 +110,17 @@ static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
+
+ static int virtio_i2c_complete_reqs(struct virtqueue *vq,
+ struct virtio_i2c_req *reqs,
+- struct i2c_msg *msgs, int num,
+- bool timedout)
++ struct i2c_msg *msgs, int num)
+ {
+- struct virtio_i2c_req *req;
+- bool failed = timedout;
+- unsigned int len;
++ bool failed = false;
+ int i, j = 0;
+
+ for (i = 0; i < num; i++) {
+- /* Detach the ith request from the vq */
+- req = virtqueue_get_buf(vq, &len);
++ struct virtio_i2c_req *req = &reqs[i];
+
+- /*
+- * Condition req == &reqs[i] should always meet since we have
+- * total num requests in the vq. reqs[i] can never be NULL here.
+- */
+- if (!failed && (WARN_ON(req != &reqs[i]) ||
+- req->in_hdr.status != VIRTIO_I2C_MSG_OK))
++ wait_for_completion(&req->completion);
++
++ if (!failed && req->in_hdr.status != VIRTIO_I2C_MSG_OK)
+ failed = true;
+
+ i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], !failed);
+@@ -132,7 +129,7 @@ static int virtio_i2c_complete_reqs(struct virtqueue *vq,
+ j++;
+ }
+
+- return timedout ? -ETIMEDOUT : j;
++ return j;
+ }
+
+ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+@@ -141,7 +138,6 @@ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ struct virtio_i2c *vi = i2c_get_adapdata(adap);
+ struct virtqueue *vq = vi->vq;
+ struct virtio_i2c_req *reqs;
+- unsigned long time_left;
+ int count;
+
+ reqs = kcalloc(num, sizeof(*reqs), GFP_KERNEL);
+@@ -160,15 +156,9 @@ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ * remote here to clear the virtqueue, so we can try another set of
+ * messages later on.
+ */
+-
+- reinit_completion(&vi->completion);
+ virtqueue_kick(vq);
+
+- time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
+- if (!time_left)
+- dev_err(&adap->dev, "virtio i2c backend timeout.\n");
+-
+- count = virtio_i2c_complete_reqs(vq, reqs, msgs, count, !time_left);
++ count = virtio_i2c_complete_reqs(vq, reqs, msgs, count);
+
+ err_free:
+ kfree(reqs);
+@@ -215,8 +205,6 @@ static int virtio_i2c_probe(struct virtio_device *vdev)
+ vdev->priv = vi;
+ vi->vdev = vdev;
+
+- init_completion(&vi->completion);
+-
+ ret = virtio_i2c_setup_vqs(vi);
+ if (ret)
+ return ret;
+diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
+index 126d1393e548b..9ce20652d4942 100644
+--- a/drivers/i2c/busses/i2c-xlr.c
++++ b/drivers/i2c/busses/i2c-xlr.c
+@@ -431,11 +431,15 @@ static int xlr_i2c_probe(struct platform_device *pdev)
+ 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)
+diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
+index a51fdd3c9b5b5..24c9387c29687 100644
+--- a/drivers/iio/accel/kxcjk-1013.c
++++ b/drivers/iio/accel/kxcjk-1013.c
+@@ -1595,8 +1595,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
+ return 0;
+
+ 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);
+@@ -1618,8 +1617,8 @@ static int kxcjk1013_remove(struct i2c_client *client)
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&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);
+ }
+diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
+index bf7ed9e7d00f4..e56ecc075014e 100644
+--- a/drivers/iio/accel/kxsd9.c
++++ b/drivers/iio/accel/kxsd9.c
+@@ -224,14 +224,14 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
+ 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,
+ iio_get_time_ns(indio_dev));
++out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
+index 715b8138fb715..09c7f10fefb6e 100644
+--- a/drivers/iio/accel/mma8452.c
++++ b/drivers/iio/accel/mma8452.c
+@@ -1470,7 +1470,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
+ if (ret)
+ return ret;
+
+- indio_dev->trig = trig;
++ indio_dev->trig = iio_trigger_get(trig);
+
+ return 0;
+ }
+diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
+index f711756e41e3d..cba57459e90ab 100644
+--- a/drivers/iio/accel/st_accel_i2c.c
++++ b/drivers/iio/accel/st_accel_i2c.c
+@@ -193,10 +193,10 @@ static int st_accel_i2c_remove(struct i2c_client *client)
+ {
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_accel_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
+index bb45d9ff95b85..5167fae1ee8ec 100644
+--- a/drivers/iio/accel/st_accel_spi.c
++++ b/drivers/iio/accel/st_accel_spi.c
+@@ -143,10 +143,10 @@ static int st_accel_spi_remove(struct spi_device *spi)
+ {
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_accel_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
+index 2c5c8a3672b2d..aa42ba759fa1a 100644
+--- a/drivers/iio/adc/ad7768-1.c
++++ b/drivers/iio/adc/ad7768-1.c
+@@ -480,8 +480,8 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p)
+ 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;
+diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
+index ea5ca163d8796..c4de706012e51 100644
+--- a/drivers/iio/adc/at91-sama5d2_adc.c
++++ b/drivers/iio/adc/at91-sama5d2_adc.c
+@@ -1377,7 +1377,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
+ *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;
+ }
+
+diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
+index 3e0c0233b4315..df99f1365c398 100644
+--- a/drivers/iio/adc/axp20x_adc.c
++++ b/drivers/iio/adc/axp20x_adc.c
+@@ -251,19 +251,8 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
+ 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 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
+ 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;
+diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
+index 16407664182ce..97d162a3cba4e 100644
+--- a/drivers/iio/adc/dln2-adc.c
++++ b/drivers/iio/adc/dln2-adc.c
+@@ -248,7 +248,6 @@ static int dln2_adc_set_chan_period(struct dln2_adc *dln2,
+ 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 @@ static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
+ .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 @@ disable_port:
+ 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 @@ static int dln2_adc_read_raw(struct iio_dev *indio_dev,
+
+ 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;
+
+@@ -656,7 +655,11 @@ static int dln2_adc_probe(struct platform_device *pdev)
+ 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,
+diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
+index 5088de835bb15..e3e75413b49e7 100644
+--- a/drivers/iio/adc/stm32-adc.c
++++ b/drivers/iio/adc/stm32-adc.c
+@@ -975,6 +975,7 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
+ {
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
++ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
+ stm32h7_adc_disable(indio_dev);
+ stm32h7_adc_enter_pwr_down(adc);
+ }
+diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
+index 170950d5dd499..d84ae6b008c1b 100644
+--- a/drivers/iio/adc/ti-tsc2046.c
++++ b/drivers/iio/adc/ti-tsc2046.c
+@@ -398,7 +398,7 @@ static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev,
+ priv->xfer.len = size;
+ priv->time_per_scan_us = size * 8 * priv->time_per_bit_ns / NSEC_PER_USEC;
+
+- if (priv->scan_interval_us > priv->time_per_scan_us)
++ if (priv->scan_interval_us < priv->time_per_scan_us)
+ dev_warn(&priv->spi->dev, "The scan interval (%d) is less then calculated scan time (%d)\n",
+ priv->scan_interval_us, priv->time_per_scan_us);
+
+diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
+index 488ec69967d67..e50718422411d 100644
+--- a/drivers/iio/dac/ad5446.c
++++ b/drivers/iio/dac/ad5446.c
+@@ -531,8 +531,15 @@ static int ad5622_write(struct ad5446_state *st, unsigned val)
+ {
+ struct i2c_client *client = to_i2c_client(st->dev);
+ __be16 data = cpu_to_be16(val);
++ int ret;
++
++ ret = i2c_master_send(client, (char *)&data, sizeof(data));
++ if (ret < 0)
++ return ret;
++ if (ret != sizeof(data))
++ return -EIO;
+
+- return i2c_master_send(client, (char *)&data, sizeof(data));
++ return 0;
+ }
+
+ /*
+diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c
+index 3104ec32dfaca..dafda84fdea35 100644
+--- a/drivers/iio/dac/ad5766.c
++++ b/drivers/iio/dac/ad5766.c
+@@ -503,13 +503,13 @@ static int ad5766_get_output_range(struct ad5766_state *st)
+ int i, ret, min, max, tmp[2];
+
+ ret = device_property_read_u32_array(&st->spi->dev,
+- "output-range-voltage",
++ "output-range-microvolts",
+ tmp, 2);
+ if (ret)
+ return ret;
+
+- min = tmp[0] / 1000;
+- max = tmp[1] / 1000;
++ min = tmp[0] / 1000000;
++ max = tmp[1] / 1000000;
+ for (i = 0; i < ARRAY_SIZE(ad5766_span_tbl); i++) {
+ if (ad5766_span_tbl[i].min != min ||
+ ad5766_span_tbl[i].max != max)
+diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
+index 8107f7bbbe3c5..7e2fd32e993a6 100644
+--- a/drivers/iio/dac/ad5770r.c
++++ b/drivers/iio/dac/ad5770r.c
+@@ -522,7 +522,7 @@ static int ad5770r_channel_config(struct ad5770r_state *st)
+ return -EINVAL;
+
+ device_for_each_child_node(&st->spi->dev, child) {
+- ret = fwnode_property_read_u32(child, "num", &num);
++ ret = fwnode_property_read_u32(child, "reg", &num);
+ if (ret)
+ goto err_child_out;
+ if (num >= AD5770R_MAX_CHANNELS) {
+diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
+index 3e0734ddafe36..600e9725da788 100644
+--- a/drivers/iio/gyro/adxrs290.c
++++ b/drivers/iio/gyro/adxrs290.c
+@@ -7,6 +7,7 @@
+ */
+
+ #include <linux/bitfield.h>
++#include <linux/bitops.h>
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/kernel.h>
+@@ -124,7 +125,7 @@ static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *
+ goto err_unlock;
+ }
+
+- *val = temp;
++ *val = sign_extend32(temp, 15);
+
+ err_unlock:
+ mutex_unlock(&st->lock);
+@@ -146,7 +147,7 @@ static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val)
+ }
+
+ /* extract lower 12 bits temperature reading */
+- *val = temp & 0x0FFF;
++ *val = sign_extend32(temp, 11);
+
+ err_unlock:
+ mutex_unlock(&st->lock);
+diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
+index 04dd6a7969ea7..4cfa0d4395605 100644
+--- a/drivers/iio/gyro/itg3200_buffer.c
++++ b/drivers/iio/gyro/itg3200_buffer.c
+@@ -61,9 +61,9 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p)
+
+ 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;
+ }
+
+diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
+index 3ef86e16ee656..a8164fe48b857 100644
+--- a/drivers/iio/gyro/st_gyro_i2c.c
++++ b/drivers/iio/gyro/st_gyro_i2c.c
+@@ -106,10 +106,10 @@ static int st_gyro_i2c_remove(struct i2c_client *client)
+ {
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_gyro_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
+index 41d835493347c..9d8916871b4bf 100644
+--- a/drivers/iio/gyro/st_gyro_spi.c
++++ b/drivers/iio/gyro/st_gyro_spi.c
+@@ -110,10 +110,10 @@ static int st_gyro_spi_remove(struct spi_device *spi)
+ {
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_gyro_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
+index b9a06ca29beec..d4e692b187cda 100644
+--- a/drivers/iio/imu/adis.c
++++ b/drivers/iio/imu/adis.c
+@@ -430,6 +430,8 @@ int __adis_initial_startup(struct adis *adis)
+ if (ret)
+ return ret;
+
++ adis_enable_irq(adis, false);
++
+ if (!adis->data->prod_id_reg)
+ return 0;
+
+@@ -526,7 +528,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
+ adis->current_page = 0;
+ }
+
+- return adis_enable_irq(adis, false);
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(adis_init);
+
+diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+index db45f1fc0b817..8dbf744c5651f 100644
+--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+@@ -1279,6 +1279,8 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
+ 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:
+@@ -1304,8 +1306,8 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
+ }
+ break;
+ }
+- default:
+- break;
++ default: /* should never occur */
++ return -EINVAL;
+ }
+
+ if (req_odr > 0) {
+diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
+index a95cc2da56be6..2f98ba70e3d78 100644
+--- a/drivers/iio/industrialio-buffer.c
++++ b/drivers/iio/industrialio-buffer.c
+@@ -1312,6 +1312,11 @@ static struct attribute *iio_buffer_wrap_attr(struct iio_buffer *buffer,
+ iio_attr->buffer = buffer;
+ memcpy(&iio_attr->dev_attr, dattr, sizeof(iio_attr->dev_attr));
+ iio_attr->dev_attr.attr.name = kstrdup_const(attr->name, GFP_KERNEL);
++ if (!iio_attr->dev_attr.attr.name) {
++ kfree(iio_attr);
++ return NULL;
++ }
++
+ sysfs_attr_init(&iio_attr->dev_attr.attr);
+
+ list_add(&iio_attr->l, &buffer->buffer_attr_list);
+@@ -1362,10 +1367,10 @@ static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev,
+
+ return 0;
+
+-error_free_buffer_attrs:
+- kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+ error_free_scan_el_attrs:
+ kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
++error_free_buffer_attrs:
++ kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+
+ return ret;
+ }
+@@ -1531,6 +1536,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
+ sizeof(struct attribute *) * buffer_attrcount);
+
+ buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
++ buffer->buffer_group.attrs = attr;
+
+ for (i = 0; i < buffer_attrcount; i++) {
+ struct attribute *wrapped;
+@@ -1538,7 +1544,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
+ wrapped = iio_buffer_wrap_attr(buffer, attr[i]);
+ if (!wrapped) {
+ ret = -ENOMEM;
+- goto error_free_scan_mask;
++ goto error_free_buffer_attrs;
+ }
+ attr[i] = wrapped;
+ }
+@@ -1553,8 +1559,6 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
+ goto error_free_buffer_attrs;
+ }
+
+- buffer->buffer_group.attrs = attr;
+-
+ ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group);
+ if (ret)
+ goto error_free_buffer_attr_group_name;
+@@ -1583,8 +1587,12 @@ error_cleanup_dynamic:
+ return ret;
+ }
+
+-static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
++static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer,
++ struct iio_dev *indio_dev,
++ int index)
+ {
++ if (index == 0)
++ iio_buffer_unregister_legacy_sysfs_groups(indio_dev);
+ bitmap_free(buffer->scan_mask);
+ kfree(buffer->buffer_group.name);
+ kfree(buffer->buffer_group.attrs);
+@@ -1616,7 +1624,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+ buffer = iio_dev_opaque->attached_buffers[i];
+ ret = __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, i);
+ if (ret) {
+- unwind_idx = i;
++ unwind_idx = i - 1;
+ goto error_unwind_sysfs_and_mask;
+ }
+ }
+@@ -1638,7 +1646,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+ error_unwind_sysfs_and_mask:
+ for (; unwind_idx >= 0; unwind_idx--) {
+ buffer = iio_dev_opaque->attached_buffers[unwind_idx];
+- __iio_buffer_free_sysfs_and_mask(buffer);
++ __iio_buffer_free_sysfs_and_mask(buffer, indio_dev, unwind_idx);
+ }
+ return ret;
+ }
+@@ -1655,11 +1663,9 @@ void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev)
+ iio_device_ioctl_handler_unregister(iio_dev_opaque->buffer_ioctl_handler);
+ kfree(iio_dev_opaque->buffer_ioctl_handler);
+
+- iio_buffer_unregister_legacy_sysfs_groups(indio_dev);
+-
+ for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) {
+ buffer = iio_dev_opaque->attached_buffers[i];
+- __iio_buffer_free_sysfs_and_mask(buffer);
++ __iio_buffer_free_sysfs_and_mask(buffer, indio_dev, i);
+ }
+ }
+
+diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
+index 2dbb37e09b8cf..3e1e86d987cc2 100644
+--- a/drivers/iio/industrialio-core.c
++++ b/drivers/iio/industrialio-core.c
+@@ -1600,6 +1600,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
+ kfree(iio_dev_opaque->chan_attr_group.attrs);
+ iio_dev_opaque->chan_attr_group.attrs = NULL;
+ kfree(iio_dev_opaque->groups);
++ iio_dev_opaque->groups = NULL;
+ }
+
+ static void iio_dev_release(struct device *device)
+@@ -1664,7 +1665,13 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
+ kfree(iio_dev_opaque);
+ return NULL;
+ }
+- dev_set_name(&indio_dev->dev, "iio:device%d", iio_dev_opaque->id);
++
++ if (dev_set_name(&indio_dev->dev, "iio:device%d", iio_dev_opaque->id)) {
++ ida_simple_remove(&iio_ida, iio_dev_opaque->id);
++ kfree(iio_dev_opaque);
++ return NULL;
++ }
++
+ INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
+ INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
+
+diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
+index b23caa2f2aa1f..93990ff1dfe39 100644
+--- a/drivers/iio/industrialio-trigger.c
++++ b/drivers/iio/industrialio-trigger.c
+@@ -556,7 +556,6 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
+ irq_modify_status(trig->subirq_base + i,
+ IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
+ }
+- get_device(&trig->dev);
+
+ return trig;
+
+diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
+index 1830221da48d2..f0bd0ad34f222 100644
+--- a/drivers/iio/light/ltr501.c
++++ b/drivers/iio/light/ltr501.c
+@@ -1273,7 +1273,7 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
+ ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
+ als_buf, sizeof(als_buf));
+ if (ret < 0)
+- return ret;
++ goto done;
+ if (test_bit(0, indio_dev->active_scan_mask))
+ scan.channels[j++] = le16_to_cpu(als_buf[1]);
+ if (test_bit(1, indio_dev->active_scan_mask))
+diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
+index 07e91846307c7..fc63856ed54de 100644
+--- a/drivers/iio/light/stk3310.c
++++ b/drivers/iio/light/stk3310.c
+@@ -546,9 +546,8 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
+ 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,
+@@ -560,6 +559,7 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
+ 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;
+diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
+index 2dfe4ee99591b..fa78f0a3b53ea 100644
+--- a/drivers/iio/magnetometer/st_magn_i2c.c
++++ b/drivers/iio/magnetometer/st_magn_i2c.c
+@@ -102,10 +102,10 @@ static int st_magn_i2c_remove(struct i2c_client *client)
+ {
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_magn_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
+index fba9787963952..ff43cbf61b056 100644
+--- a/drivers/iio/magnetometer/st_magn_spi.c
++++ b/drivers/iio/magnetometer/st_magn_spi.c
+@@ -96,10 +96,10 @@ static int st_magn_spi_remove(struct spi_device *spi)
+ {
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_magn_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
+index 52fa98f24478d..6215de677017e 100644
+--- a/drivers/iio/pressure/st_pressure_i2c.c
++++ b/drivers/iio/pressure/st_pressure_i2c.c
+@@ -119,10 +119,10 @@ static int st_press_i2c_remove(struct i2c_client *client)
+ {
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_press_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
+index ee393df54cee8..e220cf0b125f1 100644
+--- a/drivers/iio/pressure/st_pressure_spi.c
++++ b/drivers/iio/pressure/st_pressure_spi.c
+@@ -102,10 +102,10 @@ static int st_press_spi_remove(struct spi_device *spi)
+ {
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+- st_sensors_power_disable(indio_dev);
+-
+ st_press_common_remove(indio_dev);
+
++ st_sensors_power_disable(indio_dev);
++
+ return 0;
+ }
+
+@@ -117,6 +117,10 @@ static const struct spi_device_id st_press_id_table[] = {
+ { LPS33HW_PRESS_DEV_NAME },
+ { LPS35HW_PRESS_DEV_NAME },
+ { LPS22HH_PRESS_DEV_NAME },
++ { "lps001wp-press" },
++ { "lps25h-press", },
++ { "lps331ap-press" },
++ { "lps22hb-press" },
+ {},
+ };
+ MODULE_DEVICE_TABLE(spi, st_press_id_table);
+diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
+index 33083877cd19d..4353b749ecef2 100644
+--- a/drivers/iio/trigger/stm32-timer-trigger.c
++++ b/drivers/iio/trigger/stm32-timer-trigger.c
+@@ -912,6 +912,6 @@ static struct platform_driver stm32_timer_trigger_driver = {
+ };
+ 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");
+diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
+index 6146c3c1cbe5c..8d709986b88c7 100644
+--- a/drivers/infiniband/core/sysfs.c
++++ b/drivers/infiniband/core/sysfs.c
+@@ -757,7 +757,7 @@ static void ib_port_release(struct kobject *kobj)
+ if (port->hw_stats_data)
+ kfree(port->hw_stats_data->stats);
+ kfree(port->hw_stats_data);
+- kfree(port);
++ kvfree(port);
+ }
+
+ static void ib_port_gid_attr_release(struct kobject *kobj)
+@@ -1189,7 +1189,7 @@ static struct ib_port *setup_port(struct ib_core_device *coredev, int port_num,
+ struct ib_port *p;
+ int ret;
+
+- p = kzalloc(struct_size(p, attrs_list,
++ p = kvzalloc(struct_size(p, attrs_list,
+ attr->gid_tbl_len + attr->pkey_tbl_len),
+ GFP_KERNEL);
+ if (!p)
+diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
+index 740e6b2efe0e7..d1345d76d9b12 100644
+--- a/drivers/infiniband/core/uverbs_cmd.c
++++ b/drivers/infiniband/core/uverbs_cmd.c
+@@ -837,11 +837,8 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs)
+ new_mr->device = new_pd->device;
+ new_mr->pd = new_pd;
+ new_mr->type = IB_MR_TYPE_USER;
+- new_mr->dm = NULL;
+- new_mr->sig_attrs = NULL;
+ new_mr->uobject = uobj;
+ atomic_inc(&new_pd->usecnt);
+- new_mr->iova = cmd.hca_va;
+ new_uobj->object = new_mr;
+
+ rdma_restrack_new(&new_mr->res, RDMA_RESTRACK_MR);
+diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
+index 89a2b21976d63..20a46d8731455 100644
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -1232,6 +1232,9 @@ static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
+ INIT_LIST_HEAD(&qp->rdma_mrs);
+ INIT_LIST_HEAD(&qp->sig_mrs);
+
++ qp->send_cq = attr->send_cq;
++ qp->recv_cq = attr->recv_cq;
++
+ rdma_restrack_new(&qp->res, RDMA_RESTRACK_QP);
+ WARN_ONCE(!udata && !caller, "Missing kernel QP owner");
+ rdma_restrack_set_name(&qp->res, udata ? NULL : caller);
+diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+index 408dfbcc47b5e..b7ec3a3926785 100644
+--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+@@ -3354,8 +3354,11 @@ static void bnxt_re_process_res_ud_wc(struct bnxt_re_qp *qp,
+ 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);
+
+@@ -3367,9 +3370,12 @@ static void bnxt_re_process_res_ud_wc(struct bnxt_re_qp *qp,
+ 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;
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+index d4d4959c2434c..bd153aa7e9ab3 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+@@ -707,12 +707,13 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res,
+ 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);
+diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
+index 37273dc0c03ca..b0d587254fe66 100644
+--- a/drivers/infiniband/hw/hfi1/chip.c
++++ b/drivers/infiniband/hw/hfi1/chip.c
+@@ -8414,6 +8414,8 @@ static void receive_interrupt_common(struct hfi1_ctxtdata *rcd)
+ */
+ static void __hfi1_rcd_eoi_intr(struct hfi1_ctxtdata *rcd)
+ {
++ if (!rcd->rcvhdrq)
++ return;
+ clear_recv_intr(rcd);
+ if (check_packet_present(rcd))
+ force_recv_intr(rcd);
+diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c
+index de411884386bf..385e6cff0d279 100644
+--- a/drivers/infiniband/hw/hfi1/driver.c
++++ b/drivers/infiniband/hw/hfi1/driver.c
+@@ -1011,6 +1011,8 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
+ struct hfi1_packet packet;
+ int skip_pkt = 0;
+
++ if (!rcd->rcvhdrq)
++ return RCV_PKT_OK;
+ /* Control context will always use the slow path interrupt handler */
+ needset = (rcd->ctxt == HFI1_CTRL_CTXT) ? 0 : 1;
+
+diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
+index e3679d076eaaf..ec2a45c5cf575 100644
+--- a/drivers/infiniband/hw/hfi1/init.c
++++ b/drivers/infiniband/hw/hfi1/init.c
+@@ -112,7 +112,6 @@ static int hfi1_create_kctxt(struct hfi1_devdata *dd,
+ rcd->fast_handler = get_dma_rtail_setting(rcd) ?
+ handle_receive_interrupt_dma_rtail :
+ handle_receive_interrupt_nodma_rtail;
+- rcd->slow_handler = handle_receive_interrupt;
+
+ hfi1_set_seq_cnt(rcd, 1);
+
+@@ -333,6 +332,8 @@ int hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, int numa,
+ rcd->numa_id = numa;
+ rcd->rcv_array_groups = dd->rcv_entries.ngroups;
+ rcd->rhf_rcv_function_map = normal_rhf_rcv_functions;
++ rcd->slow_handler = handle_receive_interrupt;
++ rcd->do_interrupt = rcd->slow_handler;
+ rcd->msix_intr = CCE_NUM_MSIX_VECTORS;
+
+ mutex_init(&rcd->exp_mutex);
+@@ -873,18 +874,6 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
+ if (ret)
+ goto done;
+
+- /* allocate dummy tail memory for all receive contexts */
+- dd->rcvhdrtail_dummy_kvaddr = dma_alloc_coherent(&dd->pcidev->dev,
+- sizeof(u64),
+- &dd->rcvhdrtail_dummy_dma,
+- GFP_KERNEL);
+-
+- if (!dd->rcvhdrtail_dummy_kvaddr) {
+- dd_dev_err(dd, "cannot allocate dummy tail memory\n");
+- ret = -ENOMEM;
+- goto done;
+- }
+-
+ /* dd->rcd can be NULL if early initialization failed */
+ for (i = 0; dd->rcd && i < dd->first_dyn_alloc_ctxt; ++i) {
+ /*
+@@ -897,8 +886,6 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
+ if (!rcd)
+ continue;
+
+- rcd->do_interrupt = &handle_receive_interrupt;
+-
+ lastfail = hfi1_create_rcvhdrq(dd, rcd);
+ if (!lastfail)
+ lastfail = hfi1_setup_eagerbufs(rcd);
+@@ -1119,7 +1106,7 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
+ 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,
+@@ -1200,6 +1187,11 @@ void hfi1_free_devdata(struct hfi1_devdata *dd)
+ dd->tx_opstats = NULL;
+ kfree(dd->comp_vect);
+ dd->comp_vect = NULL;
++ if (dd->rcvhdrtail_dummy_kvaddr)
++ dma_free_coherent(&dd->pcidev->dev, sizeof(u64),
++ (void *)dd->rcvhdrtail_dummy_kvaddr,
++ dd->rcvhdrtail_dummy_dma);
++ dd->rcvhdrtail_dummy_kvaddr = NULL;
+ sdma_clean(dd, dd->num_sdma);
+ rvt_dealloc_device(&dd->verbs_dev.rdi);
+ }
+@@ -1297,6 +1289,15 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
+ goto bail;
+ }
+
++ /* allocate dummy tail memory for all receive contexts */
++ dd->rcvhdrtail_dummy_kvaddr =
++ dma_alloc_coherent(&dd->pcidev->dev, sizeof(u64),
++ &dd->rcvhdrtail_dummy_dma, GFP_KERNEL);
++ if (!dd->rcvhdrtail_dummy_kvaddr) {
++ ret = -ENOMEM;
++ goto bail;
++ }
++
+ atomic_set(&dd->ipoib_rsm_usr_num, 0);
+ return dd;
+
+@@ -1504,13 +1505,6 @@ static void cleanup_device_data(struct hfi1_devdata *dd)
+
+ free_credit_return(dd);
+
+- if (dd->rcvhdrtail_dummy_kvaddr) {
+- dma_free_coherent(&dd->pcidev->dev, sizeof(u64),
+- (void *)dd->rcvhdrtail_dummy_kvaddr,
+- dd->rcvhdrtail_dummy_dma);
+- dd->rcvhdrtail_dummy_kvaddr = NULL;
+- }
+-
+ /*
+ * Free any resources still in use (usually just kernel contexts)
+ * at unload; we do for ctxtcnt, because that's what we allocate.
+diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c
+index 2b6c24b7b5865..f07d328689d3d 100644
+--- a/drivers/infiniband/hw/hfi1/sdma.c
++++ b/drivers/infiniband/hw/hfi1/sdma.c
+@@ -838,8 +838,8 @@ struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd,
+ if (current->nr_cpus_allowed != 1)
+ goto out;
+
+- cpu_id = smp_processor_id();
+ rcu_read_lock();
++ cpu_id = smp_processor_id();
+ rht_node = rhashtable_lookup(dd->sdma_rht, &cpu_id,
+ sdma_rht_params);
+
+diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+index d5f3faa1627a4..51dd134952e77 100644
+--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+@@ -33,6 +33,7 @@
+ #include <linux/acpi.h>
+ #include <linux/etherdevice.h>
+ #include <linux/interrupt.h>
++#include <linux/iopoll.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <net/addrconf.h>
+@@ -1050,9 +1051,14 @@ static u32 hns_roce_v2_cmd_hw_resetting(struct hns_roce_dev *hr_dev,
+ unsigned long instance_stage,
+ unsigned long reset_stage)
+ {
++#define HW_RESET_TIMEOUT_US 1000000
++#define HW_RESET_SLEEP_US 1000
++
+ struct hns_roce_v2_priv *priv = hr_dev->priv;
+ struct hnae3_handle *handle = priv->handle;
+ const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
++ unsigned long val;
++ int ret;
+
+ /* When hardware reset is detected, we should stop sending mailbox&cmq&
+ * doorbell to hardware. If now in .init_instance() function, we should
+@@ -1064,7 +1070,11 @@ static u32 hns_roce_v2_cmd_hw_resetting(struct hns_roce_dev *hr_dev,
+ * again.
+ */
+ hr_dev->dis_db = true;
+- if (!ops->get_hw_reset_stat(handle))
++
++ ret = read_poll_timeout(ops->ae_dev_reset_cnt, val,
++ val > hr_dev->reset_cnt, HW_RESET_SLEEP_US,
++ HW_RESET_TIMEOUT_US, false, handle);
++ if (!ret)
+ hr_dev->is_reset = true;
+
+ if (!hr_dev->is_reset || reset_stage == HNS_ROCE_STATE_RST_INIT ||
+@@ -3328,7 +3338,7 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev,
+ memset(cq_context, 0, sizeof(*cq_context));
+
+ hr_reg_write(cq_context, CQC_CQ_ST, V2_CQ_STATE_VALID);
+- hr_reg_write(cq_context, CQC_ARM_ST, REG_NXT_CEQE);
++ hr_reg_write(cq_context, CQC_ARM_ST, NO_ARMED);
+ hr_reg_write(cq_context, CQC_SHIFT, ilog2(hr_cq->cq_depth));
+ hr_reg_write(cq_context, CQC_CEQN, hr_cq->vector);
+ hr_reg_write(cq_context, CQC_CQN, hr_cq->cqn);
+@@ -4399,8 +4409,8 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
+ mtu = ib_mtu_enum_to_int(ib_mtu);
+ if (WARN_ON(mtu <= 0))
+ return -EINVAL;
+-#define MAX_LP_MSG_LEN 65536
+- /* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 64KB */
++#define MAX_LP_MSG_LEN 16384
++ /* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 16KB */
+ lp_pktn_ini = ilog2(MAX_LP_MSG_LEN / mtu);
+ if (WARN_ON(lp_pktn_ini >= 0xF))
+ return -EINVAL;
+@@ -6397,10 +6407,8 @@ static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
+ if (!hr_dev)
+ return 0;
+
+- hr_dev->is_reset = true;
+ hr_dev->active = false;
+ hr_dev->dis_db = true;
+-
+ hr_dev->state = HNS_ROCE_DEVICE_STATE_RST_DOWN;
+
+ return 0;
+diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
+index 7de525a5ccf8c..aa119441eb45c 100644
+--- a/drivers/infiniband/hw/irdma/hw.c
++++ b/drivers/infiniband/hw/irdma/hw.c
+@@ -60,6 +60,8 @@ static void irdma_iwarp_ce_handler(struct irdma_sc_cq *iwcq)
+ {
+ struct irdma_cq *cq = iwcq->back_cq;
+
++ if (!cq->user_mode)
++ cq->armed = false;
+ if (cq->ibcq.comp_handler)
+ cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+ }
+@@ -146,6 +148,7 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
+ qp->flush_code = FLUSH_PROT_ERR;
+ break;
+ case IRDMA_AE_AMP_BAD_QP:
++ case IRDMA_AE_WQE_UNEXPECTED_OPCODE:
+ qp->flush_code = FLUSH_LOC_QP_OP_ERR;
+ break;
+ case IRDMA_AE_AMP_BAD_STAG_KEY:
+@@ -156,7 +159,6 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
+ case IRDMA_AE_PRIV_OPERATION_DENIED:
+ case IRDMA_AE_IB_INVALID_REQUEST:
+ case IRDMA_AE_IB_REMOTE_ACCESS_ERROR:
+- case IRDMA_AE_IB_REMOTE_OP_ERROR:
+ qp->flush_code = FLUSH_REM_ACCESS_ERR;
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ break;
+@@ -184,6 +186,9 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
+ case IRDMA_AE_AMP_MWBIND_INVALID_BOUNDS:
+ qp->flush_code = FLUSH_MW_BIND_ERR;
+ break;
++ case IRDMA_AE_IB_REMOTE_OP_ERROR:
++ qp->flush_code = FLUSH_REM_OP_ERR;
++ break;
+ default:
+ qp->flush_code = FLUSH_FATAL_ERR;
+ break;
+diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h
+index b678fe712447e..8b215f3cee891 100644
+--- a/drivers/infiniband/hw/irdma/main.h
++++ b/drivers/infiniband/hw/irdma/main.h
+@@ -541,6 +541,7 @@ int irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd,
+ void (*callback_fcn)(struct irdma_cqp_request *cqp_request),
+ void *cb_param);
+ void irdma_gsi_ud_qp_ah_cb(struct irdma_cqp_request *cqp_request);
++bool irdma_cq_empty(struct irdma_cq *iwcq);
+ int irdma_inetaddr_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr);
+ int irdma_inet6addr_event(struct notifier_block *notifier, unsigned long event,
+diff --git a/drivers/infiniband/hw/irdma/pble.c b/drivers/infiniband/hw/irdma/pble.c
+index aeeb1c310965d..fed49da770f3b 100644
+--- a/drivers/infiniband/hw/irdma/pble.c
++++ b/drivers/infiniband/hw/irdma/pble.c
+@@ -25,8 +25,7 @@ void irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
+ list_del(&chunk->list);
+ if (chunk->type == PBLE_SD_PAGED)
+ irdma_pble_free_paged_mem(chunk);
+- if (chunk->bitmapbuf)
+- kfree(chunk->bitmapmem.va);
++ bitmap_free(chunk->bitmapbuf);
+ kfree(chunk->chunkmem.va);
+ }
+ }
+@@ -283,7 +282,6 @@ add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
+ "PBLE: next_fpm_addr = %llx chunk_size[%llu] = 0x%llx\n",
+ pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
+ pble_rsrc->unallocated_pble -= (u32)(chunk->size >> 3);
+- list_add(&chunk->list, &pble_rsrc->pinfo.clist);
+ sd_reg_val = (sd_entry_type == IRDMA_SD_TYPE_PAGED) ?
+ sd_entry->u.pd_table.pd_page_addr.pa :
+ sd_entry->u.bp.addr.pa;
+@@ -295,12 +293,12 @@ add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
+ goto error;
+ }
+
++ list_add(&chunk->list, &pble_rsrc->pinfo.clist);
+ sd_entry->valid = true;
+ return 0;
+
+ error:
+- if (chunk->bitmapbuf)
+- kfree(chunk->bitmapmem.va);
++ bitmap_free(chunk->bitmapbuf);
+ kfree(chunk->chunkmem.va);
+
+ return ret_code;
+diff --git a/drivers/infiniband/hw/irdma/pble.h b/drivers/infiniband/hw/irdma/pble.h
+index e1b3b8118a2ca..aa20827dcc9de 100644
+--- a/drivers/infiniband/hw/irdma/pble.h
++++ b/drivers/infiniband/hw/irdma/pble.h
+@@ -78,7 +78,6 @@ struct irdma_chunk {
+ u32 pg_cnt;
+ enum irdma_alloc_type type;
+ struct irdma_sc_dev *dev;
+- struct irdma_virt_mem bitmapmem;
+ struct irdma_virt_mem chunkmem;
+ };
+
+diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
+index ac91ea5296db9..feebfe6bf31ad 100644
+--- a/drivers/infiniband/hw/irdma/utils.c
++++ b/drivers/infiniband/hw/irdma/utils.c
+@@ -2284,15 +2284,10 @@ enum irdma_status_code irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm,
+
+ sizeofbitmap = (u64)pchunk->size >> pprm->pble_shift;
+
+- pchunk->bitmapmem.size = sizeofbitmap >> 3;
+- pchunk->bitmapmem.va = kzalloc(pchunk->bitmapmem.size, GFP_KERNEL);
+-
+- if (!pchunk->bitmapmem.va)
++ pchunk->bitmapbuf = bitmap_zalloc(sizeofbitmap, GFP_KERNEL);
++ if (!pchunk->bitmapbuf)
+ return IRDMA_ERR_NO_MEMORY;
+
+- pchunk->bitmapbuf = pchunk->bitmapmem.va;
+- bitmap_zero(pchunk->bitmapbuf, sizeofbitmap);
+-
+ pchunk->sizeofbitmap = sizeofbitmap;
+ /* each pble is 8 bytes hence shift by 3 */
+ pprm->total_pble_alloc += pchunk->size >> 3;
+@@ -2536,3 +2531,18 @@ void irdma_ib_qp_event(struct irdma_qp *iwqp, enum irdma_qp_event_type event)
+ ibevent.element.qp = &iwqp->ibqp;
+ iwqp->ibqp.event_handler(&ibevent, iwqp->ibqp.qp_context);
+ }
++
++bool irdma_cq_empty(struct irdma_cq *iwcq)
++{
++ struct irdma_cq_uk *ukcq;
++ u64 qword3;
++ __le64 *cqe;
++ u8 polarity;
++
++ ukcq = &iwcq->sc_cq.cq_uk;
++ cqe = IRDMA_GET_CURRENT_CQ_ELEM(ukcq);
++ get_64bit_val(cqe, 24, &qword3);
++ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
++
++ return polarity != ukcq->polarity;
++}
+diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
+index 102dc9342f2a2..8bbc4620a97a2 100644
+--- a/drivers/infiniband/hw/irdma/verbs.c
++++ b/drivers/infiniband/hw/irdma/verbs.c
+@@ -3604,18 +3604,31 @@ static int irdma_req_notify_cq(struct ib_cq *ibcq,
+ struct irdma_cq *iwcq;
+ struct irdma_cq_uk *ukcq;
+ unsigned long flags;
+- enum irdma_cmpl_notify cq_notify = IRDMA_CQ_COMPL_EVENT;
++ enum irdma_cmpl_notify cq_notify;
++ bool promo_event = false;
++ int ret = 0;
+
++ cq_notify = notify_flags == IB_CQ_SOLICITED ?
++ IRDMA_CQ_COMPL_SOLICITED : IRDMA_CQ_COMPL_EVENT;
+ iwcq = to_iwcq(ibcq);
+ ukcq = &iwcq->sc_cq.cq_uk;
+- if (notify_flags == IB_CQ_SOLICITED)
+- cq_notify = IRDMA_CQ_COMPL_SOLICITED;
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+- irdma_uk_cq_request_notification(ukcq, cq_notify);
++ /* Only promote to arm the CQ for any event if the last arm event was solicited. */
++ if (iwcq->last_notify == IRDMA_CQ_COMPL_SOLICITED && notify_flags != IB_CQ_SOLICITED)
++ promo_event = true;
++
++ if (!iwcq->armed || promo_event) {
++ iwcq->armed = true;
++ iwcq->last_notify = cq_notify;
++ irdma_uk_cq_request_notification(ukcq, cq_notify);
++ }
++
++ if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) && !irdma_cq_empty(iwcq))
++ ret = 1;
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+
+- return 0;
++ return ret;
+ }
+
+ static int irdma_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
+diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h
+index 5c244cd321a3a..d0fdef8d09ead 100644
+--- a/drivers/infiniband/hw/irdma/verbs.h
++++ b/drivers/infiniband/hw/irdma/verbs.h
+@@ -110,6 +110,8 @@ struct irdma_cq {
+ u16 cq_size;
+ u16 cq_num;
+ bool user_mode;
++ bool armed;
++ enum irdma_cmpl_notify last_notify;
+ u32 polled_cmpls;
+ u32 cq_mem_size;
+ struct irdma_dma_mem kmem;
+diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
+index f367f4a4abffc..aec2e1851fa70 100644
+--- a/drivers/infiniband/hw/mlx4/main.c
++++ b/drivers/infiniband/hw/mlx4/main.c
+@@ -2217,6 +2217,11 @@ static const struct ib_device_ops mlx4_ib_hw_stats_ops = {
+ .get_hw_stats = mlx4_ib_get_hw_stats,
+ };
+
++static const struct ib_device_ops mlx4_ib_hw_stats_ops1 = {
++ .alloc_hw_device_stats = mlx4_ib_alloc_hw_device_stats,
++ .get_hw_stats = mlx4_ib_get_hw_stats,
++};
++
+ static int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev)
+ {
+ struct mlx4_ib_diag_counters *diag = ibdev->diag_counters;
+@@ -2229,9 +2234,16 @@ static int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev)
+ return 0;
+
+ for (i = 0; i < MLX4_DIAG_COUNTERS_TYPES; i++) {
+- /* i == 1 means we are building port counters */
+- if (i && !per_port)
+- continue;
++ /*
++ * i == 1 means we are building port counters, set a different
++ * stats ops without port stats callback.
++ */
++ if (i && !per_port) {
++ ib_set_device_ops(&ibdev->ib_dev,
++ &mlx4_ib_hw_stats_ops1);
++
++ return 0;
++ }
+
+ ret = __mlx4_ib_alloc_diag_counters(ibdev, &diag[i].name,
+ &diag[i].offset,
+diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
+index 8662f462e2a5f..3a1a4ac9dd33d 100644
+--- a/drivers/infiniband/hw/mlx4/qp.c
++++ b/drivers/infiniband/hw/mlx4/qp.c
+@@ -1099,8 +1099,10 @@ static int create_qp_common(struct ib_pd *pd, struct ib_qp_init_attr *init_attr,
+ 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);
+diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
+index bf20a388eabe1..6204ae2caef58 100644
+--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
++++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
+@@ -641,7 +641,6 @@ struct mlx5_ib_mr {
+
+ /* User MR data */
+ struct mlx5_cache_ent *cache_ent;
+- struct ib_umem *umem;
+
+ /* This is zero'd when the MR is allocated */
+ union {
+@@ -653,7 +652,7 @@ struct mlx5_ib_mr {
+ struct list_head list;
+ };
+
+- /* Used only by kernel MRs (umem == NULL) */
++ /* Used only by kernel MRs */
+ struct {
+ void *descs;
+ void *descs_alloc;
+@@ -675,8 +674,9 @@ struct mlx5_ib_mr {
+ int data_length;
+ };
+
+- /* Used only by User MRs (umem != NULL) */
++ /* Used only by User MRs */
+ struct {
++ struct ib_umem *umem;
+ unsigned int page_shift;
+ /* Current access_flags */
+ int access_flags;
+diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
+index 22e2f4d79743d..69b2ce4c292ae 100644
+--- a/drivers/infiniband/hw/mlx5/mr.c
++++ b/drivers/infiniband/hw/mlx5/mr.c
+@@ -1911,19 +1911,18 @@ err:
+ return ret;
+ }
+
+-static void
+-mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
++static void mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
+ {
+- if (!mr->umem && mr->descs) {
+- struct ib_device *device = mr->ibmr.device;
+- int size = mr->max_descs * mr->desc_size;
+- struct mlx5_ib_dev *dev = to_mdev(device);
++ struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
++ int size = mr->max_descs * mr->desc_size;
+
+- dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
+- DMA_TO_DEVICE);
+- kfree(mr->descs_alloc);
+- mr->descs = NULL;
+- }
++ if (!mr->descs)
++ return;
++
++ dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
++ DMA_TO_DEVICE);
++ kfree(mr->descs_alloc);
++ mr->descs = NULL;
+ }
+
+ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+@@ -1999,7 +1998,8 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+ if (mr->cache_ent) {
+ mlx5_mr_cache_free(dev, mr);
+ } else {
+- mlx5_free_priv_descs(mr);
++ if (!udata)
++ mlx5_free_priv_descs(mr);
+ kfree(mr);
+ }
+ return 0;
+@@ -2086,7 +2086,6 @@ static struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
+ if (err)
+ goto err_free_in;
+
+- mr->umem = NULL;
+ kfree(in);
+
+ return mr;
+@@ -2213,7 +2212,6 @@ static struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
+ }
+
+ mr->ibmr.device = pd->device;
+- mr->umem = NULL;
+
+ switch (mr_type) {
+ case IB_MR_TYPE_MEM_REG:
+diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
+index dcb3653db72d7..3d4e4a766574a 100644
+--- a/drivers/infiniband/hw/qedr/verbs.c
++++ b/drivers/infiniband/hw/qedr/verbs.c
+@@ -2744,15 +2744,18 @@ int qedr_query_qp(struct ib_qp *ibqp,
+ 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;
+diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
+index f0c954575bdec..4fd73b51fabf2 100644
+--- a/drivers/infiniband/sw/rxe/rxe_loc.h
++++ b/drivers/infiniband/sw/rxe/rxe_loc.h
+@@ -86,6 +86,7 @@ struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
+ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length);
+ int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);
+ int rxe_invalidate_mr(struct rxe_qp *qp, u32 rkey);
++int rxe_reg_fast_mr(struct rxe_qp *qp, struct rxe_send_wqe *wqe);
+ int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
+ void rxe_mr_cleanup(struct rxe_pool_entry *arg);
+
+diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
+index 5890a82462161..bedcf15aaea75 100644
+--- a/drivers/infiniband/sw/rxe/rxe_mr.c
++++ b/drivers/infiniband/sw/rxe/rxe_mr.c
+@@ -48,8 +48,14 @@ static void rxe_mr_init(int access, struct rxe_mr *mr)
+ u32 lkey = mr->pelem.index << 8 | rxe_get_next_key(-1);
+ u32 rkey = (access & IB_ACCESS_REMOTE) ? lkey : 0;
+
+- mr->ibmr.lkey = lkey;
+- mr->ibmr.rkey = rkey;
++ /* set ibmr->l/rkey and also copy into private l/rkey
++ * for user MRs these will always be the same
++ * for cases where caller 'owns' the key portion
++ * they may be different until REG_MR WQE is executed.
++ */
++ mr->lkey = mr->ibmr.lkey = lkey;
++ mr->rkey = mr->ibmr.rkey = rkey;
++
+ mr->state = RXE_MR_STATE_INVALID;
+ mr->type = RXE_MR_TYPE_NONE;
+ mr->map_shift = ilog2(RXE_BUF_PER_MAP);
+@@ -191,10 +197,8 @@ int rxe_mr_init_fast(struct rxe_pd *pd, int max_pages, struct rxe_mr *mr)
+ {
+ int err;
+
+- rxe_mr_init(0, mr);
+-
+- /* In fastreg, we also set the rkey */
+- mr->ibmr.rkey = mr->ibmr.lkey;
++ /* always allow remote access for FMRs */
++ rxe_mr_init(IB_ACCESS_REMOTE, mr);
+
+ err = rxe_mr_alloc(mr, max_pages);
+ if (err)
+@@ -507,8 +511,8 @@ struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
+ if (!mr)
+ return NULL;
+
+- if (unlikely((type == RXE_LOOKUP_LOCAL && mr_lkey(mr) != key) ||
+- (type == RXE_LOOKUP_REMOTE && mr_rkey(mr) != key) ||
++ if (unlikely((type == RXE_LOOKUP_LOCAL && mr->lkey != key) ||
++ (type == RXE_LOOKUP_REMOTE && mr->rkey != key) ||
+ mr_pd(mr) != pd || (access && !(access & mr->access)) ||
+ mr->state != RXE_MR_STATE_VALID)) {
+ rxe_drop_ref(mr);
+@@ -531,9 +535,9 @@ int rxe_invalidate_mr(struct rxe_qp *qp, u32 rkey)
+ goto err;
+ }
+
+- if (rkey != mr->ibmr.rkey) {
+- pr_err("%s: rkey (%#x) doesn't match mr->ibmr.rkey (%#x)\n",
+- __func__, rkey, mr->ibmr.rkey);
++ if (rkey != mr->rkey) {
++ pr_err("%s: rkey (%#x) doesn't match mr->rkey (%#x)\n",
++ __func__, rkey, mr->rkey);
+ ret = -EINVAL;
+ goto err_drop_ref;
+ }
+@@ -554,6 +558,49 @@ err:
+ return ret;
+ }
+
++/* user can (re)register fast MR by executing a REG_MR WQE.
++ * user is expected to hold a reference on the ib mr until the
++ * WQE completes.
++ * Once a fast MR is created this is the only way to change the
++ * private keys. It is the responsibility of the user to maintain
++ * the ib mr keys in sync with rxe mr keys.
++ */
++int rxe_reg_fast_mr(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
++{
++ struct rxe_mr *mr = to_rmr(wqe->wr.wr.reg.mr);
++ u32 key = wqe->wr.wr.reg.key;
++ u32 access = wqe->wr.wr.reg.access;
++
++ /* user can only register MR in free state */
++ if (unlikely(mr->state != RXE_MR_STATE_FREE)) {
++ pr_warn("%s: mr->lkey = 0x%x not free\n",
++ __func__, mr->lkey);
++ return -EINVAL;
++ }
++
++ /* user can only register mr with qp in same protection domain */
++ if (unlikely(qp->ibqp.pd != mr->ibmr.pd)) {
++ pr_warn("%s: qp->pd and mr->pd don't match\n",
++ __func__);
++ return -EINVAL;
++ }
++
++ /* user is only allowed to change key portion of l/rkey */
++ if (unlikely((mr->lkey & ~0xff) != (key & ~0xff))) {
++ pr_warn("%s: key = 0x%x has wrong index mr->lkey = 0x%x\n",
++ __func__, key, mr->lkey);
++ return -EINVAL;
++ }
++
++ mr->access = access;
++ mr->lkey = key;
++ mr->rkey = (access & IB_ACCESS_REMOTE) ? key : 0;
++ mr->iova = wqe->wr.wr.reg.mr->iova;
++ mr->state = RXE_MR_STATE_VALID;
++
++ return 0;
++}
++
+ int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+ {
+ struct rxe_mr *mr = to_rmr(ibmr);
+diff --git a/drivers/infiniband/sw/rxe/rxe_mw.c b/drivers/infiniband/sw/rxe/rxe_mw.c
+index 5ba77df7598ed..a5e2ea7d80f02 100644
+--- a/drivers/infiniband/sw/rxe/rxe_mw.c
++++ b/drivers/infiniband/sw/rxe/rxe_mw.c
+@@ -21,7 +21,7 @@ int rxe_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
+ }
+
+ rxe_add_index(mw);
+- ibmw->rkey = (mw->pelem.index << 8) | rxe_get_next_key(-1);
++ mw->rkey = ibmw->rkey = (mw->pelem.index << 8) | rxe_get_next_key(-1);
+ mw->state = (mw->ibmw.type == IB_MW_TYPE_2) ?
+ RXE_MW_STATE_FREE : RXE_MW_STATE_VALID;
+ spin_lock_init(&mw->lock);
+@@ -71,6 +71,8 @@ int rxe_dealloc_mw(struct ib_mw *ibmw)
+ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ struct rxe_mw *mw, struct rxe_mr *mr)
+ {
++ u32 key = wqe->wr.wr.mw.rkey & 0xff;
++
+ if (mw->ibmw.type == IB_MW_TYPE_1) {
+ if (unlikely(mw->state != RXE_MW_STATE_VALID)) {
+ pr_err_once(
+@@ -108,7 +110,7 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ }
+ }
+
+- if (unlikely((wqe->wr.wr.mw.rkey & 0xff) == (mw->ibmw.rkey & 0xff))) {
++ if (unlikely(key == (mw->rkey & 0xff))) {
+ pr_err_once("attempt to bind MW with same key\n");
+ return -EINVAL;
+ }
+@@ -161,13 +163,9 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ static void rxe_do_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ struct rxe_mw *mw, struct rxe_mr *mr)
+ {
+- u32 rkey;
+- u32 new_rkey;
+-
+- rkey = mw->ibmw.rkey;
+- new_rkey = (rkey & 0xffffff00) | (wqe->wr.wr.mw.rkey & 0x000000ff);
++ u32 key = wqe->wr.wr.mw.rkey & 0xff;
+
+- mw->ibmw.rkey = new_rkey;
++ mw->rkey = (mw->rkey & ~0xff) | key;
+ mw->access = wqe->wr.wr.mw.access;
+ mw->state = RXE_MW_STATE_VALID;
+ mw->addr = wqe->wr.wr.mw.addr;
+@@ -197,29 +195,29 @@ int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+ struct rxe_mw *mw;
+ struct rxe_mr *mr;
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
++ u32 mw_rkey = wqe->wr.wr.mw.mw_rkey;
++ u32 mr_lkey = wqe->wr.wr.mw.mr_lkey;
+ unsigned long flags;
+
+- mw = rxe_pool_get_index(&rxe->mw_pool,
+- wqe->wr.wr.mw.mw_rkey >> 8);
++ mw = rxe_pool_get_index(&rxe->mw_pool, mw_rkey >> 8);
+ if (unlikely(!mw)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+- if (unlikely(mw->ibmw.rkey != wqe->wr.wr.mw.mw_rkey)) {
++ if (unlikely(mw->rkey != mw_rkey)) {
+ ret = -EINVAL;
+ goto err_drop_mw;
+ }
+
+ if (likely(wqe->wr.wr.mw.length)) {
+- mr = rxe_pool_get_index(&rxe->mr_pool,
+- wqe->wr.wr.mw.mr_lkey >> 8);
++ mr = rxe_pool_get_index(&rxe->mr_pool, mr_lkey >> 8);
+ if (unlikely(!mr)) {
+ ret = -EINVAL;
+ goto err_drop_mw;
+ }
+
+- if (unlikely(mr->ibmr.lkey != wqe->wr.wr.mw.mr_lkey)) {
++ if (unlikely(mr->lkey != mr_lkey)) {
+ ret = -EINVAL;
+ goto err_drop_mr;
+ }
+@@ -292,7 +290,7 @@ int rxe_invalidate_mw(struct rxe_qp *qp, u32 rkey)
+ goto err;
+ }
+
+- if (rkey != mw->ibmw.rkey) {
++ if (rkey != mw->rkey) {
+ ret = -EINVAL;
+ goto err_drop_ref;
+ }
+@@ -323,7 +321,7 @@ struct rxe_mw *rxe_lookup_mw(struct rxe_qp *qp, int access, u32 rkey)
+ if (!mw)
+ return NULL;
+
+- if (unlikely((rxe_mw_rkey(mw) != rkey) || rxe_mw_pd(mw) != pd ||
++ if (unlikely((mw->rkey != rkey) || rxe_mw_pd(mw) != pd ||
+ (mw->ibmw.type == IB_MW_TYPE_2 && mw->qp != qp) ||
+ (mw->length == 0) ||
+ (access && !(access & mw->access)) ||
+diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h
+index 742e6ec93686c..b5a70cbe94aac 100644
+--- a/drivers/infiniband/sw/rxe/rxe_param.h
++++ b/drivers/infiniband/sw/rxe/rxe_param.h
+@@ -113,7 +113,7 @@ enum rxe_device_param {
+ /* 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,
+diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
+index 1ab6af7ddb254..ed326d82725cd 100644
+--- a/drivers/infiniband/sw/rxe/rxe_qp.c
++++ b/drivers/infiniband/sw/rxe/rxe_qp.c
+@@ -367,6 +367,7 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
+
+ err2:
+ rxe_queue_cleanup(qp->sq.queue);
++ qp->sq.queue = NULL;
+ err1:
+ qp->pd = NULL;
+ qp->rcq = NULL;
+diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
+index 3894197a82f62..fc996fd31e589 100644
+--- a/drivers/infiniband/sw/rxe/rxe_req.c
++++ b/drivers/infiniband/sw/rxe/rxe_req.c
+@@ -572,7 +572,6 @@ static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ static int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+ {
+ u8 opcode = wqe->wr.opcode;
+- struct rxe_mr *mr;
+ u32 rkey;
+ int ret;
+
+@@ -590,14 +589,11 @@ static int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+ }
+ break;
+ case IB_WR_REG_MR:
+- mr = to_rmr(wqe->wr.wr.reg.mr);
+- rxe_add_ref(mr);
+- mr->state = RXE_MR_STATE_VALID;
+- mr->access = wqe->wr.wr.reg.access;
+- mr->ibmr.lkey = wqe->wr.wr.reg.key;
+- mr->ibmr.rkey = wqe->wr.wr.reg.key;
+- mr->iova = wqe->wr.wr.reg.mr->iova;
+- rxe_drop_ref(mr);
++ ret = rxe_reg_fast_mr(qp, wqe);
++ if (unlikely(ret)) {
++ wqe->status = IB_WC_LOC_QP_OP_ERR;
++ return ret;
++ }
+ break;
+ case IB_WR_BIND_MW:
+ ret = rxe_bind_mw(qp, wqe);
+diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
+index ac2a2148027f4..d90b1d77de347 100644
+--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
++++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
+@@ -313,6 +313,8 @@ struct rxe_mr {
+
+ struct ib_umem *umem;
+
++ u32 lkey;
++ u32 rkey;
+ enum rxe_mr_state state;
+ enum rxe_mr_type type;
+ u64 va;
+@@ -350,6 +352,7 @@ struct rxe_mw {
+ enum rxe_mw_state state;
+ struct rxe_qp *qp; /* Type 2 only */
+ struct rxe_mr *mr;
++ u32 rkey;
+ int access;
+ u64 addr;
+ u64 length;
+@@ -474,26 +477,11 @@ static inline struct rxe_pd *mr_pd(struct rxe_mr *mr)
+ return to_rpd(mr->ibmr.pd);
+ }
+
+-static inline u32 mr_lkey(struct rxe_mr *mr)
+-{
+- return mr->ibmr.lkey;
+-}
+-
+-static inline u32 mr_rkey(struct rxe_mr *mr)
+-{
+- return mr->ibmr.rkey;
+-}
+-
+ static inline struct rxe_pd *rxe_mw_pd(struct rxe_mw *mw)
+ {
+ return to_rpd(mw->ibmw.pd);
+ }
+
+-static inline u32 rxe_mw_rkey(struct rxe_mw *mw)
+-{
+- return mw->ibmw.rkey;
+-}
+-
+ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name);
+
+ void rxe_mc_cleanup(struct rxe_pool_entry *arg);
+diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
+index 6c554c11a7ac3..ea58805c480fa 100644
+--- a/drivers/input/joystick/iforce/iforce-usb.c
++++ b/drivers/input/joystick/iforce/iforce-usb.c
+@@ -92,7 +92,7 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 id,
+ 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);
+diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c
+index 17bbaac8b80c8..cdc80715b5fd6 100644
+--- a/drivers/input/misc/ariel-pwrbutton.c
++++ b/drivers/input/misc/ariel-pwrbutton.c
+@@ -149,12 +149,19 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
+
++static const struct spi_device_id ariel_pwrbutton_spi_ids[] = {
++ { .name = "wyse-ariel-ec-input" },
++ { }
++};
++MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids);
++
+ static struct spi_driver ariel_pwrbutton_driver = {
+ .driver = {
+ .name = "dell-wyse-ariel-ec-input",
+ .of_match_table = ariel_pwrbutton_of_match,
+ },
+ .probe = ariel_pwrbutton_probe,
++ .id_table = ariel_pwrbutton_spi_ids,
+ };
+ module_spi_driver(ariel_pwrbutton_driver);
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index 2d0bc029619ff..956d9cd347964 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -517,6 +517,19 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
+ 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];
+
+diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
+index a5a0035536462..aedd055410443 100644
+--- a/drivers/input/serio/i8042-x86ia64io.h
++++ b/drivers/input/serio/i8042-x86ia64io.h
+@@ -272,6 +272,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
+ },
+ },
++ {
++ /* Fujitsu Lifebook T725 laptop */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
++ },
++ },
+ {
+ /* Fujitsu Lifebook U745 */
+ .matches = {
+@@ -840,6 +847,13 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
+ },
+ },
++ {
++ /* Fujitsu Lifebook T725 laptop */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
++ },
++ },
+ {
+ /* Fujitsu U574 laptop */
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
+diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
+index 6abae665ca71d..9d1dea6996a22 100644
+--- a/drivers/input/touchscreen/st1232.c
++++ b/drivers/input/touchscreen/st1232.c
+@@ -92,7 +92,7 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
+ unsigned int retries;
+ int error;
+
+- for (retries = 10; retries; retries--) {
++ for (retries = 100; retries; retries--) {
+ error = st1232_ts_read_data(ts, REG_STATUS, 1);
+ if (!error) {
+ switch (ts->read_buf[0]) {
+diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
+index a9e568276c99f..a45c5536d2506 100644
+--- a/drivers/iommu/amd/iommu_v2.c
++++ b/drivers/iommu/amd/iommu_v2.c
+@@ -928,10 +928,8 @@ static int __init amd_iommu_v2_init(void)
+ {
+ int ret;
+
+- pr_info("AMD IOMMUv2 driver by Joerg Roedel <jroedel@suse.de>\n");
+-
+ if (!amd_iommu_v2_supported()) {
+- pr_info("AMD IOMMUv2 functionality not available on this system\n");
++ pr_info("AMD IOMMUv2 functionality not available on this system - This is not a bug.\n");
+ /*
+ * Load anyway to provide the symbols to other modules
+ * which may use AMD IOMMUv2 optionally.
+@@ -946,6 +944,8 @@ static int __init amd_iommu_v2_init(void)
+
+ amd_iommu_register_ppr_notifier(&ppr_nb);
+
++ pr_info("AMD IOMMUv2 loaded and initialized\n");
++
+ return 0;
+
+ out:
+diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
+index fdfa39ec2a4d4..ad69eeb5ac5ba 100644
+--- a/drivers/iommu/apple-dart.c
++++ b/drivers/iommu/apple-dart.c
+@@ -70,6 +70,8 @@
+ #define DART_ERROR_ADDR_HI 0x54
+ #define DART_ERROR_ADDR_LO 0x50
+
++#define DART_STREAMS_ENABLE 0xfc
++
+ #define DART_TCR(sid) (0x100 + 4 * (sid))
+ #define DART_TCR_TRANSLATE_ENABLE BIT(7)
+ #define DART_TCR_BYPASS0_ENABLE BIT(8)
+@@ -301,6 +303,9 @@ static int apple_dart_hw_reset(struct apple_dart *dart)
+ apple_dart_hw_disable_dma(&stream_map);
+ apple_dart_hw_clear_all_ttbrs(&stream_map);
+
++ /* enable all streams globally since TCR is used to control isolation */
++ writel(DART_STREAM_ALL, dart->regs + DART_STREAMS_ENABLE);
++
+ /* clear any pending errors before the interrupt is unmasked */
+ writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR);
+
+diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
+index 896bea04c347e..2d60216440009 100644
+--- a/drivers/iommu/dma-iommu.c
++++ b/drivers/iommu/dma-iommu.c
+@@ -593,6 +593,9 @@ static dma_addr_t __iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys,
+ memset(padding_start, 0, padding_size);
+ }
+
++ if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
++ arch_sync_dma_for_device(phys, org_size, dir);
++
+ iova = __iommu_dma_map(dev, phys, aligned_size, prot, dma_mask);
+ if (iova == DMA_MAPPING_ERROR && is_swiotlb_buffer(dev, phys))
+ swiotlb_tbl_unmap_single(dev, phys, org_size, dir, attrs);
+@@ -828,17 +831,13 @@ static void iommu_dma_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sg;
+ int i;
+
+- if (dev_is_dma_coherent(dev) && !dev_is_untrusted(dev))
+- return;
+-
+- for_each_sg(sgl, sg, nelems, i) {
+- if (!dev_is_dma_coherent(dev))
++ if (dev_is_untrusted(dev))
++ for_each_sg(sgl, sg, nelems, i)
++ iommu_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
++ sg->length, dir);
++ else if (!dev_is_dma_coherent(dev))
++ for_each_sg(sgl, sg, nelems, i)
+ arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
+-
+- if (is_swiotlb_buffer(dev, sg_phys(sg)))
+- swiotlb_sync_single_for_cpu(dev, sg_phys(sg),
+- sg->length, dir);
+- }
+ }
+
+ static void iommu_dma_sync_sg_for_device(struct device *dev,
+@@ -848,17 +847,14 @@ static void iommu_dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg;
+ int i;
+
+- if (dev_is_dma_coherent(dev) && !dev_is_untrusted(dev))
+- return;
+-
+- for_each_sg(sgl, sg, nelems, i) {
+- if (is_swiotlb_buffer(dev, sg_phys(sg)))
+- swiotlb_sync_single_for_device(dev, sg_phys(sg),
+- sg->length, dir);
+-
+- if (!dev_is_dma_coherent(dev))
++ if (dev_is_untrusted(dev))
++ for_each_sg(sgl, sg, nelems, i)
++ iommu_dma_sync_single_for_device(dev,
++ sg_dma_address(sg),
++ sg->length, dir);
++ else if (!dev_is_dma_coherent(dev))
++ for_each_sg(sgl, sg, nelems, i)
+ 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,
+@@ -867,14 +863,9 @@ static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
+ {
+ phys_addr_t phys = page_to_phys(page) + offset;
+ bool coherent = dev_is_dma_coherent(dev);
+- dma_addr_t dma_handle;
+
+- dma_handle = __iommu_dma_map_swiotlb(dev, phys, size, dma_get_mask(dev),
++ return __iommu_dma_map_swiotlb(dev, phys, size, dma_get_mask(dev),
+ coherent, dir, attrs);
+- if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+- dma_handle != DMA_MAPPING_ERROR)
+- arch_sync_dma_for_device(phys, size, dir);
+- return dma_handle;
+ }
+
+ static void iommu_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
+@@ -1016,15 +1007,16 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
+
+ if (static_branch_unlikely(&iommu_deferred_attach_enabled)) {
+ ret = iommu_deferred_attach(dev, domain);
+- goto out;
++ if (ret)
++ goto out;
+ }
+
+- if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+- iommu_dma_sync_sg_for_device(dev, sg, nents, dir);
+-
+ if (dev_is_untrusted(dev))
+ return iommu_dma_map_sg_swiotlb(dev, sg, nents, dir, attrs);
+
++ if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
++ iommu_dma_sync_sg_for_device(dev, sg, nents, dir);
++
+ /*
+ * Work out how much IOVA space we need, and align the segments to
+ * IOVA granules for the IOMMU driver to handle. With some clever
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index d75f59ae28e6e..78f8c8e6803e9 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -412,6 +412,7 @@ static int __init intel_iommu_setup(char *str)
+ {
+ if (!str)
+ return -EINVAL;
++
+ while (*str) {
+ if (!strncmp(str, "on", 2)) {
+ dmar_disabled = 0;
+@@ -441,13 +442,16 @@ static int __init intel_iommu_setup(char *str)
+ } else if (!strncmp(str, "tboot_noforce", 13)) {
+ pr_info("Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n");
+ intel_iommu_tboot_noforce = 1;
++ } else {
++ pr_notice("Unknown option - '%s'\n", str);
+ }
+
+ str += strcspn(str, ",");
+ while (*str == ',')
+ str++;
+ }
+- return 0;
++
++ return 1;
+ }
+ __setup("intel_iommu=", intel_iommu_setup);
+
+@@ -1222,13 +1226,11 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
+ pte = &pte[pfn_level_offset(pfn, level)];
+
+ do {
+- unsigned long level_pfn;
++ unsigned long level_pfn = pfn & level_mask(level);
+
+ if (!dma_pte_present(pte))
+ goto next;
+
+- level_pfn = pfn & level_mask(level);
+-
+ /* If range covers entire pagetable, free it */
+ if (start_pfn <= level_pfn &&
+ last_pfn >= level_pfn + level_size(level) - 1) {
+@@ -1249,7 +1251,7 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
+ freelist);
+ }
+ next:
+- pfn += level_size(level);
++ pfn = level_pfn + level_size(level);
+ } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
+
+ if (first_pte)
+diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
+index d837adfd1da55..25b834104790c 100644
+--- a/drivers/iommu/mtk_iommu.c
++++ b/drivers/iommu/mtk_iommu.c
+@@ -550,7 +550,9 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
+ phys_addr_t pa;
+
+ pa = dom->iop->iova_to_phys(dom->iop, iova);
+- if (dom->data->enable_4GB && pa >= MTK_IOMMU_4GB_MODE_REMAP_BASE)
++ if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT) &&
++ dom->data->enable_4GB &&
++ pa >= MTK_IOMMU_4GB_MODE_REMAP_BASE)
+ pa &= ~BIT_ULL(32);
+
+ return pa;
+diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
+index 5cb260820eda6..7f23ad61c094f 100644
+--- a/drivers/iommu/rockchip-iommu.c
++++ b/drivers/iommu/rockchip-iommu.c
+@@ -200,8 +200,8 @@ static inline phys_addr_t rk_dte_pt_address(u32 dte)
+ #define DTE_HI_MASK2 GENMASK(7, 4)
+ #define DTE_HI_SHIFT1 24 /* shift bit 8 to bit 32 */
+ #define DTE_HI_SHIFT2 32 /* shift bit 4 to bit 36 */
+-#define PAGE_DESC_HI_MASK1 GENMASK_ULL(39, 36)
+-#define PAGE_DESC_HI_MASK2 GENMASK_ULL(35, 32)
++#define PAGE_DESC_HI_MASK1 GENMASK_ULL(35, 32)
++#define PAGE_DESC_HI_MASK2 GENMASK_ULL(39, 36)
+
+ static inline phys_addr_t rk_dte_pt_address_v2(u32 dte)
+ {
+diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
+index 53e0fb0562c11..c91ddb0cf1448 100644
+--- a/drivers/irqchip/irq-armada-370-xp.c
++++ b/drivers/irqchip/irq-armada-370-xp.c
+@@ -232,16 +232,12 @@ static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
+ 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 @@ static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
+ NULL, NULL);
+ }
+
+- return hwirq;
++ return 0;
+ }
+
+ static void armada_370_xp_msi_free(struct irq_domain *domain,
+@@ -259,7 +255,7 @@ static void armada_370_xp_msi_free(struct irq_domain *domain,
+ 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);
+ }
+
+diff --git a/drivers/irqchip/irq-aspeed-scu-ic.c b/drivers/irqchip/irq-aspeed-scu-ic.c
+index f3c6855a4cefb..18b77c3e6db4b 100644
+--- a/drivers/irqchip/irq-aspeed-scu-ic.c
++++ b/drivers/irqchip/irq-aspeed-scu-ic.c
+@@ -76,8 +76,8 @@ static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
+ generic_handle_domain_irq(scu_ic->irq_domain,
+ bit - scu_ic->irq_shift);
+
+- regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
+- BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
++ regmap_write_bits(scu_ic->scu, scu_ic->reg, mask,
++ BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
+ }
+
+ chained_irq_exit(chip, desc);
+diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c
+index e3483789f4df3..1bd0621c4ce2a 100644
+--- a/drivers/irqchip/irq-bcm6345-l1.c
++++ b/drivers/irqchip/irq-bcm6345-l1.c
+@@ -140,7 +140,7 @@ static void bcm6345_l1_irq_handle(struct irq_desc *desc)
+ 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();
+ }
+diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
+index eb0882d153666..0cb584d9815b9 100644
+--- a/drivers/irqchip/irq-gic-v3-its.c
++++ b/drivers/irqchip/irq-gic-v3-its.c
+@@ -742,7 +742,7 @@ static struct its_collection *its_build_invall_cmd(struct its_node *its,
+
+ its_fixup_cmd(cmd);
+
+- return NULL;
++ return desc->its_invall_cmd.col;
+ }
+
+ static struct its_vpe *its_build_vinvall_cmd(struct its_node *its,
+diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
+index b31c4cff4d3a5..599bb6fc5f0a2 100644
+--- a/drivers/irqchip/irq-nvic.c
++++ b/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
+ /*
+diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
+index cf74cfa820453..259065d271ef0 100644
+--- a/drivers/irqchip/irq-sifive-plic.c
++++ b/drivers/irqchip/irq-sifive-plic.c
+@@ -163,7 +163,13 @@ static void plic_irq_eoi(struct irq_data *d)
+ {
+ 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 = {
+diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
+index 64175a893312e..bb4793c7b38fd 100644
+--- a/drivers/mailbox/mtk-cmdq-mailbox.c
++++ b/drivers/mailbox/mtk-cmdq-mailbox.c
+@@ -195,7 +195,6 @@ static void cmdq_task_exec_done(struct cmdq_task *task, int sta)
+ struct cmdq_task_cb *cb = &task->pkt->async_cb;
+ struct cmdq_cb_data data;
+
+- WARN_ON(cb->cb == (cmdq_async_flush_cb)NULL);
+ data.sta = sta;
+ data.data = cb->data;
+ data.pkt = task->pkt;
+@@ -532,7 +531,8 @@ static int cmdq_probe(struct platform_device *pdev)
+ struct device_node *phandle = dev->of_node;
+ struct device_node *node;
+ int alias_id = 0;
+- char clk_name[4] = "gce";
++ static const char * const clk_name = "gce";
++ static const char * const clk_names[] = { "gce0", "gce1" };
+
+ cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
+ if (!cmdq)
+@@ -570,12 +570,9 @@ static int cmdq_probe(struct platform_device *pdev)
+
+ if (cmdq->gce_num > 1) {
+ for_each_child_of_node(phandle->parent, node) {
+- char clk_id[8];
+-
+ alias_id = of_alias_get_id(node, clk_name);
+- if (alias_id < cmdq->gce_num) {
+- snprintf(clk_id, sizeof(clk_id), "%s%d", clk_name, alias_id);
+- cmdq->clocks[alias_id].id = clk_id;
++ if (alias_id >= 0 && alias_id < cmdq->gce_num) {
++ cmdq->clocks[alias_id].id = clk_names[alias_id];
+ cmdq->clocks[alias_id].clk = of_clk_get(node, 0);
+ if (IS_ERR(cmdq->clocks[alias_id].clk)) {
+ dev_err(dev, "failed to get gce clk: %d\n", alias_id);
+diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
+index 0595559de174a..183a58c893774 100644
+--- a/drivers/md/bcache/btree.c
++++ b/drivers/md/bcache/btree.c
+@@ -378,7 +378,7 @@ static void do_btree_node_write(struct btree *b)
+ struct bvec_iter_all iter_all;
+
+ bio_for_each_segment_all(bv, b->bio, iter_all) {
+- memcpy(bvec_virt(bv), addr, PAGE_SIZE);
++ memcpy(page_address(bv->bv_page), addr, PAGE_SIZE);
+ addr += PAGE_SIZE;
+ }
+
+diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
+index f2874c77ff797..3f72c0f40613d 100644
+--- a/drivers/md/bcache/super.c
++++ b/drivers/md/bcache/super.c
+@@ -885,9 +885,9 @@ static void bcache_device_free(struct bcache_device *d)
+ bcache_device_detach(d);
+
+ if (disk) {
+- blk_cleanup_disk(disk);
+ ida_simple_remove(&bcache_device_idx,
+ first_minor_to_idx(disk->first_minor));
++ blk_cleanup_disk(disk);
+ }
+
+ bioset_exit(&d->bio_split);
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index 6c0c3d0d905aa..44006b860d0a5 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -2193,6 +2193,7 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
+
+ if (!num_sectors || num_sectors > max_sectors)
+ num_sectors = max_sectors;
++ rdev->sb_start = sb_start;
+ }
+ sb = page_address(rdev->sb_page);
+ sb->data_size = cpu_to_le64(num_sectors);
+@@ -2976,7 +2977,11 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
+ * -write_error - clears WriteErrorSeen
+ * {,-}failfast - set/clear FailFast
+ */
++
++ struct mddev *mddev = rdev->mddev;
+ int err = -EINVAL;
++ bool need_update_sb = false;
++
+ if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
+ md_error(rdev->mddev, rdev);
+ if (test_bit(Faulty, &rdev->flags))
+@@ -2991,7 +2996,6 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
+ if (rdev->raid_disk >= 0)
+ err = -EBUSY;
+ else {
+- struct mddev *mddev = rdev->mddev;
+ err = 0;
+ if (mddev_is_clustered(mddev))
+ err = md_cluster_ops->remove_disk(mddev, rdev);
+@@ -3008,10 +3012,12 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
+ } else if (cmd_match(buf, "writemostly")) {
+ set_bit(WriteMostly, &rdev->flags);
+ mddev_create_serial_pool(rdev->mddev, rdev, false);
++ need_update_sb = true;
+ err = 0;
+ } else if (cmd_match(buf, "-writemostly")) {
+ mddev_destroy_serial_pool(rdev->mddev, rdev, false);
+ clear_bit(WriteMostly, &rdev->flags);
++ need_update_sb = true;
+ err = 0;
+ } else if (cmd_match(buf, "blocked")) {
+ set_bit(Blocked, &rdev->flags);
+@@ -3037,9 +3043,11 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
+ err = 0;
+ } else if (cmd_match(buf, "failfast")) {
+ set_bit(FailFast, &rdev->flags);
++ need_update_sb = true;
+ err = 0;
+ } else if (cmd_match(buf, "-failfast")) {
+ clear_bit(FailFast, &rdev->flags);
++ need_update_sb = true;
+ err = 0;
+ } else if (cmd_match(buf, "-insync") && rdev->raid_disk >= 0 &&
+ !test_bit(Journal, &rdev->flags)) {
+@@ -3118,6 +3126,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
+ clear_bit(ExternalBbl, &rdev->flags);
+ err = 0;
+ }
++ if (need_update_sb)
++ md_update_sb(mddev, 1);
+ if (!err)
+ sysfs_notify_dirent_safe(rdev->sysfs_state);
+ return err ? err : len;
+diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
+index 70532335c7c7e..cb670f16e98e9 100644
+--- a/drivers/md/persistent-data/dm-btree-remove.c
++++ b/drivers/md/persistent-data/dm-btree-remove.c
+@@ -423,9 +423,9 @@ static int rebalance_children(struct shadow_spine *s,
+
+ 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;
+ }
+
+diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
+index 19598bd38939d..6ba12f0f0f036 100644
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -1496,7 +1496,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
+ if (!r1_bio->bios[i])
+ continue;
+
+- if (first_clone) {
++ if (first_clone && test_bit(WriteMostly, &rdev->flags)) {
+ /* do behind I/O ?
+ * Not if there are too many, or cannot
+ * allocate memory, or a reader on WriteMostly
+diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
+index 79fa36de8a04a..cd9cb354dc2c7 100644
+--- a/drivers/media/cec/core/cec-adap.c
++++ b/drivers/media/cec/core/cec-adap.c
+@@ -1199,6 +1199,7 @@ void cec_received_msg_ts(struct cec_adapter *adap,
+ 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);
+
+diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
+index 508ac295eb06e..033b0c83272fe 100644
+--- a/drivers/media/common/videobuf2/videobuf2-core.c
++++ b/drivers/media/common/videobuf2/videobuf2-core.c
+@@ -68,13 +68,13 @@ module_param(debug, int, 0644);
+ err; \
+ })
+
+-#define call_ptr_memop(vb, op, args...) \
++#define call_ptr_memop(op, vb, args...) \
+ ({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ void *ptr; \
+ \
+ log_memop(vb, op); \
+- ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
++ ptr = _q->mem_ops->op ? _q->mem_ops->op(vb, args) : NULL; \
+ if (!IS_ERR_OR_NULL(ptr)) \
+ (vb)->cnt_mem_ ## op++; \
+ ptr; \
+@@ -144,9 +144,9 @@ module_param(debug, int, 0644);
+ ((vb)->vb2_queue->mem_ops->op ? \
+ (vb)->vb2_queue->mem_ops->op(args) : 0)
+
+-#define call_ptr_memop(vb, op, args...) \
++#define call_ptr_memop(op, vb, args...) \
+ ((vb)->vb2_queue->mem_ops->op ? \
+- (vb)->vb2_queue->mem_ops->op(args) : NULL)
++ (vb)->vb2_queue->mem_ops->op(vb, args) : NULL)
+
+ #define call_void_memop(vb, op, args...) \
+ do { \
+@@ -230,9 +230,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
+ if (size < vb->planes[plane].length)
+ goto free;
+
+- mem_priv = call_ptr_memop(vb, alloc,
+- q->alloc_devs[plane] ? : q->dev,
+- q->dma_attrs, size, q->dma_dir, q->gfp_flags);
++ mem_priv = call_ptr_memop(alloc,
++ vb,
++ q->alloc_devs[plane] ? : q->dev,
++ size);
+ if (IS_ERR_OR_NULL(mem_priv)) {
+ if (mem_priv)
+ ret = PTR_ERR(mem_priv);
+@@ -975,7 +976,7 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
+ if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv)
+ return NULL;
+
+- return call_ptr_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
++ return call_ptr_memop(vaddr, vb, vb->planes[plane_no].mem_priv);
+
+ }
+ EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
+@@ -985,7 +986,7 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
+ if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv)
+ return NULL;
+
+- return call_ptr_memop(vb, cookie, vb->planes[plane_no].mem_priv);
++ return call_ptr_memop(cookie, vb, vb->planes[plane_no].mem_priv);
+ }
+ EXPORT_SYMBOL_GPL(vb2_plane_cookie);
+
+@@ -1125,10 +1126,11 @@ static int __prepare_userptr(struct vb2_buffer *vb)
+ vb->planes[plane].data_offset = 0;
+
+ /* Acquire each plane's memory */
+- mem_priv = call_ptr_memop(vb, get_userptr,
+- q->alloc_devs[plane] ? : q->dev,
+- planes[plane].m.userptr,
+- planes[plane].length, q->dma_dir);
++ mem_priv = call_ptr_memop(get_userptr,
++ vb,
++ q->alloc_devs[plane] ? : q->dev,
++ planes[plane].m.userptr,
++ planes[plane].length);
+ if (IS_ERR(mem_priv)) {
+ dprintk(q, 1, "failed acquiring userspace memory for plane %d\n",
+ plane);
+@@ -1249,9 +1251,11 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
+ vb->planes[plane].data_offset = 0;
+
+ /* Acquire each plane's memory */
+- mem_priv = call_ptr_memop(vb, attach_dmabuf,
+- q->alloc_devs[plane] ? : q->dev,
+- dbuf, planes[plane].length, q->dma_dir);
++ mem_priv = call_ptr_memop(attach_dmabuf,
++ vb,
++ q->alloc_devs[plane] ? : q->dev,
++ dbuf,
++ planes[plane].length);
+ if (IS_ERR(mem_priv)) {
+ dprintk(q, 1, "failed to attach dmabuf\n");
+ ret = PTR_ERR(mem_priv);
+@@ -2187,8 +2191,10 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
+
+ vb_plane = &vb->planes[plane];
+
+- dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv,
+- flags & O_ACCMODE);
++ dbuf = call_ptr_memop(get_dmabuf,
++ vb,
++ vb_plane->mem_priv,
++ flags & O_ACCMODE);
+ if (IS_ERR_OR_NULL(dbuf)) {
+ dprintk(q, 1, "failed to export buffer %d, plane %d\n",
+ index, plane);
+diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+index a7f61ba854405..be376f3011b68 100644
+--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
++++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+@@ -40,6 +40,8 @@ struct vb2_dc_buf {
+
+ /* DMABUF related */
+ struct dma_buf_attachment *db_attach;
++
++ struct vb2_buffer *vb;
+ };
+
+ /*********************************************/
+@@ -66,14 +68,14 @@ static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
+ /* callbacks for all buffers */
+ /*********************************************/
+
+-static void *vb2_dc_cookie(void *buf_priv)
++static void *vb2_dc_cookie(struct vb2_buffer *vb, void *buf_priv)
+ {
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return &buf->dma_addr;
+ }
+
+-static void *vb2_dc_vaddr(void *buf_priv)
++static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv)
+ {
+ struct vb2_dc_buf *buf = buf_priv;
+ struct dma_buf_map map;
+@@ -137,9 +139,9 @@ static void vb2_dc_put(void *buf_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_dc_alloc(struct device *dev, unsigned long attrs,
+- unsigned long size, enum dma_data_direction dma_dir,
+- gfp_t gfp_flags)
++static void *vb2_dc_alloc(struct vb2_buffer *vb,
++ struct device *dev,
++ unsigned long size)
+ {
+ struct vb2_dc_buf *buf;
+
+@@ -150,9 +152,10 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs,
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+- buf->attrs = attrs;
++ buf->attrs = vb->vb2_queue->dma_attrs;
+ buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,
+- GFP_KERNEL | gfp_flags, buf->attrs);
++ GFP_KERNEL | vb->vb2_queue->gfp_flags,
++ buf->attrs);
+ if (!buf->cookie) {
+ dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
+ kfree(buf);
+@@ -165,11 +168,12 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs,
+ /* Prevent the device from being released while the buffer is used */
+ buf->dev = get_device(dev);
+ buf->size = size;
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_dc_put;
+ buf->handler.arg = buf;
++ buf->vb = vb;
+
+ refcount_set(&buf->refcount, 1);
+
+@@ -397,7 +401,9 @@ static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf)
+ return sgt;
+ }
+
+-static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags)
++static struct dma_buf *vb2_dc_get_dmabuf(struct vb2_buffer *vb,
++ void *buf_priv,
++ unsigned long flags)
+ {
+ struct vb2_dc_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
+@@ -459,8 +465,8 @@ static void vb2_dc_put_userptr(void *buf_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
+- unsigned long size, enum dma_data_direction dma_dir)
++static void *vb2_dc_get_userptr(struct vb2_buffer *vb, struct device *dev,
++ unsigned long vaddr, unsigned long size)
+ {
+ struct vb2_dc_buf *buf;
+ struct frame_vector *vec;
+@@ -490,7 +496,8 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
+ return ERR_PTR(-ENOMEM);
+
+ buf->dev = dev;
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
++ buf->vb = vb;
+
+ offset = lower_32_bits(offset_in_page(vaddr));
+ vec = vb2_create_framevec(vaddr, size);
+@@ -660,8 +667,8 @@ static void vb2_dc_detach_dmabuf(void *mem_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+- unsigned long size, enum dma_data_direction dma_dir)
++static void *vb2_dc_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
++ struct dma_buf *dbuf, unsigned long size)
+ {
+ struct vb2_dc_buf *buf;
+ struct dma_buf_attachment *dba;
+@@ -677,6 +684,8 @@ static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+ return ERR_PTR(-ENOMEM);
+
+ buf->dev = dev;
++ buf->vb = vb;
++
+ /* create attachment for the dmabuf with the user device */
+ dba = dma_buf_attach(dbuf, buf->dev);
+ if (IS_ERR(dba)) {
+@@ -685,7 +694,7 @@ static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+ return dba;
+ }
+
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->size = size;
+ buf->db_attach = dba;
+
+diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+index c5b06a5095661..0d6389dd9b0c6 100644
+--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
++++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+@@ -51,6 +51,8 @@ struct vb2_dma_sg_buf {
+ struct vb2_vmarea_handler handler;
+
+ struct dma_buf_attachment *db_attach;
++
++ struct vb2_buffer *vb;
+ };
+
+ static void vb2_dma_sg_put(void *buf_priv);
+@@ -96,9 +98,8 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
+ return 0;
+ }
+
+-static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
+- unsigned long size, enum dma_data_direction dma_dir,
+- gfp_t gfp_flags)
++static void *vb2_dma_sg_alloc(struct vb2_buffer *vb, struct device *dev,
++ unsigned long size)
+ {
+ struct vb2_dma_sg_buf *buf;
+ struct sg_table *sgt;
+@@ -113,7 +114,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
+ return ERR_PTR(-ENOMEM);
+
+ buf->vaddr = NULL;
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->offset = 0;
+ buf->size = size;
+ /* size is already page aligned */
+@@ -130,7 +131,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
+ if (!buf->pages)
+ goto fail_pages_array_alloc;
+
+- ret = vb2_dma_sg_alloc_compacted(buf, gfp_flags);
++ ret = vb2_dma_sg_alloc_compacted(buf, vb->vb2_queue->gfp_flags);
+ if (ret)
+ goto fail_pages_alloc;
+
+@@ -154,6 +155,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_dma_sg_put;
+ buf->handler.arg = buf;
++ buf->vb = vb;
+
+ refcount_set(&buf->refcount, 1);
+
+@@ -213,9 +215,8 @@ static void vb2_dma_sg_finish(void *buf_priv)
+ dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir);
+ }
+
+-static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
+- unsigned long size,
+- enum dma_data_direction dma_dir)
++static void *vb2_dma_sg_get_userptr(struct vb2_buffer *vb, struct device *dev,
++ unsigned long vaddr, unsigned long size)
+ {
+ struct vb2_dma_sg_buf *buf;
+ struct sg_table *sgt;
+@@ -230,10 +231,11 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
+
+ buf->vaddr = NULL;
+ buf->dev = dev;
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->offset = vaddr & ~PAGE_MASK;
+ buf->size = size;
+ buf->dma_sgt = &buf->sg_table;
++ buf->vb = vb;
+ vec = vb2_create_framevec(vaddr, size);
+ if (IS_ERR(vec))
+ goto userptr_fail_pfnvec;
+@@ -292,7 +294,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_dma_sg_vaddr(void *buf_priv)
++static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv)
+ {
+ struct vb2_dma_sg_buf *buf = buf_priv;
+ struct dma_buf_map map;
+@@ -511,7 +513,9 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
+ .release = vb2_dma_sg_dmabuf_ops_release,
+ };
+
+-static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags)
++static struct dma_buf *vb2_dma_sg_get_dmabuf(struct vb2_buffer *vb,
++ void *buf_priv,
++ unsigned long flags)
+ {
+ struct vb2_dma_sg_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
+@@ -605,8 +609,8 @@ static void vb2_dma_sg_detach_dmabuf(void *mem_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+- unsigned long size, enum dma_data_direction dma_dir)
++static void *vb2_dma_sg_attach_dmabuf(struct vb2_buffer *vb, struct device *dev,
++ struct dma_buf *dbuf, unsigned long size)
+ {
+ struct vb2_dma_sg_buf *buf;
+ struct dma_buf_attachment *dba;
+@@ -630,14 +634,15 @@ static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+ return dba;
+ }
+
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->size = size;
+ buf->db_attach = dba;
++ buf->vb = vb;
+
+ return buf;
+ }
+
+-static void *vb2_dma_sg_cookie(void *buf_priv)
++static void *vb2_dma_sg_cookie(struct vb2_buffer *vb, void *buf_priv)
+ {
+ struct vb2_dma_sg_buf *buf = buf_priv;
+
+diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+index 83f95258ec8c6..ef36abd912dcc 100644
+--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
++++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+@@ -34,13 +34,12 @@ struct vb2_vmalloc_buf {
+
+ static void vb2_vmalloc_put(void *buf_priv);
+
+-static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs,
+- unsigned long size, enum dma_data_direction dma_dir,
+- gfp_t gfp_flags)
++static void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev,
++ unsigned long size)
+ {
+ struct vb2_vmalloc_buf *buf;
+
+- buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags);
++ buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+@@ -52,7 +51,7 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs,
+ return ERR_PTR(-ENOMEM);
+ }
+
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_vmalloc_put;
+ buf->handler.arg = buf;
+@@ -71,9 +70,8 @@ static void vb2_vmalloc_put(void *buf_priv)
+ }
+ }
+
+-static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr,
+- unsigned long size,
+- enum dma_data_direction dma_dir)
++static void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev,
++ unsigned long vaddr, unsigned long size)
+ {
+ struct vb2_vmalloc_buf *buf;
+ struct frame_vector *vec;
+@@ -84,7 +82,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr,
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ offset = vaddr & ~PAGE_MASK;
+ buf->size = size;
+ vec = vb2_create_framevec(vaddr, size);
+@@ -147,7 +145,7 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_vmalloc_vaddr(void *buf_priv)
++static void *vb2_vmalloc_vaddr(struct vb2_buffer *vb, void *buf_priv)
+ {
+ struct vb2_vmalloc_buf *buf = buf_priv;
+
+@@ -339,7 +337,9 @@ static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = {
+ .release = vb2_vmalloc_dmabuf_ops_release,
+ };
+
+-static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flags)
++static struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb,
++ void *buf_priv,
++ unsigned long flags)
+ {
+ struct vb2_vmalloc_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
+@@ -403,8 +403,10 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv)
+ kfree(buf);
+ }
+
+-static void *vb2_vmalloc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+- unsigned long size, enum dma_data_direction dma_dir)
++static void *vb2_vmalloc_attach_dmabuf(struct vb2_buffer *vb,
++ struct device *dev,
++ struct dma_buf *dbuf,
++ unsigned long size)
+ {
+ struct vb2_vmalloc_buf *buf;
+
+@@ -416,7 +418,7 @@ static void *vb2_vmalloc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf,
+ return ERR_PTR(-ENOMEM);
+
+ buf->dbuf = dbuf;
+- buf->dma_dir = dma_dir;
++ buf->dma_dir = vb->vb2_queue->dma_dir;
+ buf->size = size;
+
+ return buf;
+diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c
+index e4528784f8477..fff212c0bf3b5 100644
+--- a/drivers/media/dvb-frontends/mn88443x.c
++++ b/drivers/media/dvb-frontends/mn88443x.c
+@@ -204,11 +204,18 @@ struct mn88443x_priv {
+ 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 @@ static void mn88443x_cmn_power_on(struct mn88443x_priv *chip)
+ } else {
+ regmap_write(r_t, HIZSET3, 0x8f);
+ }
++
++ return 0;
+ }
+
+ static void mn88443x_cmn_power_off(struct mn88443x_priv *chip)
+@@ -738,7 +747,10 @@ static int mn88443x_probe(struct i2c_client *client,
+ 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);
+
+diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c
+index 2bf9467b917d1..71991f8638e6b 100644
+--- a/drivers/media/firewire/firedtv-avc.c
++++ b/drivers/media/firewire/firedtv-avc.c
+@@ -1165,7 +1165,11 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
+ 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 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
+ 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;
+ }
+diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c
+index 9363d005e2b61..e0d57e09dab0c 100644
+--- a/drivers/media/firewire/firedtv-ci.c
++++ b/drivers/media/firewire/firedtv-ci.c
+@@ -134,6 +134,8 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
+ } 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);
+ }
+diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
+index 08feb3e8c1bf6..6157e73eef24e 100644
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -597,6 +597,7 @@ config VIDEO_AK881X
+ config VIDEO_THS8200
+ tristate "Texas Instruments THS8200 video encoder"
+ depends on VIDEO_V4L2 && I2C
++ select V4L2_ASYNC
+ help
+ Support for the Texas Instruments THS8200 video encoder.
+
+diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
+index 81cdf37216ca7..c249507aa2dbc 100644
+--- a/drivers/media/i2c/imx258.c
++++ b/drivers/media/i2c/imx258.c
+@@ -1260,18 +1260,18 @@ static int imx258_probe(struct i2c_client *client)
+ return -ENOMEM;
+
+ imx258->clk = devm_clk_get_optional(&client->dev, NULL);
++ if (IS_ERR(imx258->clk))
++ return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
++ "error getting clock\n");
+ if (!imx258->clk) {
+ dev_dbg(&client->dev,
+ "no clock provided, using clock-frequency property\n");
+
+ device_property_read_u32(&client->dev, "clock-frequency", &val);
+- if (val != IMX258_INPUT_CLOCK_FREQ)
+- return -EINVAL;
+- } else if (IS_ERR(imx258->clk)) {
+- return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
+- "error getting clock\n");
++ } else {
++ val = clk_get_rate(imx258->clk);
+ }
+- if (clk_get_rate(imx258->clk) != IMX258_INPUT_CLOCK_FREQ) {
++ if (val != IMX258_INPUT_CLOCK_FREQ) {
+ dev_err(&client->dev, "input clock frequency not supported\n");
+ return -EINVAL;
+ }
+diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
+index 92376592455ee..56674173524fd 100644
+--- a/drivers/media/i2c/ir-kbd-i2c.c
++++ b/drivers/media/i2c/ir-kbd-i2c.c
+@@ -791,6 +791,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ 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;
+ }
+diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
+index 6eb88ef997836..3ae1b28c8351b 100644
+--- a/drivers/media/i2c/mt9p031.c
++++ b/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
+@@ -444,9 +446,23 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031)
+ 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);
+@@ -466,6 +482,16 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
+ 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);
+ }
+
+diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
+index 6070aaf0b32ea..4dafa9f1cf522 100644
+--- a/drivers/media/i2c/tda1997x.c
++++ b/drivers/media/i2c/tda1997x.c
+@@ -1248,13 +1248,13 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
+ {
+ 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",
+@@ -1928,13 +1928,13 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
+ {
+ 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",
+diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
+index ab14d35214aa8..25dc8d4dc5b73 100644
+--- a/drivers/media/pci/cx23885/cx23885-alsa.c
++++ b/drivers/media/pci/cx23885/cx23885-alsa.c
+@@ -550,7 +550,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
+ 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 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
+
+ error:
+ snd_card_free(card);
++error_msg:
+ pr_err("%s(): Failed to register analog audio adapter\n",
+ __func__);
+
+diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
+index e2d56dca5be40..5ad03b2a50bdb 100644
+--- a/drivers/media/pci/ivtv/ivtvfb.c
++++ b/drivers/media/pci/ivtv/ivtvfb.c
+@@ -36,7 +36,7 @@
+ #include <linux/fb.h>
+ #include <linux/ivtvfb.h>
+
+-#ifdef CONFIG_X86_64
++#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+ #include <asm/memtype.h>
+ #endif
+
+@@ -1157,7 +1157,7 @@ static int ivtvfb_init_card(struct ivtv *itv)
+ {
+ int rc;
+
+-#ifdef CONFIG_X86_64
++#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+ if (pat_enabled()) {
+ if (ivtvfb_force_pat) {
+ pr_info("PAT is enabled. Write-combined framebuffer caching will be disabled.\n");
+diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+index 6f3125c2d0976..77bae14685513 100644
+--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
++++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+@@ -258,19 +258,24 @@ static irqreturn_t netup_unidvb_isr(int irq, void *dev_id)
+ 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);
+diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
+index 887b492e4ad1c..14a119b43bca0 100644
+--- a/drivers/media/platform/allegro-dvt/allegro-core.c
++++ b/drivers/media/platform/allegro-dvt/allegro-core.c
+@@ -2185,6 +2185,15 @@ static irqreturn_t allegro_irq_thread(int irq, void *data)
+ {
+ struct allegro_dev *dev = data;
+
++ /*
++ * The firmware is initialized after the mailbox is setup. We further
++ * check the AL5_ITC_CPU_IRQ_STA register, if the firmware actually
++ * triggered the interrupt. Although this should not happen, make sure
++ * that we ignore interrupts, if the mailbox is not initialized.
++ */
++ if (!dev->mbox_status)
++ return IRQ_NONE;
++
+ allegro_mbox_notify(dev->mbox_status);
+
+ return IRQ_HANDLED;
+diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c
+index 136ab7cf36edc..ebf264b980f91 100644
+--- a/drivers/media/platform/atmel/atmel-isc-base.c
++++ b/drivers/media/platform/atmel/atmel-isc-base.c
+@@ -123,11 +123,9 @@ static int isc_clk_prepare(struct clk_hw *hw)
+ struct isc_clk *isc_clk = to_isc_clk(hw);
+ int ret;
+
+- if (isc_clk->id == ISC_ISPCK) {
+- ret = pm_runtime_resume_and_get(isc_clk->dev);
+- if (ret < 0)
+- return ret;
+- }
++ ret = pm_runtime_resume_and_get(isc_clk->dev);
++ if (ret < 0)
++ return ret;
+
+ return isc_wait_clk_stable(hw);
+ }
+@@ -138,8 +136,7 @@ static void isc_clk_unprepare(struct clk_hw *hw)
+
+ isc_wait_clk_stable(hw);
+
+- if (isc_clk->id == ISC_ISPCK)
+- pm_runtime_put_sync(isc_clk->dev);
++ pm_runtime_put_sync(isc_clk->dev);
+ }
+
+ static int isc_clk_enable(struct clk_hw *hw)
+@@ -186,16 +183,13 @@ static int isc_clk_is_enabled(struct clk_hw *hw)
+ u32 status;
+ int ret;
+
+- if (isc_clk->id == ISC_ISPCK) {
+- ret = pm_runtime_resume_and_get(isc_clk->dev);
+- if (ret < 0)
+- return 0;
+- }
++ ret = pm_runtime_resume_and_get(isc_clk->dev);
++ if (ret < 0)
++ return 0;
+
+ regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
+
+- if (isc_clk->id == ISC_ISPCK)
+- pm_runtime_put_sync(isc_clk->dev);
++ pm_runtime_put_sync(isc_clk->dev);
+
+ return status & ISC_CLK(isc_clk->id) ? 1 : 0;
+ }
+@@ -325,6 +319,9 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id)
+ const char *parent_names[3];
+ int num_parents;
+
++ if (id == ISC_ISPCK && !isc->ispck_required)
++ return 0;
++
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents < 1 || num_parents > 3)
+ return -EINVAL;
+diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h
+index 19cc60dfcbe0f..2bfcb135ef13b 100644
+--- a/drivers/media/platform/atmel/atmel-isc.h
++++ b/drivers/media/platform/atmel/atmel-isc.h
+@@ -178,6 +178,7 @@ struct isc_reg_offsets {
+ * @hclock: Hclock clock input (refer datasheet)
+ * @ispck: iscpck clock (refer datasheet)
+ * @isc_clks: ISC clocks
++ * @ispck_required: ISC requires ISP Clock initialization
+ * @dcfg: DMA master configuration, architecture dependent
+ *
+ * @dev: Registered device driver
+@@ -252,6 +253,7 @@ struct isc_device {
+ struct clk *hclock;
+ struct clk *ispck;
+ struct isc_clk isc_clks[2];
++ bool ispck_required;
+ u32 dcfg;
+
+ struct device *dev;
+diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
+index b66f1d174e9d7..e29a9193bac81 100644
+--- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c
++++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
+@@ -454,6 +454,9 @@ static int atmel_isc_probe(struct platform_device *pdev)
+ /* sama5d2-isc - 8 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+
++ /* sama5d2-isc : ISPCK is required and mandatory */
++ isc->ispck_required = true;
++
+ ret = isc_pipeline_init(isc);
+ if (ret)
+ return ret;
+@@ -476,22 +479,6 @@ static int atmel_isc_probe(struct platform_device *pdev)
+ dev_err(dev, "failed to init isc clock: %d\n", ret);
+ goto unprepare_hclk;
+ }
+-
+- isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
+-
+- ret = clk_prepare_enable(isc->ispck);
+- if (ret) {
+- dev_err(dev, "failed to enable ispck: %d\n", ret);
+- goto unprepare_hclk;
+- }
+-
+- /* ispck should be greater or equal to hclock */
+- ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
+- if (ret) {
+- dev_err(dev, "failed to set ispck rate: %d\n", ret);
+- goto unprepare_clk;
+- }
+-
+ ret = v4l2_device_register(dev, &isc->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "unable to register v4l2 device.\n");
+@@ -545,19 +532,35 @@ static int atmel_isc_probe(struct platform_device *pdev)
+ pm_runtime_enable(dev);
+ pm_request_idle(dev);
+
++ isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
++
++ ret = clk_prepare_enable(isc->ispck);
++ if (ret) {
++ dev_err(dev, "failed to enable ispck: %d\n", ret);
++ goto cleanup_subdev;
++ }
++
++ /* ispck should be greater or equal to hclock */
++ ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
++ if (ret) {
++ dev_err(dev, "failed to set ispck rate: %d\n", ret);
++ goto unprepare_clk;
++ }
++
+ regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+ dev_info(dev, "Microchip ISC version %x\n", ver);
+
+ return 0;
+
++unprepare_clk:
++ clk_disable_unprepare(isc->ispck);
++
+ cleanup_subdev:
+ isc_subdev_cleanup(isc);
+
+ unregister_v4l2_device:
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+-unprepare_clk:
+- clk_disable_unprepare(isc->ispck);
+ unprepare_hclk:
+ clk_disable_unprepare(isc->hclock);
+
+diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
+index f2785131ff569..9c05acafd0724 100644
+--- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c
++++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
+@@ -447,6 +447,9 @@ static int microchip_xisc_probe(struct platform_device *pdev)
+ /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
+
++ /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
++ isc->ispck_required = false;
++
+ ret = isc_pipeline_init(isc);
+ if (ret)
+ return ret;
+@@ -470,25 +473,10 @@ static int microchip_xisc_probe(struct platform_device *pdev)
+ goto unprepare_hclk;
+ }
+
+- isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
+-
+- ret = clk_prepare_enable(isc->ispck);
+- if (ret) {
+- dev_err(dev, "failed to enable ispck: %d\n", ret);
+- goto unprepare_hclk;
+- }
+-
+- /* ispck should be greater or equal to hclock */
+- ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
+- if (ret) {
+- dev_err(dev, "failed to set ispck rate: %d\n", ret);
+- goto unprepare_clk;
+- }
+-
+ ret = v4l2_device_register(dev, &isc->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "unable to register v4l2 device.\n");
+- goto unprepare_clk;
++ goto unprepare_hclk;
+ }
+
+ ret = xisc_parse_dt(dev, isc);
+@@ -549,8 +537,6 @@ cleanup_subdev:
+ unregister_v4l2_device:
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+-unprepare_clk:
+- clk_disable_unprepare(isc->ispck);
+ unprepare_hclk:
+ clk_disable_unprepare(isc->hclock);
+
+diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
+index 755138063ee61..fc905ea78b175 100644
+--- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c
++++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
+@@ -575,6 +575,10 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
+
+ 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 (dec_ret & SLOT_STATUS_ENC_CONFIG_ERR) {
+@@ -2088,6 +2092,8 @@ err_m2m:
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+ err_register:
++ mxc_jpeg_detach_pm_domains(jpeg);
++
+ err_irq:
+ return ret;
+ }
+diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platform/meson/ge2d/ge2d.c
+index a1393fefa8aea..9b1e973e78da3 100644
+--- a/drivers/media/platform/meson/ge2d/ge2d.c
++++ b/drivers/media/platform/meson/ge2d/ge2d.c
+@@ -779,11 +779,7 @@ static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl)
+ * If the rotation parameter changes the OUTPUT frames
+ * parameters, take them in account
+ */
+- if (fmt.width != ctx->out.pix_fmt.width ||
+- fmt.height != ctx->out.pix_fmt.width ||
+- fmt.bytesperline > ctx->out.pix_fmt.bytesperline ||
+- fmt.sizeimage > ctx->out.pix_fmt.sizeimage)
+- ctx->out.pix_fmt = fmt;
++ ctx->out.pix_fmt = fmt;
+
+ break;
+ }
+diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+index 416f356af363d..d97a6765693f1 100644
+--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
++++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+@@ -793,7 +793,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+ {
+ struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+ struct venc_enc_param param;
+- int ret;
++ int ret, pm_ret;
+ int i;
+
+ /* Once state turn into MTK_STATE_ABORT, we need stop_streaming
+@@ -845,9 +845,9 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+ return 0;
+
+ err_set_param:
+- ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
+- if (ret < 0)
+- mtk_v4l2_err("pm_runtime_put fail %d", ret);
++ pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
++ if (pm_ret < 0)
++ mtk_v4l2_err("pm_runtime_put fail %d", pm_ret);
+
+ err_start_stream:
+ for (i = 0; i < q->num_buffers; ++i) {
+diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
+index ec290dde59cfd..7f1647da0ade0 100644
+--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
++++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
+@@ -848,7 +848,8 @@ static int mtk_vpu_probe(struct platform_device *pdev)
+ 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);
+@@ -942,6 +943,8 @@ disable_vpu_clk:
+ vpu_clock_disable(vpu);
+ workqueue_destroy:
+ destroy_workqueue(vpu->wdt.wq);
++clk_unprepare:
++ clk_unprepare(vpu->clk);
+
+ return ret;
+ }
+diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
+index 3e2345eb47f7c..e031fd17f4e75 100644
+--- a/drivers/media/platform/qcom/venus/pm_helpers.c
++++ b/drivers/media/platform/qcom/venus/pm_helpers.c
+@@ -1085,12 +1085,16 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
+ if (inst->state != INST_START)
+ return 0;
+
+- if (inst->session_type == VIDC_SESSION_TYPE_ENC)
++ if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
+ vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
+ inst->clk_data.low_power_freq :
+ inst->clk_data.vpp_freq;
+
+- vpp_freq = mbs_per_sec * vpp_freq_per_mb;
++ vpp_freq = mbs_per_sec * vpp_freq_per_mb;
++ } else {
++ vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
++ }
++
+ /* 21 / 20 is overhead factor */
+ vpp_freq += vpp_freq / 20;
+ vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
+diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
+index e28eff0396888..ba4a380016cc4 100644
+--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
++++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
+@@ -553,6 +553,8 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
+
+ /* 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
+diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
+index f5f722ab1d4e8..520d044bfb8d5 100644
+--- a/drivers/media/platform/rcar-vin/rcar-dma.c
++++ b/drivers/media/platform/rcar-vin/rcar-dma.c
+@@ -904,7 +904,8 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
+ vin->format.sizeimage / 2;
+ break;
+ }
+- } else if (vin->state != RUNNING || list_empty(&vin->buf_list)) {
++ } else if ((vin->state != STOPPED && vin->state != RUNNING) ||
++ list_empty(&vin->buf_list)) {
+ vin->buf_hw[slot].buffer = NULL;
+ vin->buf_hw[slot].type = FULL;
+ phys_addr = vin->scratch_phys;
+diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
+index eba2b9f040df0..f336a95432732 100644
+--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
++++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
+@@ -1283,11 +1283,15 @@ static int s5p_mfc_probe(struct platform_device *pdev)
+ 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);
+diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
+index d914ccef98317..6110718645a4f 100644
+--- a/drivers/media/platform/stm32/stm32-dcmi.c
++++ b/drivers/media/platform/stm32/stm32-dcmi.c
+@@ -128,6 +128,7 @@ struct stm32_dcmi {
+ int sequence;
+ struct list_head buffers;
+ struct dcmi_buf *active;
++ int irq;
+
+ struct v4l2_device v4l2_dev;
+ struct video_device *vdev;
+@@ -1759,6 +1760,14 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
+ 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;
+ }
+
+@@ -1914,6 +1923,8 @@ static int dcmi_probe(struct platform_device *pdev)
+ 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");
+@@ -1926,14 +1937,6 @@ static int dcmi_probe(struct platform_device *pdev)
+ 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)
+diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+index 07b2161392d21..5ba3e29f794fd 100644
+--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
++++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+@@ -467,7 +467,7 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
+ static int sun6i_video_open(struct file *file)
+ {
+ struct sun6i_video *video = video_drvdata(file);
+- int ret;
++ int ret = 0;
+
+ if (mutex_lock_interruptible(&video->lock))
+ return -ERESTARTSYS;
+@@ -481,10 +481,8 @@ static int sun6i_video_open(struct file *file)
+ goto fh_release;
+
+ /* check if already powered */
+- if (!v4l2_fh_is_singular_file(file)) {
+- ret = -EBUSY;
++ if (!v4l2_fh_is_singular_file(file))
+ goto unlock;
+- }
+
+ ret = sun6i_csi_set_power(video->csi, true);
+ if (ret < 0)
+diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
+index 1123768731676..484046471c03f 100644
+--- a/drivers/media/radio/radio-wl1273.c
++++ b/drivers/media/radio/radio-wl1273.c
+@@ -1279,7 +1279,7 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
+
+ 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));
+diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
+index f491420d7b538..a972c0705ac79 100644
+--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
++++ b/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"
+
+diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
+index fedff68d8c496..3f8634a465730 100644
+--- a/drivers/media/radio/si470x/radio-si470x-usb.c
++++ b/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"
+
+diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
+index 48d52baec1a1c..1aa7989e756cc 100644
+--- a/drivers/media/rc/ir_toy.c
++++ b/drivers/media/rc/ir_toy.c
+@@ -310,7 +310,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
+ buf[i] = cpu_to_be16(v);
+ }
+
+- buf[count] = 0xffff;
++ buf[count] = cpu_to_be16(0xffff);
+
+ irtoy->tx_buf = buf;
+ irtoy->tx_len = size;
+diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
+index 5bc23e8c6d91d..4f77d4ebacdc5 100644
+--- a/drivers/media/rc/ite-cir.c
++++ b/drivers/media/rc/ite-cir.c
+@@ -242,7 +242,7 @@ static irqreturn_t ite_cir_isr(int irq, void *data)
+ }
+
+ /* check for the receive interrupt */
+- if (iflags & ITE_IRQ_RX_FIFO) {
++ if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) {
+ /* read the FIFO bytes */
+ rx_bytes = dev->params->get_rx_bytes(dev, rx_buf,
+ ITE_RX_FIFO_LEN);
+diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
+index e03dd1f0144f0..137a71954aabf 100644
+--- a/drivers/media/rc/mceusb.c
++++ b/drivers/media/rc/mceusb.c
+@@ -1386,6 +1386,7 @@ static void mceusb_dev_recv(struct urb *urb)
+ case -ECONNRESET:
+ case -ENOENT:
+ case -EILSEQ:
++ case -EPROTO:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
+index b91a1e845b972..506f52c1af101 100644
+--- a/drivers/media/spi/cxd2880-spi.c
++++ b/drivers/media/spi/cxd2880-spi.c
+@@ -618,7 +618,7 @@ fail_frontend:
+ fail_attach:
+ dvb_unregister_adapter(&dvb_spi->adapter);
+ fail_adapter:
+- if (!dvb_spi->vcc_supply)
++ if (dvb_spi->vcc_supply)
+ regulator_disable(dvb_spi->vcc_supply);
+ fail_regulator:
+ kfree(dvb_spi);
+diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+index 75617709c8ce2..82620613d56b8 100644
+--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
++++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+@@ -564,6 +564,10 @@ static int vidtv_bridge_remove(struct platform_device *pdev)
+
+ static void vidtv_bridge_dev_release(struct device *dev)
+ {
++ struct vidtv_dvb *dvb;
++
++ dvb = dev_get_drvdata(dev);
++ kfree(dvb);
+ }
+
+ static struct platform_device vidtv_bridge_dev = {
+diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+index 7865fa0a82957..cd5861a30b6f8 100644
+--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
++++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+@@ -931,8 +931,6 @@ static int mxl111sf_init(struct dvb_usb_device *d)
+ .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 @@ static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
+ 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 @@ static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
+ .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 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc = {
+ .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 @@ static struct dvb_usb_device_properties mxl111sf_props_mh = {
+ .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 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
+ .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 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury = {
+ .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 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = {
+ .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,
+diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
+index 1c39b61cde29b..86788771175b7 100644
+--- a/drivers/media/usb/dvb-usb/az6027.c
++++ b/drivers/media/usb/dvb-usb/az6027.c
+@@ -391,6 +391,7 @@ static struct rc_map_table rc_map_az6027_table[] = {
+ /* 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;
+ }
+
+diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
+index 02b51d1a1b67c..aff60c10cb0b2 100644
+--- a/drivers/media/usb/dvb-usb/dibusb-common.c
++++ b/drivers/media/usb/dvb-usb/dibusb-common.c
+@@ -223,7 +223,7 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
+ u8 *buf;
+ int rc;
+
+- buf = kmalloc(2, GFP_KERNEL);
++ buf = kzalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
+index c1e0dccb74088..948e22e29b42a 100644
+--- a/drivers/media/usb/em28xx/em28xx-cards.c
++++ b/drivers/media/usb/em28xx/em28xx-cards.c
+@@ -4139,8 +4139,11 @@ static void em28xx_usb_disconnect(struct usb_interface *intf)
+
+ em28xx_close_extension(dev);
+
+- if (dev->dev_next)
++ if (dev->dev_next) {
++ em28xx_close_extension(dev->dev_next);
+ em28xx_release_resources(dev->dev_next);
++ }
++
+ em28xx_release_resources(dev);
+
+ if (dev->dev_next) {
+diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
+index 584fa400cd7d8..acc0bf7dbe2b1 100644
+--- a/drivers/media/usb/em28xx/em28xx-core.c
++++ b/drivers/media/usb/em28xx/em28xx-core.c
+@@ -1154,8 +1154,9 @@ int em28xx_suspend_extension(struct em28xx *dev)
+ 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);
+ }
+diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
+index 3f650ede0c3dc..e293f6f3d1bc9 100644
+--- a/drivers/media/usb/tm6000/tm6000-video.c
++++ b/drivers/media/usb/tm6000/tm6000-video.c
+@@ -852,8 +852,7 @@ static int vidioc_querycap(struct file *file, void *priv,
+ 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;
+diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
+index bfda46a36dc50..38822cedd93a9 100644
+--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
++++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
+@@ -327,7 +327,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
+ result = mutex_lock_interruptible(&dec->usb_mutex);
+ if (result) {
+ printk("%s: Failed to lock usb mutex.\n", __func__);
+- goto err;
++ goto err_free;
+ }
+
+ b[0] = 0xaa;
+@@ -349,7 +349,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
+ if (result) {
+ printk("%s: command bulk message failed: error %d\n",
+ __func__, result);
+- goto err;
++ goto err_mutex_unlock;
+ }
+
+ result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
+@@ -358,7 +358,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
+ if (result) {
+ printk("%s: result bulk message failed: error %d\n",
+ __func__, result);
+- goto err;
++ goto err_mutex_unlock;
+ } else {
+ if (debug) {
+ printk(KERN_DEBUG "%s: result: %*ph\n",
+@@ -371,9 +371,9 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
+ memcpy(cmd_result, &b[4], b[3]);
+ }
+
+-err:
++err_mutex_unlock:
+ mutex_unlock(&dec->usb_mutex);
+-
++err_free:
+ kfree(b);
+ return result;
+ }
+diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
+index 9a791d8ef200d..c4bc67024534a 100644
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -2194,6 +2194,7 @@ int uvc_register_video_device(struct uvc_device *dev,
+ const struct v4l2_file_operations *fops,
+ const struct v4l2_ioctl_ops *ioctl_ops)
+ {
++ const char *name;
+ int ret;
+
+ /* Initialize the video buffers queue. */
+@@ -2222,16 +2223,20 @@ int uvc_register_video_device(struct uvc_device *dev,
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ default:
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
++ name = "Video Capture";
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
++ name = "Video Output";
+ break;
+ case V4L2_BUF_TYPE_META_CAPTURE:
+ vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
++ name = "Metadata";
+ break;
+ }
+
+- strscpy(vdev->name, dev->name, sizeof(vdev->name));
++ snprintf(vdev->name, sizeof(vdev->name), "%s %u", name,
++ stream->header.bTerminalLink);
+
+ /*
+ * Set the driver data before calling video_register_device, otherwise
+diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
+index 6acb8013de08b..c9d208677bcd8 100644
+--- a/drivers/media/usb/uvc/uvc_v4l2.c
++++ b/drivers/media/usb/uvc/uvc_v4l2.c
+@@ -472,10 +472,13 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
+ 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;
+ }
+diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
+index e16464606b140..9f37eaf28ce7e 100644
+--- a/drivers/media/usb/uvc/uvc_video.c
++++ b/drivers/media/usb/uvc/uvc_video.c
+@@ -115,6 +115,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
+ 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 */
+diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+index 47aff3b197426..80aaf07b16f28 100644
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -744,10 +744,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
+ /*
+ * x86 is the only compat architecture with different struct alignment
+ * between 32-bit and 64-bit tasks.
+- *
+- * On all other architectures, v4l2_event32 and v4l2_event32_time32 are
+- * the same as v4l2_event and v4l2_event_time32, so we can use the native
+- * handlers, converting v4l2_event to v4l2_event_time32 if necessary.
+ */
+ struct v4l2_event32 {
+ __u32 type;
+@@ -765,21 +761,6 @@ struct v4l2_event32 {
+ __u32 reserved[8];
+ };
+
+-#ifdef CONFIG_COMPAT_32BIT_TIME
+-struct v4l2_event32_time32 {
+- __u32 type;
+- union {
+- compat_s64 value64;
+- __u8 data[64];
+- } u;
+- __u32 pending;
+- __u32 sequence;
+- struct old_timespec32 timestamp;
+- __u32 id;
+- __u32 reserved[8];
+-};
+-#endif
+-
+ static int put_v4l2_event32(struct v4l2_event *p64,
+ struct v4l2_event32 __user *p32)
+ {
+@@ -795,7 +776,22 @@ static int put_v4l2_event32(struct v4l2_event *p64,
+ return 0;
+ }
+
++#endif
++
+ #ifdef CONFIG_COMPAT_32BIT_TIME
++struct v4l2_event32_time32 {
++ __u32 type;
++ union {
++ compat_s64 value64;
++ __u8 data[64];
++ } u;
++ __u32 pending;
++ __u32 sequence;
++ struct old_timespec32 timestamp;
++ __u32 id;
++ __u32 reserved[8];
++};
++
+ static int put_v4l2_event32_time32(struct v4l2_event *p64,
+ struct v4l2_event32_time32 __user *p32)
+ {
+@@ -811,7 +807,6 @@ static int put_v4l2_event32_time32(struct v4l2_event *p64,
+ return 0;
+ }
+ #endif
+-#endif
+
+ struct v4l2_edid32 {
+ __u32 pad;
+@@ -873,9 +868,7 @@ static int put_v4l2_edid32(struct v4l2_edid *p64,
+ #define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32)
+ #define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32)
+ #define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32)
+-#ifdef CONFIG_X86_64
+ #define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32)
+-#endif
+ #define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32)
+ #endif
+
+@@ -929,10 +922,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
+ #ifdef CONFIG_X86_64
+ case VIDIOC_DQEVENT32:
+ return VIDIOC_DQEVENT;
++#endif
+ #ifdef CONFIG_COMPAT_32BIT_TIME
+ case VIDIOC_DQEVENT32_TIME32:
+ return VIDIOC_DQEVENT;
+-#endif
+ #endif
+ }
+ return cmd;
+@@ -1025,10 +1018,10 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
+ #ifdef CONFIG_X86_64
+ case VIDIOC_DQEVENT32:
+ return put_v4l2_event32(parg, arg);
++#endif
+ #ifdef CONFIG_COMPAT_32BIT_TIME
+ case VIDIOC_DQEVENT32_TIME32:
+ return put_v4l2_event32_time32(parg, arg);
+-#endif
+ #endif
+ }
+ return 0;
+diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
+index 05d5db3d85e58..f4f67b385d00a 100644
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -869,7 +869,7 @@ static void v4l_print_default(const void *arg, bool write_only)
+ 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;
+
+@@ -878,23 +878,41 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+ 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)
+@@ -2187,7 +2205,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
+ 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)
+@@ -2206,6 +2224,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
+ test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control ctrl;
++ int ret;
+
+ if (vfh && vfh->ctrl_handler)
+ return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
+@@ -2221,9 +2240,11 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
+ ctrls.controls = &ctrl;
+ ctrl.id = p->id;
+ ctrl.value = p->value;
+- if (check_ext_ctrls(&ctrls, 1))
+- return ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
+- return -EINVAL;
++ if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL))
++ return -EINVAL;
++ ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
++ p->value = ctrl.value;
++ return ret;
+ }
+
+ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+@@ -2243,8 +2264,8 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+ 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,
+@@ -2264,8 +2285,8 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+ 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,
+@@ -2285,8 +2306,8 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+ 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;
+ }
+
+ /*
+diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
+index d062c2f8250f4..75a8c38df9394 100644
+--- a/drivers/memory/fsl_ifc.c
++++ b/drivers/memory/fsl_ifc.c
+@@ -263,7 +263,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
+
+ 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);
+
+@@ -272,7 +272,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
+ 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) {
+@@ -281,17 +281,16 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
+ 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);
+diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
+index 45eed659b0c6d..77a011d5ff8c1 100644
+--- a/drivers/memory/renesas-rpc-if.c
++++ b/drivers/memory/renesas-rpc-if.c
+@@ -160,10 +160,62 @@ static const struct regmap_access_table rpcif_volatile_table = {
+ .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
+ };
+
++
++/*
++ * Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed
++ * with proper width. Requires SMENR_SPIDE to be correctly set before!
++ */
++static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
++{
++ struct rpcif *rpc = context;
++
++ if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
++ u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
++
++ if (spide == 0x8) {
++ *val = readb(rpc->base + reg);
++ return 0;
++ } else if (spide == 0xC) {
++ *val = readw(rpc->base + reg);
++ return 0;
++ } else if (spide != 0xF) {
++ return -EILSEQ;
++ }
++ }
++
++ *val = readl(rpc->base + reg);
++ return 0;
++
++}
++
++static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
++{
++ struct rpcif *rpc = context;
++
++ if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
++ u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
++
++ if (spide == 0x8) {
++ writeb(val, rpc->base + reg);
++ return 0;
++ } else if (spide == 0xC) {
++ writew(val, rpc->base + reg);
++ return 0;
++ } else if (spide != 0xF) {
++ return -EILSEQ;
++ }
++ }
++
++ writel(val, rpc->base + reg);
++ return 0;
++}
++
+ static const struct regmap_config rpcif_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
++ .reg_read = rpcif_reg_read,
++ .reg_write = rpcif_reg_write,
+ .fast_io = true,
+ .max_register = RPCIF_PHYINT,
+ .volatile_table = &rpcif_volatile_table,
+@@ -173,17 +225,15 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+- void __iomem *base;
+
+ rpc->dev = dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+- base = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(base))
+- return PTR_ERR(base);
++ rpc->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->base))
++ return PTR_ERR(rpc->base);
+
+- rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+- &rpcif_regmap_config);
++ rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
+ if (IS_ERR(rpc->regmap)) {
+ dev_err(&pdev->dev,
+ "failed to init regmap for rpcif, error %ld\n",
+@@ -354,20 +404,16 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
+ nbytes = op->data.nbytes;
+ rpc->xferlen = nbytes;
+
+- rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) |
+- RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
++ rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
+ }
+ }
+ EXPORT_SYMBOL(rpcif_prepare);
+
+ int rpcif_manual_xfer(struct rpcif *rpc)
+ {
+- u32 smenr, smcr, pos = 0, max = 4;
++ u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
+ int ret = 0;
+
+- if (rpc->bus_size == 2)
+- max = 8;
+-
+ pm_runtime_get_sync(rpc->dev);
+
+ regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
+@@ -378,37 +424,36 @@ int rpcif_manual_xfer(struct rpcif *rpc)
+ regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option);
+ regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
+ regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
++ regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr);
+ smenr = rpc->enable;
+
+ switch (rpc->dir) {
+ case RPCIF_DATA_OUT:
+ while (pos < rpc->xferlen) {
+- u32 nbytes = rpc->xferlen - pos;
+- u32 data[2];
++ u32 bytes_left = rpc->xferlen - pos;
++ u32 nbytes, data[2];
+
+ smcr = rpc->smcr | RPCIF_SMCR_SPIE;
+- if (nbytes > max) {
+- nbytes = max;
++
++ /* nbytes may only be 1, 2, 4, or 8 */
++ nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
++ if (bytes_left > nbytes)
+ smcr |= RPCIF_SMCR_SSLKP;
+- }
++
++ smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
++ regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
+
+ memcpy(data, rpc->buffer + pos, nbytes);
+- if (nbytes > 4) {
++ if (nbytes == 8) {
+ regmap_write(rpc->regmap, RPCIF_SMWDR1,
+ data[0]);
+ regmap_write(rpc->regmap, RPCIF_SMWDR0,
+ data[1]);
+- } else if (nbytes > 2) {
++ } else {
+ regmap_write(rpc->regmap, RPCIF_SMWDR0,
+ data[0]);
+- } else {
+- regmap_write(rpc->regmap, RPCIF_SMWDR0,
+- data[0] << 16);
+ }
+
+- regmap_write(rpc->regmap, RPCIF_SMADR,
+- rpc->smadr + pos);
+- regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
+ regmap_write(rpc->regmap, RPCIF_SMCR, smcr);
+ ret = wait_msg_xfer_end(rpc);
+ if (ret)
+@@ -448,14 +493,16 @@ int rpcif_manual_xfer(struct rpcif *rpc)
+ break;
+ }
+ while (pos < rpc->xferlen) {
+- u32 nbytes = rpc->xferlen - pos;
+- u32 data[2];
++ u32 bytes_left = rpc->xferlen - pos;
++ u32 nbytes, data[2];
+
+- if (nbytes > max)
+- nbytes = max;
++ /* nbytes may only be 1, 2, 4, or 8 */
++ nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
+
+ regmap_write(rpc->regmap, RPCIF_SMADR,
+ rpc->smadr + pos);
++ smenr &= ~RPCIF_SMENR_SPIDE(0xF);
++ smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
+ regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
+ regmap_write(rpc->regmap, RPCIF_SMCR,
+ rpc->smcr | RPCIF_SMCR_SPIE);
+@@ -463,18 +510,14 @@ int rpcif_manual_xfer(struct rpcif *rpc)
+ if (ret)
+ goto err_out;
+
+- if (nbytes > 4) {
++ if (nbytes == 8) {
+ regmap_read(rpc->regmap, RPCIF_SMRDR1,
+ &data[0]);
+ regmap_read(rpc->regmap, RPCIF_SMRDR0,
+ &data[1]);
+- } else if (nbytes > 2) {
+- regmap_read(rpc->regmap, RPCIF_SMRDR0,
+- &data[0]);
+- } else {
++ } else {
+ regmap_read(rpc->regmap, RPCIF_SMRDR0,
+ &data[0]);
+- data[0] >>= 16;
+ }
+ memcpy(rpc->buffer + pos, data, nbytes);
+
+diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
+index c3462dbc8c22b..6fc90f2160e93 100644
+--- a/drivers/memory/tegra/tegra20-emc.c
++++ b/drivers/memory/tegra/tegra20-emc.c
+@@ -1117,4 +1117,5 @@ module_platform_driver(tegra_emc_driver);
+
+ MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
+ MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver");
++MODULE_SOFTDEP("pre: governor_simpleondemand");
+ MODULE_LICENSE("GPL v2");
+diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
+index acf36676e388d..487e4cc2951e0 100644
+--- a/drivers/memstick/core/ms_block.c
++++ b/drivers/memstick/core/ms_block.c
+@@ -1736,7 +1736,7 @@ static int msb_init_card(struct memstick_dev *card)
+ 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;
+diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
+index f9a93b0565e15..435d4c058b20e 100644
+--- a/drivers/memstick/host/jmb38x_ms.c
++++ b/drivers/memstick/host/jmb38x_ms.c
+@@ -882,7 +882,7 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
+
+ iounmap(host->addr);
+ err_out_free:
+- kfree(msh);
++ memstick_free_host(msh);
+ return NULL;
+ }
+
+diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
+index e79a0218c492e..1d35d147552d4 100644
+--- a/drivers/memstick/host/r592.c
++++ b/drivers/memstick/host/r592.c
+@@ -838,15 +838,15 @@ static void r592_remove(struct pci_dev *pdev)
+ }
+ 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
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index ca0edab91aeb6..d2f3452455389 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -1194,6 +1194,7 @@ config MFD_SI476X_CORE
+ config MFD_SIMPLE_MFD_I2C
+ tristate
+ depends on I2C
++ select MFD_CORE
+ select REGMAP_I2C
+ help
+ This driver creates a single register map with the intention for it
+diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c
+index 20cb294c75122..5d3715a28b28e 100644
+--- a/drivers/mfd/altera-sysmgr.c
++++ b/drivers/mfd/altera-sysmgr.c
+@@ -153,7 +153,7 @@ static int sysmgr_probe(struct platform_device *pdev)
+ if (!base)
+ return -ENOMEM;
+
+- sysmgr_config.max_register = resource_size(res) - 3;
++ sysmgr_config.max_register = resource_size(res) - 4;
+ regmap = devm_regmap_init_mmio(dev, base, &sysmgr_config);
+ }
+
+diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c
+index 83e676a096dc1..852129ea07666 100644
+--- a/drivers/mfd/dln2.c
++++ b/drivers/mfd/dln2.c
+@@ -50,6 +50,7 @@ enum dln2_handle {
+ DLN2_HANDLE_GPIO,
+ DLN2_HANDLE_I2C,
+ DLN2_HANDLE_SPI,
++ DLN2_HANDLE_ADC,
+ DLN2_HANDLES
+ };
+
+@@ -653,6 +654,7 @@ enum {
+ DLN2_ACPI_MATCH_GPIO = 0,
+ DLN2_ACPI_MATCH_I2C = 1,
+ DLN2_ACPI_MATCH_SPI = 2,
++ DLN2_ACPI_MATCH_ADC = 3,
+ };
+
+ static struct dln2_platform_data dln2_pdata_gpio = {
+@@ -683,6 +685,16 @@ static struct mfd_cell_acpi_match dln2_acpi_match_spi = {
+ .adr = DLN2_ACPI_MATCH_SPI,
+ };
+
++/* Only one ADC port supported */
++static struct dln2_platform_data dln2_pdata_adc = {
++ .handle = DLN2_HANDLE_ADC,
++ .port = 0,
++};
++
++static struct mfd_cell_acpi_match dln2_acpi_match_adc = {
++ .adr = DLN2_ACPI_MATCH_ADC,
++};
++
+ static const struct mfd_cell dln2_devs[] = {
+ {
+ .name = "dln2-gpio",
+@@ -702,6 +714,12 @@ static const struct mfd_cell dln2_devs[] = {
+ .platform_data = &dln2_pdata_spi,
+ .pdata_size = sizeof(struct dln2_platform_data),
+ },
++ {
++ .name = "dln2-adc",
++ .acpi_match = &dln2_acpi_match_adc,
++ .platform_data = &dln2_pdata_adc,
++ .pdata_size = sizeof(struct dln2_platform_data),
++ },
+ };
+
+ static void dln2_stop(struct dln2_dev *dln2)
+diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
+index 79f5c6a18815a..684a011a63968 100644
+--- a/drivers/mfd/mfd-core.c
++++ b/drivers/mfd/mfd-core.c
+@@ -198,6 +198,7 @@ static int mfd_add_device(struct device *parent, int id,
+ if (of_device_is_compatible(np, cell->of_compatible)) {
+ /* Ignore 'disabled' devices error free */
+ if (!of_device_is_available(np)) {
++ of_node_put(np);
+ ret = 0;
+ goto fail_alias;
+ }
+@@ -205,6 +206,7 @@ static int mfd_add_device(struct device *parent, int id,
+ ret = mfd_match_of_node_to_dev(pdev, np, cell);
+ if (ret == -EAGAIN)
+ continue;
++ of_node_put(np);
+ if (ret)
+ goto fail_alias;
+
+diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
+index 6fb206da27298..265464b5d7cc5 100644
+--- a/drivers/mfd/motorola-cpcap.c
++++ b/drivers/mfd/motorola-cpcap.c
+@@ -202,6 +202,13 @@ static const struct of_device_id cpcap_of_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, cpcap_of_match);
+
++static const struct spi_device_id cpcap_spi_ids[] = {
++ { .name = "cpcap", },
++ { .name = "6556002", },
++ {},
++};
++MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
++
+ static const struct regmap_config cpcap_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 4,
+@@ -342,6 +349,7 @@ static struct spi_driver cpcap_driver = {
+ .pm = &cpcap_pm,
+ },
+ .probe = cpcap_probe,
++ .id_table = cpcap_spi_ids,
+ };
+ module_spi_driver(cpcap_driver);
+
+diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c
+index 6b7956604a0f0..9890882db1ed3 100644
+--- a/drivers/mfd/sprd-sc27xx-spi.c
++++ b/drivers/mfd/sprd-sc27xx-spi.c
+@@ -236,6 +236,12 @@ static const struct of_device_id sprd_pmic_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, sprd_pmic_match);
+
++static const struct spi_device_id sprd_pmic_spi_ids[] = {
++ { .name = "sc2731", .driver_data = (unsigned long)&sc2731_data },
++ {},
++};
++MODULE_DEVICE_TABLE(spi, sprd_pmic_spi_ids);
++
+ static struct spi_driver sprd_pmic_driver = {
+ .driver = {
+ .name = "sc27xx-pmic",
+@@ -243,6 +249,7 @@ static struct spi_driver sprd_pmic_driver = {
+ .pm = &sprd_pmic_pm_ops,
+ },
+ .probe = sprd_pmic_probe,
++ .id_table = sprd_pmic_spi_ids,
+ };
+
+ static int __init sprd_pmic_init(void)
+diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
+index baf83594a01d3..5121edb0d9eff 100644
+--- a/drivers/misc/cardreader/rtsx_pcr.c
++++ b/drivers/misc/cardreader/rtsx_pcr.c
+@@ -1803,8 +1803,6 @@ static int rtsx_pci_runtime_suspend(struct device *device)
+ mutex_lock(&pcr->pcr_mutex);
+ rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+
+- free_irq(pcr->irq, (void *)pcr);
+-
+ mutex_unlock(&pcr->pcr_mutex);
+
+ pcr->is_runtime_suspended = true;
+@@ -1825,8 +1823,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
+ mutex_lock(&pcr->pcr_mutex);
+
+ rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
+- rtsx_pci_acquire_irq(pcr);
+- synchronize_irq(pcr->irq);
+
+ if (pcr->ops->fetch_vendor_settings)
+ pcr->ops->fetch_vendor_settings(pcr);
+diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
+index 632325474233a..b38978a3b3ffa 100644
+--- a/drivers/misc/eeprom/at25.c
++++ b/drivers/misc/eeprom/at25.c
+@@ -376,7 +376,6 @@ MODULE_DEVICE_TABLE(spi, at25_spi_ids);
+ static int at25_probe(struct spi_device *spi)
+ {
+ struct at25_data *at25 = NULL;
+- struct spi_eeprom chip;
+ int err;
+ int sr;
+ u8 id[FM25_ID_LEN];
+@@ -389,15 +388,18 @@ static int at25_probe(struct spi_device *spi)
+ if (match && !strcmp(match->compatible, "cypress,fm25"))
+ is_fram = 1;
+
++ at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
++ if (!at25)
++ return -ENOMEM;
++
+ /* Chip description */
+- if (!spi->dev.platform_data) {
+- if (!is_fram) {
+- err = at25_fw_to_chip(&spi->dev, &chip);
+- if (err)
+- return err;
+- }
+- } else
+- chip = *(struct spi_eeprom *)spi->dev.platform_data;
++ if (spi->dev.platform_data) {
++ memcpy(&at25->chip, spi->dev.platform_data, sizeof(at25->chip));
++ } else if (!is_fram) {
++ err = at25_fw_to_chip(&spi->dev, &at25->chip);
++ if (err)
++ return err;
++ }
+
+ /* Ping the chip ... the status register is pretty portable,
+ * unlike probing manufacturer IDs. We do expect that system
+@@ -409,12 +411,7 @@ static int at25_probe(struct spi_device *spi)
+ return -ENXIO;
+ }
+
+- at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
+- if (!at25)
+- return -ENOMEM;
+-
+ mutex_init(&at25->lock);
+- at25->chip = chip;
+ at25->spi = spi;
+ spi_set_drvdata(spi, at25);
+
+@@ -431,7 +428,7 @@ static int at25_probe(struct spi_device *spi)
+ dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]);
+ return -ENODEV;
+ }
+- chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
++ at25->chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
+
+ if (at25->chip.byte_len > 64 * 1024)
+ at25->chip.flags |= EE_ADDR3;
+@@ -464,7 +461,7 @@ static int at25_probe(struct spi_device *spi)
+ at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
+ at25->nvmem_config.name = dev_name(&spi->dev);
+ at25->nvmem_config.dev = &spi->dev;
+- at25->nvmem_config.read_only = chip.flags & EE_READONLY;
++ at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY;
+ at25->nvmem_config.root_only = true;
+ at25->nvmem_config.owner = THIS_MODULE;
+ at25->nvmem_config.compat = true;
+@@ -474,17 +471,18 @@ static int at25_probe(struct spi_device *spi)
+ at25->nvmem_config.priv = at25;
+ at25->nvmem_config.stride = 1;
+ at25->nvmem_config.word_size = 1;
+- at25->nvmem_config.size = chip.byte_len;
++ at25->nvmem_config.size = at25->chip.byte_len;
+
+ at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
+ if (IS_ERR(at25->nvmem))
+ return PTR_ERR(at25->nvmem);
+
+ dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
+- (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
+- (chip.byte_len < 1024) ? "Byte" : "KByte",
++ (at25->chip.byte_len < 1024) ?
++ at25->chip.byte_len : (at25->chip.byte_len / 1024),
++ (at25->chip.byte_len < 1024) ? "Byte" : "KByte",
+ at25->chip.name, is_fram ? "fram" : "eeprom",
+- (chip.flags & EE_READONLY) ? " (readonly)" : "",
++ (at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
+ at25->chip.page_size);
+ return 0;
+ }
+diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
+index ad6ced4546556..f3002653bd010 100644
+--- a/drivers/misc/fastrpc.c
++++ b/drivers/misc/fastrpc.c
+@@ -719,16 +719,18 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
+ 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);
+ }
+ }
+
+diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
+index 380f9aa56eb26..1e8f1bb3cad7c 100644
+--- a/drivers/mmc/host/dw_mmc.c
++++ b/drivers/mmc/host/dw_mmc.c
+@@ -2086,7 +2086,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
+ * 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;
+ }
+diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
+index f4c8e1a61f537..b431cdd27353b 100644
+--- a/drivers/mmc/host/mmc_spi.c
++++ b/drivers/mmc/host/mmc_spi.c
+@@ -1514,6 +1514,12 @@ static int mmc_spi_remove(struct spi_device *spi)
+ return 0;
+ }
+
++static const struct spi_device_id mmc_spi_dev_ids[] = {
++ { "mmc-spi-slot"},
++ { },
++};
++MODULE_DEVICE_TABLE(spi, mmc_spi_dev_ids);
++
+ static const struct of_device_id mmc_spi_of_match_table[] = {
+ { .compatible = "mmc-spi-slot", },
+ {},
+@@ -1525,6 +1531,7 @@ static struct spi_driver mmc_spi_driver = {
+ .name = "mmc_spi",
+ .of_match_table = mmc_spi_of_match_table,
+ },
++ .id_table = mmc_spi_dev_ids,
+ .probe = mmc_spi_probe,
+ .remove = mmc_spi_remove,
+ };
+diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
+index 6c9d38132f74c..16d1c7a43d331 100644
+--- a/drivers/mmc/host/moxart-mmc.c
++++ b/drivers/mmc/host/moxart-mmc.c
+@@ -566,37 +566,37 @@ static int moxart_probe(struct platform_device *pdev)
+ if (!mmc) {
+ dev_err(dev, "mmc_alloc_host failed\n");
+ ret = -ENOMEM;
+- goto out;
++ goto out_mmc;
+ }
+
+ ret = of_address_to_resource(node, 0, &res_mmc);
+ if (ret) {
+ dev_err(dev, "of_address_to_resource failed\n");
+- goto out;
++ goto out_mmc;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ dev_err(dev, "irq_of_parse_and_map failed\n");
+ ret = -EINVAL;
+- goto out;
++ goto out_mmc;
+ }
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+- goto out;
++ goto out_mmc;
+ }
+
+ reg_mmc = devm_ioremap_resource(dev, &res_mmc);
+ if (IS_ERR(reg_mmc)) {
+ ret = PTR_ERR(reg_mmc);
+- goto out;
++ goto out_mmc;
+ }
+
+ ret = mmc_of_parse(mmc);
+ if (ret)
+- goto out;
++ goto out_mmc;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+@@ -621,6 +621,14 @@ static int moxart_probe(struct platform_device *pdev)
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
++ if (!IS_ERR(host->dma_chan_tx)) {
++ dma_release_channel(host->dma_chan_tx);
++ host->dma_chan_tx = NULL;
++ }
++ if (!IS_ERR(host->dma_chan_rx)) {
++ dma_release_channel(host->dma_chan_rx);
++ host->dma_chan_rx = NULL;
++ }
+ dev_dbg(dev, "PIO mode transfer enabled\n");
+ host->have_dma = false;
+ } else {
+@@ -675,6 +683,11 @@ static int moxart_probe(struct platform_device *pdev)
+ return 0;
+
+ out:
++ if (!IS_ERR_OR_NULL(host->dma_chan_tx))
++ dma_release_channel(host->dma_chan_tx);
++ if (!IS_ERR_OR_NULL(host->dma_chan_rx))
++ dma_release_channel(host->dma_chan_rx);
++out_mmc:
+ if (mmc)
+ mmc_free_host(mmc);
+ return ret;
+@@ -687,9 +700,9 @@ static int moxart_remove(struct platform_device *pdev)
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+- if (!IS_ERR(host->dma_chan_tx))
++ if (!IS_ERR_OR_NULL(host->dma_chan_tx))
+ dma_release_channel(host->dma_chan_tx);
+- if (!IS_ERR(host->dma_chan_rx))
++ if (!IS_ERR_OR_NULL(host->dma_chan_rx))
+ dma_release_channel(host->dma_chan_rx);
+ mmc_remove_host(mmc);
+ mmc_free_host(mmc);
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index b06b4dcb7c782..9e6dab7e34242 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -8,6 +8,7 @@
+ #include <linux/clk.h>
+ #include <linux/delay.h>
+ #include <linux/dma-mapping.h>
++#include <linux/iopoll.h>
+ #include <linux/ioport.h>
+ #include <linux/irq.h>
+ #include <linux/of_address.h>
+@@ -2330,6 +2331,7 @@ static void msdc_cqe_enable(struct mmc_host *mmc)
+ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
+ {
+ struct msdc_host *host = mmc_priv(mmc);
++ unsigned int val = 0;
+
+ /* disable cmdq irq */
+ sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ);
+@@ -2339,6 +2341,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
+ if (recovery) {
+ sdr_set_field(host->base + MSDC_DMA_CTRL,
+ MSDC_DMA_CTRL_STOP, 1);
++ if (WARN_ON(readl_poll_timeout(host->base + MSDC_DMA_CFG, val,
++ !(val & MSDC_DMA_CFG_STS), 1, 3000)))
++ return;
+ msdc_reset_hw(host);
+ }
+ }
+diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
+index 947581de78601..8c3655d3be961 100644
+--- a/drivers/mmc/host/mxs-mmc.c
++++ b/drivers/mmc/host/mxs-mmc.c
+@@ -552,6 +552,11 @@ static const struct of_device_id mxs_mmc_dt_ids[] = {
+ };
+ 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)
+ {
+ struct device_node *np = pdev->dev.of_node;
+@@ -591,6 +596,11 @@ static int mxs_mmc_probe(struct platform_device *pdev)
+ "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);
+diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
+index a4407f391f66a..f5b2684ad8058 100644
+--- a/drivers/mmc/host/renesas_sdhi_core.c
++++ b/drivers/mmc/host/renesas_sdhi_core.c
+@@ -673,7 +673,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
+
+ /* Issue CMD19 twice for each tap */
+ for (i = 0; i < 2 * priv->tap_num; i++) {
+- int cmd_error;
++ int cmd_error = 0;
+
+ /* Set sampling clock position */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num);
+diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
+index e658f01742420..60f19369de845 100644
+--- a/drivers/mmc/host/sdhci-esdhc-imx.c
++++ b/drivers/mmc/host/sdhci-esdhc-imx.c
+@@ -300,7 +300,6 @@ 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,
+ };
+@@ -309,7 +308,6 @@ 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_CQHCI
+ | ESDHC_FLAG_STATE_LOST_IN_LPMODE,
+ };
+
+diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
+index 8f4d1f003f656..fd188b6d88f49 100644
+--- a/drivers/mmc/host/sdhci-omap.c
++++ b/drivers/mmc/host/sdhci-omap.c
+@@ -62,6 +62,8 @@
+ #define SDHCI_OMAP_IE 0x234
+ #define INT_CC_EN BIT(0)
+
++#define SDHCI_OMAP_ISE 0x238
++
+ #define SDHCI_OMAP_AC12 0x23c
+ #define AC12_V1V8_SIGEN BIT(19)
+ #define AC12_SCLK_SEL BIT(23)
+@@ -113,6 +115,8 @@ struct sdhci_omap_host {
+ u32 hctl;
+ u32 sysctl;
+ u32 capa;
++ u32 ie;
++ u32 ise;
+ };
+
+ static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
+@@ -682,7 +686,8 @@ static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode,
+ {
+ 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)
+@@ -1244,14 +1249,23 @@ static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host)
+ {
+ omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+ omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL);
++ omap_host->sysctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL);
+ omap_host->capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA);
++ omap_host->ie = sdhci_omap_readl(omap_host, SDHCI_OMAP_IE);
++ omap_host->ise = sdhci_omap_readl(omap_host, SDHCI_OMAP_ISE);
+ }
+
++/* Order matters here, HCTL must be restored in two phases */
+ static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host)
+ {
+- sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con);
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl);
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa);
++ sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl);
++
++ sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, omap_host->sysctl);
++ sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con);
++ sdhci_omap_writel(omap_host, SDHCI_OMAP_IE, omap_host->ie);
++ sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise);
+ }
+
+ static int __maybe_unused sdhci_omap_suspend(struct device *dev)
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
+index 2d80a04e11d87..7728f26adb19f 100644
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -771,7 +771,19 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
+ 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)
+@@ -3952,6 +3964,7 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
+ * descriptor for each segment, plus 1 for a nop end descriptor.
+ */
+ host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
++ host->max_adma = 65536;
+
+ host->max_timeout_count = 0xE;
+
+@@ -4617,10 +4630,12 @@ int sdhci_setup_host(struct sdhci_host *host)
+ * 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;
+ }
+diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
+index e8d04e42a5afd..6c689be3e48f6 100644
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -340,7 +340,8 @@ struct sdhci_adma2_64_desc {
+
+ /*
+ * 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
+
+@@ -543,6 +544,7 @@ struct sdhci_host {
+ 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 */
+diff --git a/drivers/most/most_usb.c b/drivers/most/most_usb.c
+index 2640c5b326a49..acabb7715b423 100644
+--- a/drivers/most/most_usb.c
++++ b/drivers/most/most_usb.c
+@@ -149,7 +149,8 @@ static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf)
+ retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ DRCI_READ_REQ, req_type,
+ 0x0000,
+- reg, dma_buf, sizeof(*dma_buf), 5 * HZ);
++ reg, dma_buf, sizeof(*dma_buf),
++ USB_CTRL_GET_TIMEOUT);
+ *buf = le16_to_cpu(*dma_buf);
+ kfree(dma_buf);
+
+@@ -176,7 +177,7 @@ static inline int drci_wr_reg(struct usb_device *dev, u16 reg, u16 data)
+ reg,
+ NULL,
+ 0,
+- 5 * HZ);
++ USB_CTRL_SET_TIMEOUT);
+ }
+
+ static inline int start_sync_ep(struct usb_device *usb_dev, u16 ep)
+diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
+index 9802e265fca80..2b317ed6c103f 100644
+--- a/drivers/mtd/devices/mtd_dataflash.c
++++ b/drivers/mtd/devices/mtd_dataflash.c
+@@ -96,6 +96,13 @@ struct dataflash {
+ struct mtd_info mtd;
+ };
+
++static const struct spi_device_id dataflash_dev_ids[] = {
++ { "at45" },
++ { "dataflash" },
++ { },
++};
++MODULE_DEVICE_TABLE(spi, dataflash_dev_ids);
++
+ #ifdef CONFIG_OF
+ static const struct of_device_id dataflash_dt_ids[] = {
+ { .compatible = "atmel,at45", },
+@@ -927,6 +934,7 @@ static struct spi_driver dataflash_driver = {
+ .name = "mtd_dataflash",
+ .of_match_table = of_match_ptr(dataflash_dt_ids),
+ },
++ .id_table = dataflash_dev_ids,
+
+ .probe = dataflash_probe,
+ .remove = dataflash_remove,
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index c8fd7f758938b..1532291989471 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -724,8 +724,6 @@ int del_mtd_device(struct mtd_info *mtd)
+
+ 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;
+@@ -741,6 +739,8 @@ int del_mtd_device(struct mtd_info *mtd)
+ 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);
+diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
+index ff1697f899ba6..13de39aa3288f 100644
+--- a/drivers/mtd/nand/raw/ams-delta.c
++++ b/drivers/mtd/nand/raw/ams-delta.c
+@@ -217,9 +217,8 @@ static int gpio_nand_setup_interface(struct nand_chip *this, int csline,
+
+ static int gpio_nand_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -370,6 +369,13 @@ static int gpio_nand_probe(struct platform_device *pdev)
+ /* Release write protection */
+ gpiod_set_value(priv->gpiod_nwp, 0);
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ /* Scan to find existence of the device */
+ err = nand_scan(this, 1);
+ if (err)
+diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c
+index 9cbcc698c64d8..53bd10738418b 100644
+--- a/drivers/mtd/nand/raw/arasan-nand-controller.c
++++ b/drivers/mtd/nand/raw/arasan-nand-controller.c
+@@ -973,6 +973,21 @@ static int anfc_setup_interface(struct nand_chip *chip, int target,
+ nvddr = nand_get_nvddr_timings(conf);
+ if (IS_ERR(nvddr))
+ return PTR_ERR(nvddr);
++
++ /*
++ * The controller only supports data payload requests which are
++ * a multiple of 4. In practice, most data accesses are 4-byte
++ * aligned and this is not an issue. However, rounding up will
++ * simply be refused by the controller if we reached the end of
++ * the device *and* we are using the NV-DDR interface(!). In
++ * this situation, unaligned data requests ending at the device
++ * boundary will confuse the controller and cannot be performed.
++ *
++ * This is something that happens in nand_read_subpage() when
++ * selecting software ECC support and must be avoided.
++ */
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT)
++ return -ENOTSUPP;
+ } else {
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
+index 99116896cfd6c..5aa3a06d740c7 100644
+--- a/drivers/mtd/nand/raw/au1550nd.c
++++ b/drivers/mtd/nand/raw/au1550nd.c
+@@ -239,9 +239,8 @@ static int au1550nd_exec_op(struct nand_chip *this,
+
+ static int au1550nd_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -310,6 +309,13 @@ static int au1550nd_probe(struct platform_device *pdev)
+ if (pd->devwidth)
+ this->options |= NAND_BUSWIDTH_16;
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ ret = nand_scan(this, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
+diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
+index a3e66155ae405..6b2bda815b880 100644
+--- a/drivers/mtd/nand/raw/fsmc_nand.c
++++ b/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 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
+ {
+ 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 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
+ 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 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
+ 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;
+ }
+
+@@ -438,8 +455,10 @@ static int fsmc_correct_ecc1(struct nand_chip *chip,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
+ {
++ bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
++
+ return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc,
+- chip->ecc.size, false);
++ chip->ecc.size, sm_order);
+ }
+
+ /* Count the number of 0's in buff upto a max of max_bits */
+@@ -662,6 +681,9 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
+ instr->ctx.waitrdy.timeout_ms);
+ break;
+ }
++
++ if (instr->delay_ns)
++ ndelay(instr->delay_ns);
+ }
+
+ return ret;
+diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
+index fb7a086de35e5..fdf073d2e1b6c 100644
+--- a/drivers/mtd/nand/raw/gpio.c
++++ b/drivers/mtd/nand/raw/gpio.c
+@@ -163,9 +163,8 @@ static int gpio_nand_exec_op(struct nand_chip *chip,
+
+ static int gpio_nand_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -365,6 +364,13 @@ static int gpio_nand_probe(struct platform_device *pdev)
+ if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
+ gpiod_direction_output(gpiomtd->nwp, 1);
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ ret = nand_scan(chip, 1);
+ if (ret)
+ goto err_wp;
+diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c
+index b9784f3da7a11..7c1c80dae826a 100644
+--- a/drivers/mtd/nand/raw/intel-nand-controller.c
++++ b/drivers/mtd/nand/raw/intel-nand-controller.c
+@@ -609,6 +609,11 @@ static int ebu_nand_probe(struct platform_device *pdev)
+ dev_err(dev, "failed to get chip select: %d\n", ret);
+ return ret;
+ }
++ if (cs >= MAX_CS) {
++ dev_err(dev, "got invalid chip select: %d\n", cs);
++ return -EINVAL;
++ }
++
+ ebu_host->cs_num = cs;
+
+ resname = devm_kasprintf(dev, GFP_KERNEL, "nand_cs%d", cs);
+diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
+index bcd4a556c959c..cb293c50acb87 100644
+--- a/drivers/mtd/nand/raw/mpc5121_nfc.c
++++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
+@@ -605,9 +605,8 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+
+ static int mpc5121_nfc_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -772,6 +771,13 @@ static int mpc5121_nfc_probe(struct platform_device *op)
+ goto error;
+ }
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ /* Detect NAND chips */
+ retval = nand_scan(chip, be32_to_cpup(chips_no));
+ if (retval) {
+diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
+index 3d6c6e8805207..a130320de4128 100644
+--- a/drivers/mtd/nand/raw/nand_base.c
++++ b/drivers/mtd/nand/raw/nand_base.c
+@@ -926,7 +926,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
+ struct nand_sdr_timings *spec_timings)
+ {
+ const struct nand_controller_ops *ops = chip->controller->ops;
+- int best_mode = 0, mode, ret;
++ int best_mode = 0, mode, ret = -EOPNOTSUPP;
+
+ iface->type = NAND_SDR_IFACE;
+
+@@ -977,7 +977,7 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip,
+ struct nand_nvddr_timings *spec_timings)
+ {
+ const struct nand_controller_ops *ops = chip->controller->ops;
+- int best_mode = 0, mode, ret;
++ int best_mode = 0, mode, ret = -EOPNOTSUPP;
+
+ iface->type = NAND_NVDDR_IFACE;
+
+@@ -1837,7 +1837,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
+ NAND_OP_CMD(NAND_CMD_ERASE1, 0),
+ NAND_OP_ADDR(2, addrs, 0),
+ NAND_OP_CMD(NAND_CMD_ERASE2,
+- NAND_COMMON_TIMING_MS(conf, tWB_max)),
++ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max),
+ 0),
+ };
+diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
+index 66211c9311d2f..2c87c7d892058 100644
+--- a/drivers/mtd/nand/raw/orion_nand.c
++++ b/drivers/mtd/nand/raw/orion_nand.c
+@@ -85,9 +85,8 @@ static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+
+ static int orion_nand_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -190,6 +189,13 @@ static int __init orion_nand_probe(struct platform_device *pdev)
+ return ret;
+ }
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ nc->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ ret = nand_scan(nc, 1);
+ if (ret)
+ goto no_dev;
+diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
+index 789f33312c15f..c176036453ed9 100644
+--- a/drivers/mtd/nand/raw/pasemi_nand.c
++++ b/drivers/mtd/nand/raw/pasemi_nand.c
+@@ -75,9 +75,8 @@ static int pasemi_device_ready(struct nand_chip *chip)
+
+ static int pasemi_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -154,6 +153,13 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
+ /* Enable the following for a flash based bad block table */
+ chip->bbt_options = NAND_BBT_USE_FLASH;
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ /* Scan to find existence of the device */
+ err = nand_scan(chip, 1);
+ if (err)
+diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
+index 7711e1020c21c..0ee08c42cc35b 100644
+--- a/drivers/mtd/nand/raw/plat_nand.c
++++ b/drivers/mtd/nand/raw/plat_nand.c
+@@ -21,9 +21,8 @@ struct plat_nand_data {
+
+ static int plat_nand_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -94,6 +93,13 @@ static int plat_nand_probe(struct platform_device *pdev)
+ goto out;
+ }
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ /* Scan to find existence of the device */
+ err = nand_scan(&data->chip, pdata->chip.nr_chips);
+ if (err)
+diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
+index 70f8305c9b6e1..fb39cc7ebce03 100644
+--- a/drivers/mtd/nand/raw/socrates_nand.c
++++ b/drivers/mtd/nand/raw/socrates_nand.c
+@@ -119,9 +119,8 @@ static int socrates_nand_device_ready(struct nand_chip *nand_chip)
+
+ static int socrates_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -175,6 +174,13 @@ static int socrates_nand_probe(struct platform_device *ofdev)
+ /* TODO: I have no idea what real delay is. */
+ nand_chip->legacy.chip_delay = 20; /* 20us command delay time */
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ dev_set_drvdata(&ofdev->dev, host);
+
+ res = nand_scan(nand_chip, 1);
+diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
+index 26751976e5026..236fd8c5a958f 100644
+--- a/drivers/mtd/nand/raw/xway_nand.c
++++ b/drivers/mtd/nand/raw/xway_nand.c
+@@ -148,9 +148,8 @@ static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len)
+
+ static int xway_attach_chip(struct nand_chip *chip)
+ {
+- chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+-
+- if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
++ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
++ chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
+ chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
+
+ return 0;
+@@ -219,6 +218,13 @@ static int xway_nand_probe(struct platform_device *pdev)
+ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
+ | cs_flag, EBU_NAND_CON);
+
++ /*
++ * This driver assumes that the default ECC engine should be TYPE_SOFT.
++ * Set ->engine_type before registering the NAND devices in order to
++ * provide a driver specific default value.
++ */
++ data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
++
+ /* Scan to find existence of the device */
+ err = nand_scan(&data->chip, 1);
+ if (err)
+diff --git a/drivers/mtd/spi-nor/controllers/hisi-sfc.c b/drivers/mtd/spi-nor/controllers/hisi-sfc.c
+index 47fbf1d1e5573..516e502694780 100644
+--- a/drivers/mtd/spi-nor/controllers/hisi-sfc.c
++++ b/drivers/mtd/spi-nor/controllers/hisi-sfc.c
+@@ -477,7 +477,6 @@ static int hisi_spi_nor_remove(struct platform_device *pdev)
+
+ hisi_spi_nor_unregister_all(host);
+ mutex_destroy(&host->lock);
+- clk_disable_unprepare(host->clk);
+ return 0;
+ }
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index f37b1c56f7c43..dd335ae1122b0 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -150,7 +150,7 @@ config NET_FC
+
+ config IFB
+ tristate "Intermediate Functional Block support"
+- depends on NET_CLS_ACT
++ depends on NET_ACT_MIRRED || NFT_FWD_NETDEV
+ select NET_REDIRECT
+ help
+ This is an intermediate driver that allows sharing of
+diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
+index 7d3752cbf761d..bca36be884b8d 100644
+--- a/drivers/net/bonding/bond_alb.c
++++ b/drivers/net/bonding/bond_alb.c
+@@ -1502,14 +1502,14 @@ void bond_alb_monitor(struct work_struct *work)
+ 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 */
+@@ -1531,7 +1531,7 @@ void bond_alb_monitor(struct work_struct *work)
+ }
+
+ /* 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)) {
+@@ -1541,7 +1541,7 @@ void bond_alb_monitor(struct work_struct *work)
+ bond_info->unbalanced_load = 0;
+ }
+ }
+- bond_info->tx_rebalance_counter = 0;
++ atomic_set(&bond_info->tx_rebalance_counter, 0);
+ }
+
+ if (bond_info->rlb_enabled) {
+@@ -1611,7 +1611,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
+ 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;
+@@ -1648,7 +1649,8 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
+ 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
+diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c
+index fd07561da0348..6a6cdd0bb2585 100644
+--- a/drivers/net/bonding/bond_sysfs_slave.c
++++ b/drivers/net/bonding/bond_sysfs_slave.c
+@@ -108,15 +108,15 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
+ }
+ 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
+ };
+
+@@ -137,24 +137,10 @@ const struct sysfs_ops slave_sysfs_ops = {
+
+ int bond_sysfs_slave_add(struct slave *slave)
+ {
+- const struct slave_attribute **a;
+- int 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));
++ sysfs_remove_files(&slave->kobj, slave_attrs);
+ }
+diff --git a/drivers/net/can/dev/bittiming.c b/drivers/net/can/dev/bittiming.c
+index f49170eadd547..b1b5a82f08299 100644
+--- a/drivers/net/can/dev/bittiming.c
++++ b/drivers/net/can/dev/bittiming.c
+@@ -209,7 +209,7 @@ 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;
++ unsigned int tseg1, alltseg;
+ u64 brp64;
+
+ tseg1 = bt->prop_seg + bt->phase_seg1;
+diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c
+index 74d9899fc904c..eb74cdf26b88c 100644
+--- a/drivers/net/can/kvaser_pciefd.c
++++ b/drivers/net/can/kvaser_pciefd.c
+@@ -248,6 +248,9 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
+ #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 {
+@@ -1285,7 +1288,10 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
+
+ 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;
+diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
+index 2470c47b2e315..c2a8421e7845c 100644
+--- a/drivers/net/can/m_can/m_can.c
++++ b/drivers/net/can/m_can/m_can.c
+@@ -204,16 +204,16 @@ enum m_can_reg {
+
+ /* 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) */
+@@ -517,7 +517,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
+ err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DATA,
+ cf->data, DIV_ROUND_UP(cf->len, 4));
+ if (err)
+- goto out_fail;
++ goto out_free_skb;
+ }
+
+ /* acknowledge rx fifo 0 */
+@@ -532,6 +532,8 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
+
+ return 0;
+
++out_free_skb:
++ kfree_skb(skb);
+ out_fail:
+ netdev_err(dev, "FIFO read returned %d\n", err);
+ return err;
+@@ -810,8 +812,6 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
+ {
+ 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)
+@@ -1494,20 +1494,32 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
+ case 30:
+ /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
+ can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
+- cdev->can.bittiming_const = &m_can_bittiming_const_30X;
+- cdev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;
++ cdev->can.bittiming_const = cdev->bit_timing ?
++ cdev->bit_timing : &m_can_bittiming_const_30X;
++
++ cdev->can.data_bittiming_const = cdev->data_timing ?
++ cdev->data_timing :
++ &m_can_data_bittiming_const_30X;
+ break;
+ case 31:
+ /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
+ can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
+- cdev->can.bittiming_const = &m_can_bittiming_const_31X;
+- cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
++ cdev->can.bittiming_const = cdev->bit_timing ?
++ cdev->bit_timing : &m_can_bittiming_const_31X;
++
++ cdev->can.data_bittiming_const = cdev->data_timing ?
++ cdev->data_timing :
++ &m_can_data_bittiming_const_31X;
+ break;
+ case 32:
+ case 33:
+ /* Support both MCAN version v3.2.x and v3.3.0 */
+- cdev->can.bittiming_const = &m_can_bittiming_const_31X;
+- cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
++ cdev->can.bittiming_const = cdev->bit_timing ?
++ cdev->bit_timing : &m_can_bittiming_const_31X;
++
++ cdev->can.data_bittiming_const = cdev->data_timing ?
++ cdev->data_timing :
++ &m_can_data_bittiming_const_31X;
+
+ cdev->can.ctrlmode_supported |=
+ (m_can_niso_supported(cdev) ?
+diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
+index d18b515e6ccc7..2c5d409971686 100644
+--- a/drivers/net/can/m_can/m_can.h
++++ b/drivers/net/can/m_can/m_can.h
+@@ -85,6 +85,9 @@ struct m_can_classdev {
+ struct sk_buff *tx_skb;
+ struct phy *transceiver;
+
++ const struct can_bittiming_const *bit_timing;
++ const struct can_bittiming_const *data_timing;
++
+ struct m_can_ops *ops;
+
+ int version;
+diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c
+index 89cc3d41e952b..b56a54d6c5a9c 100644
+--- a/drivers/net/can/m_can/m_can_pci.c
++++ b/drivers/net/can/m_can/m_can_pci.c
+@@ -18,9 +18,14 @@
+
+ #define M_CAN_PCI_MMIO_BAR 0
+
+-#define M_CAN_CLOCK_FREQ_EHL 100000000
+ #define CTL_CSR_INT_CTL_OFFSET 0x508
+
++struct m_can_pci_config {
++ const struct can_bittiming_const *bit_timing;
++ const struct can_bittiming_const *data_timing;
++ unsigned int clock_freq;
++};
++
+ struct m_can_pci_priv {
+ struct m_can_classdev cdev;
+
+@@ -42,8 +47,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
+ static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
+ {
+ struct m_can_pci_priv *priv = cdev_to_priv(cdev);
++ void __iomem *src = priv->base + offset;
+
+- ioread32_rep(priv->base + offset, val, val_count);
++ while (val_count--) {
++ *(unsigned int *)val = ioread32(src);
++ val += 4;
++ src += 4;
++ }
+
+ return 0;
+ }
+@@ -61,8 +71,13 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
+ const void *val, size_t val_count)
+ {
+ struct m_can_pci_priv *priv = cdev_to_priv(cdev);
++ void __iomem *dst = priv->base + offset;
+
+- iowrite32_rep(priv->base + offset, val, val_count);
++ while (val_count--) {
++ iowrite32(*(unsigned int *)val, dst);
++ val += 4;
++ dst += 4;
++ }
+
+ return 0;
+ }
+@@ -74,9 +89,40 @@ static struct m_can_ops m_can_pci_ops = {
+ .read_fifo = iomap_read_fifo,
+ };
+
++static const struct can_bittiming_const m_can_bittiming_const_ehl = {
++ .name = KBUILD_MODNAME,
++ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
++ .tseg1_max = 64,
++ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
++ .tseg2_max = 128,
++ .sjw_max = 128,
++ .brp_min = 1,
++ .brp_max = 512,
++ .brp_inc = 1,
++};
++
++static const struct can_bittiming_const m_can_data_bittiming_const_ehl = {
++ .name = KBUILD_MODNAME,
++ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
++ .tseg1_max = 16,
++ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
++ .tseg2_max = 8,
++ .sjw_max = 4,
++ .brp_min = 1,
++ .brp_max = 32,
++ .brp_inc = 1,
++};
++
++static const struct m_can_pci_config m_can_pci_ehl = {
++ .bit_timing = &m_can_bittiming_const_ehl,
++ .data_timing = &m_can_data_bittiming_const_ehl,
++ .clock_freq = 200000000,
++};
++
+ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+ {
+ struct device *dev = &pci->dev;
++ const struct m_can_pci_config *cfg;
+ struct m_can_classdev *mcan_class;
+ struct m_can_pci_priv *priv;
+ void __iomem *base;
+@@ -104,6 +150,8 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+ if (!mcan_class)
+ return -ENOMEM;
+
++ cfg = (const struct m_can_pci_config *)id->driver_data;
++
+ priv = cdev_to_priv(mcan_class);
+
+ priv->base = base;
+@@ -115,7 +163,9 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+ mcan_class->dev = &pci->dev;
+ mcan_class->net->irq = pci_irq_vector(pci, 0);
+ mcan_class->pm_clock_support = 1;
+- mcan_class->can.clock.freq = id->driver_data;
++ mcan_class->bit_timing = cfg->bit_timing;
++ mcan_class->data_timing = cfg->data_timing;
++ mcan_class->can.clock.freq = cfg->clock_freq;
+ mcan_class->ops = &m_can_pci_ops;
+
+ pci_set_drvdata(pci, mcan_class);
+@@ -168,8 +218,8 @@ static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
+ m_can_pci_suspend, m_can_pci_resume);
+
+ static const struct pci_device_id m_can_pci_id_table[] = {
+- { PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, },
+- { PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, },
++ { PCI_VDEVICE(INTEL, 0x4bc1), (kernel_ulong_t)&m_can_pci_ehl, },
++ { PCI_VDEVICE(INTEL, 0x4bc2), (kernel_ulong_t)&m_can_pci_ehl, },
+ { } /* Terminating Entry */
+ };
+ MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);
+diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
+index 92a54a5fd4c50..964c8a09226a9 100644
+--- a/drivers/net/can/pch_can.c
++++ b/drivers/net/can/pch_can.c
+@@ -692,11 +692,11 @@ static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
+ cf->data[i + 1] = data_reg >> 8;
+ }
+
+- netif_receive_skb(skb);
+ rcv_pkts++;
+ stats->rx_packets++;
+ quota--;
+ stats->rx_bytes += cf->len;
++ netif_receive_skb(skb);
+
+ pch_fifo_thresh(priv, obj_num);
+ obj_num++;
+diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
+index e21b169c14c01..4642b6d4aaf7b 100644
+--- a/drivers/net/can/sja1000/ems_pcmcia.c
++++ b/drivers/net/can/sja1000/ems_pcmcia.c
+@@ -234,7 +234,12 @@ static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
+ 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;
+diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+index 673861ab665a4..e16dc482f3270 100644
+--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
++++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+@@ -1092,7 +1092,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
+
+ err = mcp251xfd_chip_rx_int_enable(priv);
+ if (err)
+- return err;
++ goto out_chip_stop;
+
+ err = mcp251xfd_chip_ecc_init(priv);
+ if (err)
+@@ -2290,8 +2290,10 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
+ * check will fail, too. So leave IRQ handler
+ * directly.
+ */
+- if (priv->can.state == CAN_STATE_BUS_OFF)
++ if (priv->can.state == CAN_STATE_BUS_OFF) {
++ can_rx_offload_threaded_irq_finish(&priv->offload);
+ return IRQ_HANDLED;
++ }
+ }
+
+ handled = IRQ_HANDLED;
+diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
+index 96a13c770e4a1..24627ab146261 100644
+--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
++++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
+@@ -664,7 +664,7 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
+ struct can_device_stats *can_stats = &can->can_stats;
+ struct can_frame *cf = NULL;
+ struct sk_buff *skb;
+- int ret;
++ int ret = 0;
+
+ if (!netif_running(netdev)) {
+ if (net_ratelimit())
+@@ -823,8 +823,6 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
+ can->state = CAN_STATE_BUS_OFF;
+ can_bus_off(netdev);
+ ret = can->do_set_mode(netdev, CAN_MODE_STOP);
+- if (ret)
+- return ret;
+ }
+ break;
+
+@@ -881,7 +879,7 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
+ ES58X_EVENT_BUSOFF, timestamp);
+ }
+
+- return 0;
++ return ret;
+ }
+
+ /**
+diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+index 59ba7c7beec00..f7af1bf5ab46d 100644
+--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
++++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+@@ -28,10 +28,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 */
+@@ -80,6 +76,12 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg;
+
+ #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)
++
+ /* error factors */
+ #define M16C_EF_ACKE BIT(0)
+ #define M16C_EF_CRCE BIT(1)
+@@ -340,6 +342,50 @@ struct kvaser_usb_err_summary {
+ };
+ };
+
++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 const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
++ .clock = {
++ .freq = 8000000,
++ },
++ .timestamp_freq = 1,
++ .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++};
++
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
++ .clock = {
++ .freq = 16000000,
++ },
++ .timestamp_freq = 1,
++ .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++};
++
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
++ .clock = {
++ .freq = 24000000,
++ },
++ .timestamp_freq = 1,
++ .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++};
++
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
++ .clock = {
++ .freq = 32000000,
++ },
++ .timestamp_freq = 1,
++ .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++};
++
+ static void *
+ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
+ const struct sk_buff *skb, int *frame_len,
+@@ -471,6 +517,27 @@ static int kvaser_usb_leaf_send_simple_cmd(const struct kvaser_usb *dev,
+ 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);
++
++ switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
++ case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
++ break;
++ case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
++ break;
++ case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
++ break;
++ }
++}
++
+ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
+ {
+ struct kvaser_cmd cmd;
+@@ -486,14 +553,13 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
+
+ switch (dev->card_data.leaf.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_dev_cfg_8mhz;
+ break;
+ }
+
+@@ -1225,24 +1291,11 @@ static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev)
+ {
+ 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_set_bittiming(struct net_device *netdev)
+ {
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+@@ -1348,11 +1401,3 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
+ .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,
+-};
+diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
+index 837b3fecd71e9..af8d3dadbbb8b 100644
+--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
++++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
+@@ -841,14 +841,14 @@ static int pcan_usb_start(struct peak_usb_device *dev)
+ pdev->bec.rxerr = 0;
+ pdev->bec.txerr = 0;
+
+- /* be notified on error counter changes (if requested by user) */
+- if (dev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
+- err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK);
+- if (err)
+- netdev_warn(dev->netdev,
+- "Asking for BERR reporting error %u\n",
+- err);
+- }
++ /* always ask the device for BERR reporting, to be able to switch from
++ * WARNING to PASSIVE state
++ */
++ err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK);
++ if (err)
++ netdev_warn(dev->netdev,
++ "Asking for BERR reporting error %u\n",
++ err);
+
+ /* if revision greater than 3, can put silent mode on/off */
+ if (dev->device_rev > 3) {
+@@ -986,7 +986,6 @@ const struct peak_usb_adapter pcan_usb = {
+ .device_id = PCAN_USB_PRODUCT_ID,
+ .ctrl_count = 1,
+ .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
+- CAN_CTRLMODE_BERR_REPORTING |
+ CAN_CTRLMODE_CC_LEN8_DLC,
+ .clock = {
+ .freq = PCAN_USB_CRYSTAL_HZ / 2,
+diff --git a/drivers/net/dsa/b53/b53_spi.c b/drivers/net/dsa/b53/b53_spi.c
+index 01e37b75471e1..2b88f03e52521 100644
+--- a/drivers/net/dsa/b53/b53_spi.c
++++ b/drivers/net/dsa/b53/b53_spi.c
+@@ -349,6 +349,19 @@ static const struct of_device_id b53_spi_of_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, b53_spi_of_match);
+
++static const struct spi_device_id b53_spi_ids[] = {
++ { .name = "bcm5325" },
++ { .name = "bcm5365" },
++ { .name = "bcm5395" },
++ { .name = "bcm5397" },
++ { .name = "bcm5398" },
++ { .name = "bcm53115" },
++ { .name = "bcm53125" },
++ { .name = "bcm53128" },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(spi, b53_spi_ids);
++
+ static struct spi_driver b53_spi_driver = {
+ .driver = {
+ .name = "b53-switch",
+@@ -357,6 +370,7 @@ static struct spi_driver b53_spi_driver = {
+ .probe = b53_spi_probe,
+ .remove = b53_spi_remove,
+ .shutdown = b53_spi_shutdown,
++ .id_table = b53_spi_ids,
+ };
+
+ module_spi_driver(b53_spi_driver);
+diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
+index 8dadcae93c9b5..43d126628610b 100644
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -471,6 +471,12 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
+ u16 reg;
+ int err;
+
++ /* The 88e6250 family does not have the PHY detect bit. Instead,
++ * report whether the port is internal.
++ */
++ if (chip->info->family == MV88E6XXX_FAMILY_6250)
++ return port < chip->info->num_internal_phys;
++
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err) {
+ dev_err(chip->dev,
+@@ -640,7 +646,10 @@ static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
+ unsigned long *mask,
+ struct phylink_link_state *state)
+ {
+- if (port == 0 || port == 9 || port == 10) {
++ bool is_6191x =
++ chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
++
++ if (((port == 0 || port == 9) && !is_6191x) || port == 10) {
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 10000baseCR_Full);
+@@ -690,44 +699,48 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
+ {
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+- int err;
++ int err = 0;
+
+ p = &chip->ports[port];
+
+- /* FIXME: is this the correct test? If we're in fixed mode on an
+- * internal port, why should we process this any different from
+- * PHY mode? On the other hand, the port may be automedia between
+- * an internal PHY and the serdes...
+- */
+- if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
+- return;
+-
+ mv88e6xxx_reg_lock(chip);
+- /* In inband mode, the link may come up at any time while the link
+- * is not forced down. Force the link down while we reconfigure the
+- * interface mode.
+- */
+- if (mode == MLO_AN_INBAND && p->interface != state->interface &&
+- chip->info->ops->port_set_link)
+- chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
+-
+- err = mv88e6xxx_port_config_interface(chip, port, state->interface);
+- if (err && err != -EOPNOTSUPP)
+- goto err_unlock;
+
+- err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
+- state->advertising);
+- /* FIXME: we should restart negotiation if something changed - which
+- * is something we get if we convert to using phylinks PCS operations.
+- */
+- if (err > 0)
+- err = 0;
++ if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) {
++ /* In inband mode, the link may come up at any time while the
++ * link is not forced down. Force the link down while we
++ * reconfigure the interface mode.
++ */
++ if (mode == MLO_AN_INBAND &&
++ p->interface != state->interface &&
++ chip->info->ops->port_set_link)
++ chip->info->ops->port_set_link(chip, port,
++ LINK_FORCED_DOWN);
++
++ err = mv88e6xxx_port_config_interface(chip, port,
++ state->interface);
++ if (err && err != -EOPNOTSUPP)
++ goto err_unlock;
++
++ err = mv88e6xxx_serdes_pcs_config(chip, port, mode,
++ state->interface,
++ state->advertising);
++ /* FIXME: we should restart negotiation if something changed -
++ * which is something we get if we convert to using phylinks
++ * PCS operations.
++ */
++ if (err > 0)
++ err = 0;
++ }
+
+ /* Undo the forced down state above after completing configuration
+- * irrespective of its state on entry, which allows the link to come up.
++ * irrespective of its state on entry, which allows the link to come
++ * up in the in-band case where there is no separate SERDES. Also
++ * ensure that the link can come up if the PPU is in use and we are
++ * in PHY mode (we treat the PPU as an effective in-band mechanism.)
+ */
+- if (mode == MLO_AN_INBAND && p->interface != state->interface &&
+- chip->info->ops->port_set_link)
++ if (chip->info->ops->port_set_link &&
++ ((mode == MLO_AN_INBAND && p->interface != state->interface) ||
++ (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port))))
+ chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
+
+ p->interface = state->interface;
+@@ -750,13 +763,16 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
+ ops = chip->info->ops;
+
+ mv88e6xxx_reg_lock(chip);
+- /* Internal PHYs propagate their configuration directly to the MAC.
+- * External PHYs depend on whether the PPU is enabled for this port.
++ /* Force the link down if we know the port may not be automatically
++ * updated by the switch or if we are using fixed-link mode.
+ */
+- if (((!mv88e6xxx_phy_is_internal(ds, port) &&
+- !mv88e6xxx_port_ppu_updates(chip, port)) ||
++ if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
+ mode == MLO_AN_FIXED) && ops->port_sync_link)
+ err = ops->port_sync_link(chip, port, mode, false);
++
++ if (!err && ops->port_set_speed_duplex)
++ err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED,
++ DUPLEX_UNFORCED);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (err)
+@@ -777,11 +793,11 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
+ ops = chip->info->ops;
+
+ mv88e6xxx_reg_lock(chip);
+- /* Internal PHYs propagate their configuration directly to the MAC.
+- * External PHYs depend on whether the PPU is enabled for this port.
++ /* Configure and force the link up if we know that the port may not
++ * automatically updated by the switch or if we are using fixed-link
++ * mode.
+ */
+- if ((!mv88e6xxx_phy_is_internal(ds, port) &&
+- !mv88e6xxx_port_ppu_updates(chip, port)) ||
++ if (!mv88e6xxx_port_ppu_updates(chip, port) ||
+ mode == MLO_AN_FIXED) {
+ /* FIXME: for an automedia port, should we force the link
+ * down here - what if the link comes up due to "other" media
+diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
+index d9817b20ea641..ab41619a809b3 100644
+--- a/drivers/net/dsa/mv88e6xxx/port.c
++++ b/drivers/net/dsa/mv88e6xxx/port.c
+@@ -283,7 +283,7 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
+ if (err)
+ return err;
+
+- if (speed)
++ if (speed != SPEED_UNFORCED)
+ dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
+ else
+ dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
+@@ -516,7 +516,7 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
+ if (err)
+ return err;
+
+- if (speed)
++ if (speed != SPEED_UNFORCED)
+ dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
+ else
+ dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
+diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
+index 6ea0036787986..2b05ead515cdc 100644
+--- a/drivers/net/dsa/mv88e6xxx/serdes.c
++++ b/drivers/net/dsa/mv88e6xxx/serdes.c
+@@ -50,11 +50,22 @@ static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
+ }
+
+ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
+- u16 status, u16 lpa,
++ u16 ctrl, u16 status, u16 lpa,
+ struct phylink_link_state *state)
+ {
++ state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
++
+ if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
+- state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
++ /* The Spped and Duplex Resolved register is 1 if AN is enabled
++ * and complete, or if AN is disabled. So with disabled AN we
++ * still get here on link up. But we want to set an_complete
++ * only if AN was enabled, thus we look at BMCR_ANENABLE.
++ * (According to 802.3-2008 section 22.2.4.2.10, we should be
++ * able to get this same value from BMSR_ANEGCAPABLE, but tests
++ * show that these Marvell PHYs don't conform to this part of
++ * the specificaion - BMSR_ANEGCAPABLE is simply always 1.)
++ */
++ state->an_complete = !!(ctrl & BMCR_ANENABLE);
+ state->duplex = status &
+ MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
+ DUPLEX_FULL : DUPLEX_HALF;
+@@ -81,6 +92,18 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
+ dev_err(chip->dev, "invalid PHY speed\n");
+ return -EINVAL;
+ }
++ } else if (state->link &&
++ state->interface != PHY_INTERFACE_MODE_SGMII) {
++ /* If Speed and Duplex Resolved register is 0 and link is up, it
++ * means that AN was enabled, but link partner had it disabled
++ * and the PHY invoked the Auto-Negotiation Bypass feature and
++ * linked anyway.
++ */
++ state->duplex = DUPLEX_FULL;
++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
++ state->speed = SPEED_2500;
++ else
++ state->speed = SPEED_1000;
+ } else {
+ state->link = false;
+ }
+@@ -168,9 +191,15 @@ int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
+ int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
+ int lane, struct phylink_link_state *state)
+ {
+- u16 lpa, status;
++ u16 lpa, status, ctrl;
+ int err;
+
++ err = mv88e6352_serdes_read(chip, MII_BMCR, &ctrl);
++ if (err) {
++ dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err);
++ return err;
++ }
++
+ err = mv88e6352_serdes_read(chip, 0x11, &status);
+ if (err) {
+ dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
+@@ -183,7 +212,7 @@ int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
+ return err;
+ }
+
+- return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
++ return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state);
+ }
+
+ int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
+@@ -801,7 +830,7 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ bool up)
+ {
+ u8 cmode = chip->ports[port].cmode;
+- int err = 0;
++ int err;
+
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+@@ -813,6 +842,9 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ case MV88E6XXX_PORT_STS_CMODE_RXAUI:
+ err = mv88e6390_serdes_power_10g(chip, lane, up);
+ break;
++ default:
++ err = -EINVAL;
++ break;
+ }
+
+ if (!err && up)
+@@ -883,9 +915,16 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
+ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
+ int port, int lane, struct phylink_link_state *state)
+ {
+- u16 lpa, status;
++ u16 lpa, status, ctrl;
+ int err;
+
++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6390_SGMII_BMCR, &ctrl);
++ if (err) {
++ dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err);
++ return err;
++ }
++
+ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
+ MV88E6390_SGMII_PHY_STATUS, &status);
+ if (err) {
+@@ -900,7 +939,7 @@ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
+ return err;
+ }
+
+- return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
++ return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state);
+ }
+
+ static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
+@@ -1271,9 +1310,31 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
+ }
+ }
+
+-static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
++static int mv88e6393x_serdes_power_lane(struct mv88e6xxx_chip *chip, int lane,
++ bool on)
+ {
+- u16 reg, pcs;
++ u16 reg;
++ int err;
++
++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_CTRL1, &reg);
++ if (err)
++ return err;
++
++ if (on)
++ reg &= ~(MV88E6393X_SERDES_CTRL1_TX_PDOWN |
++ MV88E6393X_SERDES_CTRL1_RX_PDOWN);
++ else
++ reg |= MV88E6393X_SERDES_CTRL1_TX_PDOWN |
++ MV88E6393X_SERDES_CTRL1_RX_PDOWN;
++
++ return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_CTRL1, reg);
++}
++
++static int mv88e6393x_serdes_erratum_4_6(struct mv88e6xxx_chip *chip, int lane)
++{
++ u16 reg;
+ int err;
+
+ /* mv88e6393x family errata 4.6:
+@@ -1284,26 +1345,45 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
+ * It seems that after this workaround the SERDES is automatically
+ * powered up (the bit is cleared), so power it down.
+ */
+- if (lane == MV88E6393X_PORT0_LANE || lane == MV88E6393X_PORT9_LANE ||
+- lane == MV88E6393X_PORT10_LANE) {
+- err = mv88e6390_serdes_read(chip, lane,
+- MDIO_MMD_PHYXS,
+- MV88E6393X_SERDES_POC, &reg);
+- if (err)
+- return err;
++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_POC, &reg);
++ if (err)
++ return err;
+
+- reg &= ~MV88E6393X_SERDES_POC_PDOWN;
+- reg |= MV88E6393X_SERDES_POC_RESET;
++ reg &= ~MV88E6393X_SERDES_POC_PDOWN;
++ reg |= MV88E6393X_SERDES_POC_RESET;
+
+- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
+- MV88E6393X_SERDES_POC, reg);
+- if (err)
+- return err;
++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_POC, reg);
++ if (err)
++ return err;
+
+- err = mv88e6390_serdes_power_sgmii(chip, lane, false);
+- if (err)
+- return err;
+- }
++ err = mv88e6390_serdes_power_sgmii(chip, lane, false);
++ if (err)
++ return err;
++
++ return mv88e6393x_serdes_power_lane(chip, lane, false);
++}
++
++int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip)
++{
++ int err;
++
++ err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT0_LANE);
++ if (err)
++ return err;
++
++ err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT9_LANE);
++ if (err)
++ return err;
++
++ return mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT10_LANE);
++}
++
++static int mv88e6393x_serdes_erratum_4_8(struct mv88e6xxx_chip *chip, int lane)
++{
++ u16 reg, pcs;
++ int err;
+
+ /* mv88e6393x family errata 4.8:
+ * When a SERDES port is operating in 1000BASE-X or SGMII mode link may
+@@ -1334,38 +1414,152 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
+ MV88E6393X_ERRATA_4_8_REG, reg);
+ }
+
+-int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip)
++static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane,
++ u8 cmode)
++{
++ static const struct {
++ u16 dev, reg, val, mask;
++ } fixes[] = {
++ { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
++ { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
++ { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
++ { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
++ { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
++ { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
++ { MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC,
++ MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET },
++ };
++ int err, i;
++ u16 reg;
++
++ /* mv88e6393x family errata 5.2:
++ * For optimal signal integrity the following sequence should be applied
++ * to SERDES operating in 10G mode. These registers only apply to 10G
++ * operation and have no effect on other speeds.
++ */
++ if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER)
++ return 0;
++
++ for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
++ err = mv88e6390_serdes_read(chip, lane, fixes[i].dev,
++ fixes[i].reg, &reg);
++ if (err)
++ return err;
++
++ reg &= ~fixes[i].mask;
++ reg |= fixes[i].val;
++
++ err = mv88e6390_serdes_write(chip, lane, fixes[i].dev,
++ fixes[i].reg, reg);
++ if (err)
++ return err;
++ }
++
++ return 0;
++}
++
++static int mv88e6393x_serdes_fix_2500basex_an(struct mv88e6xxx_chip *chip,
++ int lane, u8 cmode, bool on)
+ {
++ u16 reg;
+ int err;
+
+- err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT0_LANE);
++ if (cmode != MV88E6XXX_PORT_STS_CMODE_2500BASEX)
++ return 0;
++
++ /* Inband AN is broken on Amethyst in 2500base-x mode when set by
++ * standard mechanism (via cmode).
++ * We can get around this by configuring the PCS mode to 1000base-x
++ * and then writing value 0x58 to register 1e.8000. (This must be done
++ * while SerDes receiver and transmitter are disabled, which is, when
++ * this function is called.)
++ * It seem that when we do this configuration to 2500base-x mode (by
++ * changing PCS mode to 1000base-x and frequency to 3.125 GHz from
++ * 1.25 GHz) and then configure to sgmii or 1000base-x, the device
++ * thinks that it already has SerDes at 1.25 GHz and does not change
++ * the 1e.8000 register, leaving SerDes at 3.125 GHz.
++ * To avoid this, change PCS mode back to 2500base-x when disabling
++ * SerDes from 2500base-x mode.
++ */
++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_POC, &reg);
++ if (err)
++ return err;
++
++ reg &= ~(MV88E6393X_SERDES_POC_PCS_MASK | MV88E6393X_SERDES_POC_AN);
++ if (on)
++ reg |= MV88E6393X_SERDES_POC_PCS_1000BASEX |
++ MV88E6393X_SERDES_POC_AN;
++ else
++ reg |= MV88E6393X_SERDES_POC_PCS_2500BASEX;
++ reg |= MV88E6393X_SERDES_POC_RESET;
++
++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
++ MV88E6393X_SERDES_POC, reg);
+ if (err)
+ return err;
+
+- err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT9_LANE);
++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_VEND1, 0x8000, 0x58);
+ if (err)
+ return err;
+
+- return mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT10_LANE);
++ return 0;
+ }
+
+ int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
+ bool on)
+ {
+ u8 cmode = chip->ports[port].cmode;
++ int err;
+
+ if (port != 0 && port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
++ if (on) {
++ err = mv88e6393x_serdes_erratum_4_8(chip, lane);
++ if (err)
++ return err;
++
++ err = mv88e6393x_serdes_erratum_5_2(chip, lane, cmode);
++ if (err)
++ return err;
++
++ err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
++ true);
++ if (err)
++ return err;
++
++ err = mv88e6393x_serdes_power_lane(chip, lane, true);
++ if (err)
++ return err;
++ }
++
+ switch (cmode) {
+ case MV88E6XXX_PORT_STS_CMODE_SGMII:
+ case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
+ case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
+- return mv88e6390_serdes_power_sgmii(chip, lane, on);
++ err = mv88e6390_serdes_power_sgmii(chip, lane, on);
++ break;
+ case MV88E6393X_PORT_STS_CMODE_5GBASER:
+ case MV88E6393X_PORT_STS_CMODE_10GBASER:
+- return mv88e6390_serdes_power_10g(chip, lane, on);
++ err = mv88e6390_serdes_power_10g(chip, lane, on);
++ break;
++ default:
++ err = -EINVAL;
++ break;
+ }
+
+- return 0;
++ if (err)
++ return err;
++
++ if (!on) {
++ err = mv88e6393x_serdes_power_lane(chip, lane, false);
++ if (err)
++ return err;
++
++ err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
++ false);
++ }
++
++ return err;
+ }
+diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
+index cbb3ba30caea9..8dd8ed225b459 100644
+--- a/drivers/net/dsa/mv88e6xxx/serdes.h
++++ b/drivers/net/dsa/mv88e6xxx/serdes.h
+@@ -93,6 +93,10 @@
+ #define MV88E6393X_SERDES_POC_PCS_MASK 0x0007
+ #define MV88E6393X_SERDES_POC_RESET BIT(15)
+ #define MV88E6393X_SERDES_POC_PDOWN BIT(5)
++#define MV88E6393X_SERDES_POC_AN BIT(3)
++#define MV88E6393X_SERDES_CTRL1 0xf003
++#define MV88E6393X_SERDES_CTRL1_TX_PDOWN BIT(9)
++#define MV88E6393X_SERDES_CTRL1_RX_PDOWN BIT(8)
+
+ #define MV88E6393X_ERRATA_4_8_REG 0xF074
+ #define MV88E6393X_ERRATA_4_8_BIT BIT(14)
+diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
+index 341236dcbdb47..1513dfb523de7 100644
+--- a/drivers/net/dsa/ocelot/felix.c
++++ b/drivers/net/dsa/ocelot/felix.c
+@@ -290,8 +290,11 @@ static int felix_setup_mmio_filtering(struct felix *felix)
+ }
+ }
+
+- if (cpu < 0)
++ if (cpu < 0) {
++ kfree(tagging_rule);
++ kfree(redirect_rule);
+ return -EINVAL;
++ }
+
+ tagging_rule->key_type = OCELOT_VCAP_KEY_ETYPE;
+ *(__be16 *)tagging_rule->key.etype.etype.value = htons(ETH_P_1588);
+@@ -1368,12 +1371,12 @@ out:
+ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+ {
+- u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
++ u32 tstamp_lo = OCELOT_SKB_CB(skb)->tstamp_lo;
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct ocelot *ocelot = ds->priv;
+- u32 tstamp_lo, tstamp_hi;
+ struct timespec64 ts;
+- u64 tstamp, val;
++ u32 tstamp_hi;
++ u64 tstamp;
+
+ /* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb
+ * for RX timestamping. Then free it, and poll for its copy through
+@@ -1388,9 +1391,6 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
+ ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
+ tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+
+- ocelot_xfh_get_rew_val(extraction, &val);
+- tstamp_lo = (u32)val;
+-
+ tstamp_hi = tstamp >> 32;
+ if ((tstamp & 0xffffffff) < tstamp_lo)
+ tstamp_hi--;
+diff --git a/drivers/net/dsa/rtl8366.c b/drivers/net/dsa/rtl8366.c
+index 75897a3690969..ffbe5b6b2655b 100644
+--- a/drivers/net/dsa/rtl8366.c
++++ b/drivers/net/dsa/rtl8366.c
+@@ -457,7 +457,7 @@ int rtl8366_vlan_del(struct dsa_switch *ds, int port,
+ * anymore then clear the whole member
+ * config so it can be reused.
+ */
+- if (!vlanmc.member && vlanmc.untag) {
++ if (!vlanmc.member) {
+ vlanmc.vid = 0;
+ vlanmc.priority = 0;
+ vlanmc.fid = 0;
+diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c
+index a89093bc6c6ad..9e3b572ed999e 100644
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -1350,7 +1350,7 @@ static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index)
+
+ 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;
+diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
+index 1c00d719e5d76..804b37c76b1e6 100644
+--- a/drivers/net/ethernet/altera/altera_tse_main.c
++++ b/drivers/net/ethernet/altera/altera_tse_main.c
+@@ -1430,16 +1430,19 @@ static int altera_tse_probe(struct platform_device *pdev)
+ 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,
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+index b2cd3bdba9f89..533b8519ec352 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+@@ -1331,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
+@@ -1389,6 +1393,10 @@
+ #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
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+index 18e48b3bc402b..213769054391c 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+@@ -1977,12 +1977,26 @@ static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
+ }
+ }
+
++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)) {
+ netif_dbg(pdata, link, pdata->netdev,
+@@ -2003,7 +2017,7 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
+ wait = XGBE_RATECHANGE_COUNT;
+ while (wait--) {
+ if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
+- return;
++ goto reenable_pll;
+
+ usleep_range(1000, 2000);
+ }
+@@ -2013,6 +2027,10 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
+
+ /* 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)
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+index 23b2d390fcdda..ace691d7cd759 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+@@ -40,10 +40,12 @@
+
+ #define AQ_DEVICE_ID_AQC113DEV 0x00C0
+ #define AQ_DEVICE_ID_AQC113CS 0x94C0
++#define AQ_DEVICE_ID_AQC113CA 0x34C0
+ #define AQ_DEVICE_ID_AQC114CS 0x93C0
+ #define AQ_DEVICE_ID_AQC113 0x04C0
+ #define AQ_DEVICE_ID_AQC113C 0x14C0
+ #define AQ_DEVICE_ID_AQC115C 0x12C0
++#define AQ_DEVICE_ID_AQC116C 0x11C0
+
+ #define HW_ATL_NIC_NAME "Marvell (aQuantia) AQtion 10Gbit Network Adapter"
+
+@@ -53,20 +55,19 @@
+
+ #define AQ_NIC_RATE_10G BIT(0)
+ #define AQ_NIC_RATE_5G BIT(1)
+-#define AQ_NIC_RATE_5GSR BIT(2)
+-#define AQ_NIC_RATE_2G5 BIT(3)
+-#define AQ_NIC_RATE_1G BIT(4)
+-#define AQ_NIC_RATE_100M BIT(5)
+-#define AQ_NIC_RATE_10M BIT(6)
+-#define AQ_NIC_RATE_1G_HALF BIT(7)
+-#define AQ_NIC_RATE_100M_HALF BIT(8)
+-#define AQ_NIC_RATE_10M_HALF BIT(9)
++#define AQ_NIC_RATE_2G5 BIT(2)
++#define AQ_NIC_RATE_1G BIT(3)
++#define AQ_NIC_RATE_100M BIT(4)
++#define AQ_NIC_RATE_10M BIT(5)
++#define AQ_NIC_RATE_1G_HALF BIT(6)
++#define AQ_NIC_RATE_100M_HALF BIT(7)
++#define AQ_NIC_RATE_10M_HALF BIT(8)
+
+-#define AQ_NIC_RATE_EEE_10G BIT(10)
+-#define AQ_NIC_RATE_EEE_5G BIT(11)
+-#define AQ_NIC_RATE_EEE_2G5 BIT(12)
+-#define AQ_NIC_RATE_EEE_1G BIT(13)
+-#define AQ_NIC_RATE_EEE_100M BIT(14)
++#define AQ_NIC_RATE_EEE_10G BIT(9)
++#define AQ_NIC_RATE_EEE_5G BIT(10)
++#define AQ_NIC_RATE_EEE_2G5 BIT(11)
++#define AQ_NIC_RATE_EEE_1G BIT(12)
++#define AQ_NIC_RATE_EEE_100M BIT(13)
+ #define AQ_NIC_RATE_EEE_MSK (AQ_NIC_RATE_EEE_10G |\
+ AQ_NIC_RATE_EEE_5G |\
+ AQ_NIC_RATE_EEE_2G5 |\
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+index bed481816ea31..7442850ca95f0 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+@@ -80,6 +80,8 @@ struct aq_hw_link_status_s {
+ };
+
+ struct aq_stats_s {
++ u64 brc;
++ u64 btc;
+ u64 uprc;
+ u64 mprc;
+ u64 bprc;
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+index 6c049864dac08..9de0065f89b90 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+@@ -903,8 +903,14 @@ u64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
+ data[++i] = stats->mbtc;
+ data[++i] = stats->bbrc;
+ data[++i] = stats->bbtc;
+- data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
+- data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
++ if (stats->brc)
++ data[++i] = stats->brc;
++ else
++ data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
++ if (stats->btc)
++ data[++i] = stats->btc;
++ else
++ data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
+ data[++i] = stats->dma_pkt_rc;
+ data[++i] = stats->dma_pkt_tc;
+ data[++i] = stats->dma_oct_rc;
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+index d4b1976ee69b9..797a95142d1f4 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+@@ -49,6 +49,8 @@ static const struct pci_device_id aq_pci_tbl[] = {
+ { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113), },
+ { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113C), },
+ { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC115C), },
++ { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC113CA), },
++ { PCI_VDEVICE(AQUANTIA, AQ_DEVICE_ID_AQC116C), },
+
+ {}
+ };
+@@ -85,7 +87,10 @@ static const struct aq_board_revision_s hw_atl_boards[] = {
+ { AQ_DEVICE_ID_AQC113CS, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
+ { AQ_DEVICE_ID_AQC114CS, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
+ { AQ_DEVICE_ID_AQC113C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
+- { AQ_DEVICE_ID_AQC115C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
++ { AQ_DEVICE_ID_AQC115C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc115c, },
++ { AQ_DEVICE_ID_AQC113CA, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc113, },
++ { AQ_DEVICE_ID_AQC116C, AQ_HWREV_ANY, &hw_atl2_ops, &hw_atl2_caps_aqc116c, },
++
+ };
+
+ MODULE_DEVICE_TABLE(pci, aq_pci_tbl);
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
+index d281322d7dd29..f4774cf051c97 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
+@@ -362,9 +362,6 @@ unsigned int aq_vec_get_sw_stats(struct aq_vec_s *self, const unsigned int tc, u
+ {
+ unsigned int count;
+
+- WARN_ONCE(!aq_vec_is_valid_tc(self, tc),
+- "Invalid tc %u (#rx=%u, #tx=%u)\n",
+- tc, self->rx_rings, self->tx_rings);
+ if (!aq_vec_is_valid_tc(self, tc))
+ return 0;
+
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+index 404cbf60d3f2f..65b9e5846be45 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+@@ -559,6 +559,11 @@ int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+ 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;
+@@ -567,6 +572,11 @@ int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+
+ 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,
+@@ -857,12 +867,20 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
+ int hw_atl_utils_update_stats(struct aq_hw_s *self)
+ {
+ struct aq_stats_s *cs = &self->curr_stats;
++ struct aq_stats_s curr_stats = *cs;
+ struct hw_atl_utils_mbox mbox;
++ bool corrupted_stats = false;
+
+ hw_atl_utils_mpi_read_stats(self, &mbox);
+
+-#define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
+- mbox.stats._N_ - self->last_stats._N_)
++#define AQ_SDELTA(_N_) \
++do { \
++ if (!corrupted_stats && \
++ ((s64)(mbox.stats._N_ - self->last_stats._N_)) >= 0) \
++ curr_stats._N_ += mbox.stats._N_ - self->last_stats._N_; \
++ else \
++ corrupted_stats = true; \
++} while (0)
+
+ if (self->aq_link_status.mbps) {
+ AQ_SDELTA(uprc);
+@@ -882,6 +900,9 @@ int hw_atl_utils_update_stats(struct aq_hw_s *self)
+ AQ_SDELTA(bbrc);
+ AQ_SDELTA(bbtc);
+ AQ_SDELTA(dpc);
++
++ if (!corrupted_stats)
++ *cs = curr_stats;
+ }
+ #undef AQ_SDELTA
+
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+index ee0c22d049354..05086f0040fd9 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+@@ -132,9 +132,6 @@ static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
+ if (speed & AQ_NIC_RATE_5G)
+ rate |= FW2X_RATE_5G;
+
+- if (speed & AQ_NIC_RATE_5GSR)
+- rate |= FW2X_RATE_5G;
+-
+ if (speed & AQ_NIC_RATE_2G5)
+ rate |= FW2X_RATE_2G5;
+
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+index 92f64048bf691..c76ccdc77ba60 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+@@ -65,11 +65,25 @@ const struct aq_hw_caps_s hw_atl2_caps_aqc113 = {
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2G5 |
+ AQ_NIC_RATE_1G |
+- AQ_NIC_RATE_1G_HALF |
+ AQ_NIC_RATE_100M |
+- AQ_NIC_RATE_100M_HALF |
+- AQ_NIC_RATE_10M |
+- AQ_NIC_RATE_10M_HALF,
++ AQ_NIC_RATE_10M,
++};
++
++const struct aq_hw_caps_s hw_atl2_caps_aqc115c = {
++ DEFAULT_BOARD_BASIC_CAPABILITIES,
++ .media_type = AQ_HW_MEDIA_TYPE_TP,
++ .link_speed_msk = AQ_NIC_RATE_2G5 |
++ AQ_NIC_RATE_1G |
++ AQ_NIC_RATE_100M |
++ AQ_NIC_RATE_10M,
++};
++
++const struct aq_hw_caps_s hw_atl2_caps_aqc116c = {
++ DEFAULT_BOARD_BASIC_CAPABILITIES,
++ .media_type = AQ_HW_MEDIA_TYPE_TP,
++ .link_speed_msk = AQ_NIC_RATE_1G |
++ AQ_NIC_RATE_100M |
++ AQ_NIC_RATE_10M,
+ };
+
+ static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self)
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
+index de8723f1c28a1..346f0dc9912e5 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.h
+@@ -9,6 +9,8 @@
+ #include "aq_common.h"
+
+ extern const struct aq_hw_caps_s hw_atl2_caps_aqc113;
++extern const struct aq_hw_caps_s hw_atl2_caps_aqc115c;
++extern const struct aq_hw_caps_s hw_atl2_caps_aqc116c;
+ extern const struct aq_hw_ops hw_atl2_ops;
+
+ #endif /* HW_ATL2_H */
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
+index b66fa346581ce..6bad64c77b87c 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
+@@ -239,7 +239,8 @@ struct version_s {
+ u8 minor;
+ u16 build;
+ } phy;
+- u32 rsvd;
++ u32 drv_iface_ver:4;
++ u32 rsvd:28;
+ };
+
+ struct link_status_s {
+@@ -424,7 +425,7 @@ struct cable_diag_status_s {
+ u16 rsvd2;
+ };
+
+-struct statistics_s {
++struct statistics_a0_s {
+ struct {
+ u32 link_up;
+ u32 link_down;
+@@ -457,6 +458,33 @@ struct statistics_s {
+ u32 reserve_fw_gap;
+ };
+
++struct __packed statistics_b0_s {
++ u64 rx_good_octets;
++ u64 rx_pause_frames;
++ u64 rx_good_frames;
++ u64 rx_errors;
++ u64 rx_unicast_frames;
++ u64 rx_multicast_frames;
++ u64 rx_broadcast_frames;
++
++ u64 tx_good_octets;
++ u64 tx_pause_frames;
++ u64 tx_good_frames;
++ u64 tx_errors;
++ u64 tx_unicast_frames;
++ u64 tx_multicast_frames;
++ u64 tx_broadcast_frames;
++
++ u32 main_loop_cycles;
++};
++
++struct __packed statistics_s {
++ union __packed {
++ struct statistics_a0_s a0;
++ struct statistics_b0_s b0;
++ };
++};
++
+ struct filter_caps_s {
+ u8 l2_filters_base_index:6;
+ u8 flexible_filter_mask:2;
+@@ -545,7 +573,7 @@ struct management_status_s {
+ u32 rsvd5;
+ };
+
+-struct fw_interface_out {
++struct __packed fw_interface_out {
+ struct transaction_counter_s transaction_id;
+ struct version_s version;
+ struct link_status_s link_status;
+@@ -569,7 +597,6 @@ struct fw_interface_out {
+ struct core_dump_s core_dump;
+ u32 rsvd11;
+ struct statistics_s stats;
+- u32 rsvd12;
+ struct filter_caps_s filter_caps;
+ struct device_caps_s device_caps;
+ u32 rsvd13;
+@@ -592,6 +619,9 @@ struct fw_interface_out {
+ #define AQ_HOST_MODE_LOW_POWER 3U
+ #define AQ_HOST_MODE_SHUTDOWN 4U
+
++#define AQ_A2_FW_INTERFACE_A0 0
++#define AQ_A2_FW_INTERFACE_B0 1
++
+ int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops);
+
+ int hw_atl2_utils_soft_reset(struct aq_hw_s *self);
+diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
+index dd259c8f2f4f3..58d426dda3edb 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
++++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
+@@ -84,7 +84,7 @@ static int hw_atl2_shared_buffer_read_block(struct aq_hw_s *self,
+ if (cnt > AQ_A2_FW_READ_TRY_MAX)
+ return -ETIME;
+ if (tid1.transaction_cnt_a != tid1.transaction_cnt_b)
+- udelay(1);
++ mdelay(1);
+ } while (tid1.transaction_cnt_a != tid1.transaction_cnt_b);
+
+ hw_atl2_mif_shared_buf_read(self, offset, (u32 *)data, dwords);
+@@ -154,7 +154,7 @@ static void a2_link_speed_mask2fw(u32 speed,
+ {
+ link_options->rate_10G = !!(speed & AQ_NIC_RATE_10G);
+ link_options->rate_5G = !!(speed & AQ_NIC_RATE_5G);
+- link_options->rate_N5G = !!(speed & AQ_NIC_RATE_5GSR);
++ link_options->rate_N5G = link_options->rate_5G;
+ link_options->rate_2P5G = !!(speed & AQ_NIC_RATE_2G5);
+ link_options->rate_N2P5G = link_options->rate_2P5G;
+ link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G);
+@@ -192,8 +192,6 @@ static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps)
+ rate |= AQ_NIC_RATE_10G;
+ if (lkp_link_caps->rate_5G)
+ rate |= AQ_NIC_RATE_5G;
+- if (lkp_link_caps->rate_N5G)
+- rate |= AQ_NIC_RATE_5GSR;
+ if (lkp_link_caps->rate_2P5G)
+ rate |= AQ_NIC_RATE_2G5;
+ if (lkp_link_caps->rate_1G)
+@@ -335,15 +333,22 @@ static int aq_a2_fw_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
+ return 0;
+ }
+
+-static int aq_a2_fw_update_stats(struct aq_hw_s *self)
++static void aq_a2_fill_a0_stats(struct aq_hw_s *self,
++ struct statistics_s *stats)
+ {
+ struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
+- struct statistics_s stats;
+-
+- hw_atl2_shared_buffer_read_safe(self, stats, &stats);
+-
+-#define AQ_SDELTA(_N_, _F_) (self->curr_stats._N_ += \
+- stats.msm._F_ - priv->last_stats.msm._F_)
++ struct aq_stats_s *cs = &self->curr_stats;
++ struct aq_stats_s curr_stats = *cs;
++ bool corrupted_stats = false;
++
++#define AQ_SDELTA(_N, _F) \
++do { \
++ if (!corrupted_stats && \
++ ((s64)(stats->a0.msm._F - priv->last_stats.a0.msm._F)) >= 0) \
++ curr_stats._N += stats->a0.msm._F - priv->last_stats.a0.msm._F;\
++ else \
++ corrupted_stats = true; \
++} while (0)
+
+ if (self->aq_link_status.mbps) {
+ AQ_SDELTA(uprc, rx_unicast_frames);
+@@ -362,17 +367,76 @@ static int aq_a2_fw_update_stats(struct aq_hw_s *self)
+ AQ_SDELTA(mbtc, tx_multicast_octets);
+ AQ_SDELTA(bbrc, rx_broadcast_octets);
+ AQ_SDELTA(bbtc, tx_broadcast_octets);
++
++ if (!corrupted_stats)
++ *cs = curr_stats;
+ }
+ #undef AQ_SDELTA
+- self->curr_stats.dma_pkt_rc =
+- hw_atl_stats_rx_dma_good_pkt_counter_get(self);
+- self->curr_stats.dma_pkt_tc =
+- hw_atl_stats_tx_dma_good_pkt_counter_get(self);
+- self->curr_stats.dma_oct_rc =
+- hw_atl_stats_rx_dma_good_octet_counter_get(self);
+- self->curr_stats.dma_oct_tc =
+- hw_atl_stats_tx_dma_good_octet_counter_get(self);
+- self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
++
++}
++
++static void aq_a2_fill_b0_stats(struct aq_hw_s *self,
++ struct statistics_s *stats)
++{
++ struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
++ struct aq_stats_s *cs = &self->curr_stats;
++ struct aq_stats_s curr_stats = *cs;
++ bool corrupted_stats = false;
++
++#define AQ_SDELTA(_N, _F) \
++do { \
++ if (!corrupted_stats && \
++ ((s64)(stats->b0._F - priv->last_stats.b0._F)) >= 0) \
++ curr_stats._N += stats->b0._F - priv->last_stats.b0._F; \
++ else \
++ corrupted_stats = true; \
++} while (0)
++
++ if (self->aq_link_status.mbps) {
++ AQ_SDELTA(uprc, rx_unicast_frames);
++ AQ_SDELTA(mprc, rx_multicast_frames);
++ AQ_SDELTA(bprc, rx_broadcast_frames);
++ AQ_SDELTA(erpr, rx_errors);
++ AQ_SDELTA(brc, rx_good_octets);
++
++ AQ_SDELTA(uptc, tx_unicast_frames);
++ AQ_SDELTA(mptc, tx_multicast_frames);
++ AQ_SDELTA(bptc, tx_broadcast_frames);
++ AQ_SDELTA(erpt, tx_errors);
++ AQ_SDELTA(btc, tx_good_octets);
++
++ if (!corrupted_stats)
++ *cs = curr_stats;
++ }
++#undef AQ_SDELTA
++}
++
++static int aq_a2_fw_update_stats(struct aq_hw_s *self)
++{
++ struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
++ struct aq_stats_s *cs = &self->curr_stats;
++ struct statistics_s stats;
++ struct version_s version;
++ int err;
++
++ err = hw_atl2_shared_buffer_read_safe(self, version, &version);
++ if (err)
++ return err;
++
++ err = hw_atl2_shared_buffer_read_safe(self, stats, &stats);
++ if (err)
++ return err;
++
++ if (version.drv_iface_ver == AQ_A2_FW_INTERFACE_A0)
++ aq_a2_fill_a0_stats(self, &stats);
++ else
++ aq_a2_fill_b0_stats(self, &stats);
++
++ cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
++ cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
++ cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
++ cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
++ cs->dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
+
+ memcpy(&priv->last_stats, &stats, sizeof(stats));
+
+@@ -499,9 +563,9 @@ u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self)
+ hw_atl2_shared_buffer_read_safe(self, version, &version);
+
+ /* A2 FW version is stored in reverse order */
+- return version.mac.major << 24 |
+- version.mac.minor << 16 |
+- version.mac.build;
++ return version.bundle.major << 24 |
++ version.bundle.minor << 16 |
++ version.bundle.build;
+ }
+
+ int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self,
+diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
+index 02a569500234c..376f81796a293 100644
+--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
++++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
+@@ -708,7 +708,9 @@ static int bcm4908_enet_probe(struct platform_device *pdev)
+
+ enet->irq_tx = platform_get_irq_byname(pdev, "tx");
+
+- dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
++ err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
++ if (err)
++ return err;
+
+ err = bcm4908_enet_dma_alloc(enet);
+ if (err)
+diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
+index 7fa1b695400d7..0877b3d7f88c5 100644
+--- a/drivers/net/ethernet/broadcom/bcmsysport.c
++++ b/drivers/net/ethernet/broadcom/bcmsysport.c
+@@ -1309,11 +1309,11 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
+ 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;
+@@ -1373,8 +1373,10 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
+ 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)
+@@ -2013,6 +2015,7 @@ static int bcm_sysport_open(struct net_device *dev)
+ }
+
+ /* 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) {
+diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
+index 984f76e74b43e..16b73bb9acc78 100644
+--- a/drivers/net/ethernet/broadcom/bcmsysport.h
++++ b/drivers/net/ethernet/broadcom/bcmsysport.h
+@@ -711,6 +711,7 @@ struct bcm_sysport_priv {
+ int wol_irq;
+
+ /* Transmit rings */
++ spinlock_t desc_lock;
+ struct bcm_sysport_tx_ring *tx_rings;
+
+ /* Receive queue */
+diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
+index 1835d2e451c01..fc7fce642666c 100644
+--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
+@@ -635,11 +635,13 @@ static int bnx2x_ilt_client_mem_op(struct bnx2x *bp, int cli_num,
+ {
+ 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;
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 62f84cc91e4d1..0fba01db336cc 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -13370,7 +13370,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ }
+
+ bnxt_inv_fw_health_reg(bp);
+- bnxt_dl_register(bp);
++ rc = bnxt_dl_register(bp);
++ if (rc)
++ goto init_err_dl;
+
+ rc = register_netdev(dev);
+ if (rc)
+@@ -13390,6 +13392,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+
+ init_err_cleanup:
+ bnxt_dl_unregister(bp);
++init_err_dl:
+ bnxt_shutdown_tc(bp);
+ bnxt_clear_int_mode(bp);
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+index 9576547df4aba..2a80882971e3d 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+@@ -134,7 +134,7 @@ void bnxt_dl_fw_reporters_create(struct bnxt *bp)
+ {
+ struct bnxt_fw_health *health = bp->fw_health;
+
+- if (!bp->dl || !health)
++ if (!health)
+ return;
+
+ if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
+@@ -188,7 +188,7 @@ void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
+ {
+ struct bnxt_fw_health *health = bp->fw_health;
+
+- if (!bp->dl || !health)
++ if (!health)
+ return;
+
+ if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
+@@ -781,6 +781,7 @@ int bnxt_dl_register(struct bnxt *bp)
+ {
+ const struct devlink_ops *devlink_ops;
+ struct devlink_port_attrs attrs = {};
++ struct bnxt_dl *bp_dl;
+ struct devlink *dl;
+ int rc;
+
+@@ -795,7 +796,9 @@ int bnxt_dl_register(struct bnxt *bp)
+ return -ENOMEM;
+ }
+
+- bnxt_link_bp_to_dl(bp, dl);
++ bp->dl = dl;
++ bp_dl = devlink_priv(dl);
++ bp_dl->bp = bp;
+
+ /* Add switchdev eswitch mode setting, if SRIOV supported */
+ if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
+@@ -833,7 +836,6 @@ err_dl_port_unreg:
+ err_dl_unreg:
+ devlink_unregister(dl);
+ err_dl_free:
+- bnxt_link_bp_to_dl(bp, NULL);
+ devlink_free(dl);
+ return rc;
+ }
+@@ -842,9 +844,6 @@ void bnxt_dl_unregister(struct bnxt *bp)
+ {
+ struct devlink *dl = bp->dl;
+
+- if (!dl)
+- return;
+-
+ if (BNXT_PF(bp)) {
+ bnxt_dl_params_unregister(bp);
+ devlink_port_unregister(&bp->dl_port);
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
+index d889f240da2b2..406dc655a5fc9 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
+@@ -20,19 +20,6 @@ static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
+ return ((struct bnxt_dl *)devlink_priv(dl))->bp;
+ }
+
+-/* To clear devlink pointer from bp, pass NULL dl */
+-static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl)
+-{
+- bp->dl = dl;
+-
+- /* add a back pointer in dl to bp */
+- if (dl) {
+- struct bnxt_dl *bp_dl = devlink_priv(dl);
+-
+- bp_dl->bp = bp;
+- }
+-}
+-
+ #define NVM_OFF_MSIX_VEC_PER_PF_MAX 108
+ #define NVM_OFF_MSIX_VEC_PER_PF_MIN 114
+ #define NVM_OFF_IGNORE_ARI 164
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+index e6a4a768b10b2..1471b6130a2b9 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+@@ -1868,7 +1868,7 @@ static int bnxt_tc_setup_indr_block_cb(enum tc_setup_type type,
+ struct flow_cls_offload *flower = type_data;
+ struct bnxt *bp = priv->bp;
+
+- if (flower->common.chain_index)
++ if (!tc_cls_can_offload_and_chain0(bp->dev, type_data))
+ return -EOPNOTSUPP;
+
+ switch (type) {
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+index 5903bdb78916f..129352bbe1143 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+@@ -2015,12 +2015,15 @@ static int cxgb4_get_module_info(struct net_device *dev,
+ 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;
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+index 002fc62ea7262..63bc956d20376 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+@@ -293,6 +293,8 @@ enum {
+ #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
+diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
+index bcad69c480740..4af5561cbfc54 100644
+--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
++++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
+@@ -870,7 +870,7 @@ static void do_abort_syn_rcv(struct sock *child, struct sock *parent)
+ * created only after 3 way handshake is done.
+ */
+ sock_orphan(child);
+- percpu_counter_inc((child)->sk_prot->orphan_count);
++ INC_ORPHAN_COUNT(child);
+ chtls_release_resources(child);
+ chtls_conn_done(child);
+ } else {
+diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
+index b1161bdeda4dc..f61ca657601ca 100644
+--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
++++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
+@@ -95,7 +95,7 @@ struct deferred_skb_cb {
+ #define WSCALE_OK(tp) ((tp)->rx_opt.wscale_ok)
+ #define TSTAMP_OK(tp) ((tp)->rx_opt.tstamp_ok)
+ #define SACK_OK(tp) ((tp)->rx_opt.sack_ok)
+-#define INC_ORPHAN_COUNT(sk) percpu_counter_inc((sk)->sk_prot->orphan_count)
++#define INC_ORPHAN_COUNT(sk) this_cpu_inc(*(sk)->sk_prot->orphan_count)
+
+ /* TLS SKB */
+ #define skb_ulp_tls_inline(skb) (ULP_SKB_CB(skb)->ulp.tls.ofld)
+diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
+index 36ab4cbf2ad08..b9d967e419387 100644
+--- a/drivers/net/ethernet/dec/tulip/de4x5.c
++++ b/drivers/net/ethernet/dec/tulip/de4x5.c
+@@ -4708,6 +4708,10 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p)
+ 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;
+@@ -4999,19 +5003,23 @@ mii_get_phy(struct net_device *dev)
+ }
+ 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:
+diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
+index 85b99099c6b94..5babcf05bc2f1 100644
+--- a/drivers/net/ethernet/dec/tulip/winbond-840.c
++++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
+@@ -877,7 +877,7 @@ static void init_registers(struct net_device *dev)
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords */
+
+-#if defined (__i386__) && !defined(MODULE)
++#if defined (__i386__) && !defined(MODULE) && !defined(CONFIG_UML)
+ /* When not a module we can work around broken '486 PCI boards. */
+ if (boot_cpu_data.x86 <= 4) {
+ i |= 0x4800;
+diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c
+index 25c91b3c5fd30..819266d463b07 100644
+--- a/drivers/net/ethernet/fealnx.c
++++ b/drivers/net/ethernet/fealnx.c
+@@ -857,7 +857,7 @@ static int netdev_open(struct net_device *dev)
+ np->bcrvalue |= 0x04; /* big-endian */
+ #endif
+
+-#if defined(__i386__) && !defined(MODULE)
++#if defined(__i386__) && !defined(MODULE) && !defined(CONFIG_UML)
+ if (boot_cpu_data.x86 <= 4)
+ np->crvalue = 0xa00;
+ else
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+index 7065c71ed7b86..1108e1730841b 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -4538,10 +4538,12 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
+
+ fsl_mc_portal_free(priv->mc_io);
+
+- free_netdev(net_dev);
++ destroy_workqueue(priv->dpaa2_ptp_wq);
+
+ dev_dbg(net_dev->dev.parent, "Removed interface %s\n", net_dev->name);
+
++ free_netdev(net_dev);
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+index 4577226d3c6ad..0536d2c76fbc4 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+@@ -486,14 +486,16 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
+
+ data_size = sizeof(struct streamid_data);
+ si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
++ if (!si_data)
++ return -ENOMEM;
+ cbd.length = cpu_to_le16(data_size);
+
+ dma = dma_map_single(&priv->si->pdev->dev, si_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+- kfree(si_data);
+- return -ENOMEM;
++ err = -ENOMEM;
++ goto out;
+ }
+
+ cbd.addr[0] = cpu_to_le32(lower_32_bits(dma));
+@@ -512,12 +514,10 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
+
+ err = enetc_send_cmd(priv->si, &cbd);
+ if (err)
+- return -EINVAL;
++ goto out;
+
+- if (!enable) {
+- kfree(si_data);
+- return 0;
+- }
++ if (!enable)
++ goto out;
+
+ /* Enable the entry overwrite again incase space flushed by hardware */
+ memset(&cbd, 0, sizeof(cbd));
+@@ -560,6 +560,10 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
+ }
+
+ err = enetc_send_cmd(priv->si, &cbd);
++out:
++ if (!dma_mapping_error(&priv->si->pdev->dev, dma))
++ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE);
++
+ kfree(si_data);
+
+ return err;
+diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
+index 7b4961daa2540..ed7301b691694 100644
+--- a/drivers/net/ethernet/freescale/fec.h
++++ b/drivers/net/ethernet/freescale/fec.h
+@@ -377,6 +377,9 @@ struct bufdesc_ex {
+ #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)
+
+diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
+index ec87b370bba1f..a3e87e10ee6bd 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -1480,7 +1480,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
+ 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;
+diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
+index 92dc18a4bcc41..c1d4042671f9f 100644
+--- a/drivers/net/ethernet/google/gve/gve.h
++++ b/drivers/net/ethernet/google/gve/gve.h
+@@ -30,7 +30,7 @@
+ #define GVE_MIN_MSIX 3
+
+ /* Numbers of gve tx/rx stats in stats report. */
+-#define GVE_TX_STATS_REPORT_NUM 5
++#define GVE_TX_STATS_REPORT_NUM 6
+ #define GVE_RX_STATS_REPORT_NUM 2
+
+ /* Interval to schedule a stats report update, 20000ms. */
+@@ -224,11 +224,6 @@ struct gve_tx_iovec {
+ u32 iov_padding; /* padding associated with this segment */
+ };
+
+-struct gve_tx_dma_buf {
+- DEFINE_DMA_UNMAP_ADDR(dma);
+- DEFINE_DMA_UNMAP_LEN(len);
+-};
+-
+ /* Tracks the memory in the fifo occupied by the skb. Mapped 1:1 to a desc
+ * ring entry but only used for a pkt_desc not a seg_desc
+ */
+@@ -236,7 +231,10 @@ struct gve_tx_buffer_state {
+ struct sk_buff *skb; /* skb for this pkt */
+ union {
+ struct gve_tx_iovec iov[GVE_TX_MAX_IOVEC]; /* segments of this pkt */
+- struct gve_tx_dma_buf buf;
++ struct {
++ DEFINE_DMA_UNMAP_ADDR(dma);
++ DEFINE_DMA_UNMAP_LEN(len);
++ };
+ };
+ };
+
+@@ -280,7 +278,8 @@ struct gve_tx_pending_packet_dqo {
+ * All others correspond to `skb`'s frags and should be unmapped with
+ * `dma_unmap_page`.
+ */
+- struct gve_tx_dma_buf bufs[MAX_SKB_FRAGS + 1];
++ DEFINE_DMA_UNMAP_ADDR(dma[MAX_SKB_FRAGS + 1]);
++ DEFINE_DMA_UNMAP_LEN(len[MAX_SKB_FRAGS + 1]);
+ u16 num_bufs;
+
+ /* Linked list index to next element in the list, or -1 if none */
+@@ -414,7 +413,9 @@ struct gve_tx_ring {
+ u32 q_num ____cacheline_aligned; /* queue idx */
+ u32 stop_queue; /* count of queue stops */
+ u32 wake_queue; /* count of queue wakes */
++ u32 queue_timeout; /* count of queue timeouts */
+ u32 ntfy_id; /* notification block index */
++ u32 last_kick_msec; /* Last time the queue was kicked */
+ dma_addr_t bus; /* dma address of the descr ring */
+ dma_addr_t q_resources_bus; /* dma address of the queue resources */
+ dma_addr_t complq_bus_dqo; /* dma address of the dqo.compl_ring */
+diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
+index 47c3d8f313fcf..3953f6f7a4273 100644
+--- a/drivers/net/ethernet/google/gve/gve_adminq.h
++++ b/drivers/net/ethernet/google/gve/gve_adminq.h
+@@ -270,6 +270,7 @@ enum gve_stat_names {
+ TX_LAST_COMPLETION_PROCESSED = 5,
+ RX_NEXT_EXPECTED_SEQUENCE = 6,
+ RX_BUFFERS_POSTED = 7,
++ TX_TIMEOUT_CNT = 8,
+ // stats from NIC
+ RX_QUEUE_DROP_CNT = 65,
+ RX_NO_BUFFERS_POSTED = 66,
+diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
+index bf8a4a7c43f78..959352fceead7 100644
+--- a/drivers/net/ethernet/google/gve/gve_main.c
++++ b/drivers/net/ethernet/google/gve/gve_main.c
+@@ -24,6 +24,9 @@
+ #define GVE_VERSION "1.0.0"
+ #define GVE_VERSION_PREFIX "GVE-"
+
++// Minimum amount of time between queue kicks in msec (10 seconds)
++#define MIN_TX_TIMEOUT_GAP (1000 * 10)
++
+ const char gve_version_str[] = GVE_VERSION;
+ static const char gve_version_prefix[] = GVE_VERSION_PREFIX;
+
+@@ -1116,9 +1119,47 @@ static void gve_turnup(struct gve_priv *priv)
+
+ static void gve_tx_timeout(struct net_device *dev, unsigned int txqueue)
+ {
+- struct gve_priv *priv = netdev_priv(dev);
++ struct gve_notify_block *block;
++ struct gve_tx_ring *tx = NULL;
++ struct gve_priv *priv;
++ u32 last_nic_done;
++ u32 current_time;
++ u32 ntfy_idx;
++
++ netdev_info(dev, "Timeout on tx queue, %d", txqueue);
++ priv = netdev_priv(dev);
++ if (txqueue > priv->tx_cfg.num_queues)
++ goto reset;
++
++ ntfy_idx = gve_tx_idx_to_ntfy(priv, txqueue);
++ if (ntfy_idx >= priv->num_ntfy_blks)
++ goto reset;
++
++ block = &priv->ntfy_blocks[ntfy_idx];
++ tx = block->tx;
+
++ current_time = jiffies_to_msecs(jiffies);
++ if (tx->last_kick_msec + MIN_TX_TIMEOUT_GAP > current_time)
++ goto reset;
++
++ /* Check to see if there are missed completions, which will allow us to
++ * kick the queue.
++ */
++ last_nic_done = gve_tx_load_event_counter(priv, tx);
++ if (last_nic_done - tx->done) {
++ netdev_info(dev, "Kicking queue %d", txqueue);
++ iowrite32be(GVE_IRQ_MASK, gve_irq_doorbell(priv, block));
++ napi_schedule(&block->napi);
++ tx->last_kick_msec = current_time;
++ goto out;
++ } // Else reset.
++
++reset:
+ gve_schedule_reset(priv);
++
++out:
++ if (tx)
++ tx->queue_timeout++;
+ priv->tx_timeo_cnt++;
+ }
+
+@@ -1247,6 +1288,11 @@ void gve_handle_report_stats(struct gve_priv *priv)
+ .value = cpu_to_be64(last_completion),
+ .queue_id = cpu_to_be32(idx),
+ };
++ stats[stats_idx++] = (struct stats) {
++ .stat_name = cpu_to_be32(TX_TIMEOUT_CNT),
++ .value = cpu_to_be64(priv->tx[idx].queue_timeout),
++ .queue_id = cpu_to_be32(idx),
++ };
+ }
+ }
+ /* rx stats */
+diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
+index 94941d4e47449..16169f291ad9f 100644
+--- a/drivers/net/ethernet/google/gve/gve_rx.c
++++ b/drivers/net/ethernet/google/gve/gve_rx.c
+@@ -514,8 +514,13 @@ static bool gve_rx_refill_buffers(struct gve_priv *priv, struct gve_rx_ring *rx)
+
+ gve_rx_free_buffer(dev, page_info, data_slot);
+ page_info->page = NULL;
+- if (gve_rx_alloc_buffer(priv, dev, page_info, data_slot))
++ if (gve_rx_alloc_buffer(priv, dev, page_info,
++ data_slot)) {
++ u64_stats_update_begin(&rx->statss);
++ rx->rx_buf_alloc_fail++;
++ u64_stats_update_end(&rx->statss);
+ break;
++ }
+ }
+ }
+ fill_cnt++;
+diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c
+index 665ac795a1adf..9922ce46a6351 100644
+--- a/drivers/net/ethernet/google/gve/gve_tx.c
++++ b/drivers/net/ethernet/google/gve/gve_tx.c
+@@ -303,15 +303,15 @@ static inline int gve_skb_fifo_bytes_required(struct gve_tx_ring *tx,
+ static void gve_tx_unmap_buf(struct device *dev, struct gve_tx_buffer_state *info)
+ {
+ if (info->skb) {
+- dma_unmap_single(dev, dma_unmap_addr(&info->buf, dma),
+- dma_unmap_len(&info->buf, len),
++ dma_unmap_single(dev, dma_unmap_addr(info, dma),
++ dma_unmap_len(info, len),
+ DMA_TO_DEVICE);
+- dma_unmap_len_set(&info->buf, len, 0);
++ dma_unmap_len_set(info, len, 0);
+ } else {
+- dma_unmap_page(dev, dma_unmap_addr(&info->buf, dma),
+- dma_unmap_len(&info->buf, len),
++ dma_unmap_page(dev, dma_unmap_addr(info, dma),
++ dma_unmap_len(info, len),
+ DMA_TO_DEVICE);
+- dma_unmap_len_set(&info->buf, len, 0);
++ dma_unmap_len_set(info, len, 0);
+ }
+ }
+
+@@ -491,7 +491,6 @@ static int gve_tx_add_skb_no_copy(struct gve_priv *priv, struct gve_tx_ring *tx,
+ struct gve_tx_buffer_state *info;
+ bool is_gso = skb_is_gso(skb);
+ u32 idx = tx->req & tx->mask;
+- struct gve_tx_dma_buf *buf;
+ u64 addr;
+ u32 len;
+ int i;
+@@ -515,9 +514,8 @@ static int gve_tx_add_skb_no_copy(struct gve_priv *priv, struct gve_tx_ring *tx,
+ tx->dma_mapping_error++;
+ goto drop;
+ }
+- buf = &info->buf;
+- dma_unmap_len_set(buf, len, len);
+- dma_unmap_addr_set(buf, dma, addr);
++ dma_unmap_len_set(info, len, len);
++ dma_unmap_addr_set(info, dma, addr);
+
+ payload_nfrags = shinfo->nr_frags;
+ if (hlen < len) {
+@@ -549,10 +547,9 @@ static int gve_tx_add_skb_no_copy(struct gve_priv *priv, struct gve_tx_ring *tx,
+ tx->dma_mapping_error++;
+ goto unmap_drop;
+ }
+- buf = &tx->info[idx].buf;
+ tx->info[idx].skb = NULL;
+- dma_unmap_len_set(buf, len, len);
+- dma_unmap_addr_set(buf, dma, addr);
++ dma_unmap_len_set(&tx->info[idx], len, len);
++ dma_unmap_addr_set(&tx->info[idx], dma, addr);
+
+ gve_tx_fill_seg_desc(seg_desc, skb, is_gso, len, addr);
+ }
+diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+index 05ddb6a75c38f..ec394d9916681 100644
+--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
++++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+@@ -85,18 +85,16 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)
+ int j;
+
+ for (j = 0; j < cur_state->num_bufs; j++) {
+- struct gve_tx_dma_buf *buf = &cur_state->bufs[j];
+-
+ if (j == 0) {
+ dma_unmap_single(tx->dev,
+- dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len),
+- DMA_TO_DEVICE);
++ dma_unmap_addr(cur_state, dma[j]),
++ dma_unmap_len(cur_state, len[j]),
++ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(tx->dev,
+- dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len),
+- DMA_TO_DEVICE);
++ dma_unmap_addr(cur_state, dma[j]),
++ dma_unmap_len(cur_state, len[j]),
++ DMA_TO_DEVICE);
+ }
+ }
+ if (cur_state->skb) {
+@@ -457,15 +455,15 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ const bool is_gso = skb_is_gso(skb);
+ u32 desc_idx = tx->dqo_tx.tail;
+
+- struct gve_tx_pending_packet_dqo *pending_packet;
++ struct gve_tx_pending_packet_dqo *pkt;
+ struct gve_tx_metadata_dqo metadata;
+ s16 completion_tag;
+ int i;
+
+- pending_packet = gve_alloc_pending_packet(tx);
+- pending_packet->skb = skb;
+- pending_packet->num_bufs = 0;
+- completion_tag = pending_packet - tx->dqo.pending_packets;
++ pkt = gve_alloc_pending_packet(tx);
++ pkt->skb = skb;
++ pkt->num_bufs = 0;
++ completion_tag = pkt - tx->dqo.pending_packets;
+
+ gve_extract_tx_metadata_dqo(skb, &metadata);
+ if (is_gso) {
+@@ -493,8 +491,6 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+
+ /* Map the linear portion of skb */
+ {
+- struct gve_tx_dma_buf *buf =
+- &pending_packet->bufs[pending_packet->num_bufs];
+ u32 len = skb_headlen(skb);
+ dma_addr_t addr;
+
+@@ -502,9 +498,9 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ if (unlikely(dma_mapping_error(tx->dev, addr)))
+ goto err;
+
+- dma_unmap_len_set(buf, len, len);
+- dma_unmap_addr_set(buf, dma, addr);
+- ++pending_packet->num_bufs;
++ dma_unmap_len_set(pkt, len[pkt->num_bufs], len);
++ dma_unmap_addr_set(pkt, dma[pkt->num_bufs], addr);
++ ++pkt->num_bufs;
+
+ gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ completion_tag,
+@@ -512,8 +508,6 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ }
+
+ for (i = 0; i < shinfo->nr_frags; i++) {
+- struct gve_tx_dma_buf *buf =
+- &pending_packet->bufs[pending_packet->num_bufs];
+ const skb_frag_t *frag = &shinfo->frags[i];
+ bool is_eop = i == (shinfo->nr_frags - 1);
+ u32 len = skb_frag_size(frag);
+@@ -523,9 +517,9 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ if (unlikely(dma_mapping_error(tx->dev, addr)))
+ goto err;
+
+- dma_unmap_len_set(buf, len, len);
+- dma_unmap_addr_set(buf, dma, addr);
+- ++pending_packet->num_bufs;
++ dma_unmap_len_set(pkt, len[pkt->num_bufs], len);
++ dma_unmap_addr_set(pkt, dma[pkt->num_bufs], addr);
++ ++pkt->num_bufs;
+
+ gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ completion_tag, is_eop, is_gso);
+@@ -552,22 +546,23 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ return 0;
+
+ err:
+- for (i = 0; i < pending_packet->num_bufs; i++) {
+- struct gve_tx_dma_buf *buf = &pending_packet->bufs[i];
+-
++ for (i = 0; i < pkt->num_bufs; i++) {
+ if (i == 0) {
+- dma_unmap_single(tx->dev, dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len),
++ dma_unmap_single(tx->dev,
++ dma_unmap_addr(pkt, dma[i]),
++ dma_unmap_len(pkt, len[i]),
+ DMA_TO_DEVICE);
+ } else {
+- dma_unmap_page(tx->dev, dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len), DMA_TO_DEVICE);
++ dma_unmap_page(tx->dev,
++ dma_unmap_addr(pkt, dma[i]),
++ dma_unmap_len(pkt, len[i]),
++ DMA_TO_DEVICE);
+ }
+ }
+
+- pending_packet->skb = NULL;
+- pending_packet->num_bufs = 0;
+- gve_free_pending_packet(tx, pending_packet);
++ pkt->skb = NULL;
++ pkt->num_bufs = 0;
++ gve_free_pending_packet(tx, pkt);
+
+ return -1;
+ }
+@@ -725,12 +720,12 @@ static void add_to_list(struct gve_tx_ring *tx, struct gve_index_list *list,
+
+ static void remove_from_list(struct gve_tx_ring *tx,
+ struct gve_index_list *list,
+- struct gve_tx_pending_packet_dqo *pending_packet)
++ struct gve_tx_pending_packet_dqo *pkt)
+ {
+ s16 prev_index, next_index;
+
+- prev_index = pending_packet->prev;
+- next_index = pending_packet->next;
++ prev_index = pkt->prev;
++ next_index = pkt->next;
+
+ if (prev_index == -1) {
+ /* Node is head */
+@@ -747,21 +742,18 @@ static void remove_from_list(struct gve_tx_ring *tx,
+ }
+
+ static void gve_unmap_packet(struct device *dev,
+- struct gve_tx_pending_packet_dqo *pending_packet)
++ struct gve_tx_pending_packet_dqo *pkt)
+ {
+- struct gve_tx_dma_buf *buf;
+ int i;
+
+ /* SKB linear portion is guaranteed to be mapped */
+- buf = &pending_packet->bufs[0];
+- dma_unmap_single(dev, dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len), DMA_TO_DEVICE);
+- for (i = 1; i < pending_packet->num_bufs; i++) {
+- buf = &pending_packet->bufs[i];
+- dma_unmap_page(dev, dma_unmap_addr(buf, dma),
+- dma_unmap_len(buf, len), DMA_TO_DEVICE);
++ dma_unmap_single(dev, dma_unmap_addr(pkt, dma[0]),
++ dma_unmap_len(pkt, len[0]), DMA_TO_DEVICE);
++ for (i = 1; i < pkt->num_bufs; i++) {
++ dma_unmap_page(dev, dma_unmap_addr(pkt, dma[i]),
++ dma_unmap_len(pkt, len[i]), DMA_TO_DEVICE);
+ }
+- pending_packet->num_bufs = 0;
++ pkt->num_bufs = 0;
+ }
+
+ /* Completion types and expected behavior:
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+index 23d9cbf262c32..740850b64aff5 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+@@ -400,6 +400,10 @@ static void hns_dsaf_ge_srst_by_port(struct dsaf_device *dsaf_dev, u32 port,
+ 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.*/
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+index d701451596c82..47bba4c62f040 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
++++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+@@ -830,6 +830,8 @@ struct hnae3_handle {
+
+ u8 netdev_flags;
+ struct dentry *hnae3_dbgfs;
++ /* protects concurrent contention between debugfs commands */
++ struct mutex dbgfs_lock;
+
+ /* Network interface message level enabled bits */
+ u32 msg_enable;
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+index e54f96251fea9..3205849bdb95b 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+@@ -1021,6 +1021,7 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
+ if (ret)
+ return ret;
+
++ mutex_lock(&handle->dbgfs_lock);
+ save_buf = &hns3_dbg_cmd[index].buf;
+
+ if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
+@@ -1033,15 +1034,15 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
+ read_buf = *save_buf;
+ } else {
+ read_buf = kvzalloc(hns3_dbg_cmd[index].buf_len, GFP_KERNEL);
+- if (!read_buf)
+- return -ENOMEM;
++ if (!read_buf) {
++ ret = -ENOMEM;
++ goto out;
++ }
+
+ /* save the buffer addr until the last read operation */
+ *save_buf = read_buf;
+- }
+
+- /* get data ready for the first time to read */
+- if (!*ppos) {
++ /* get data ready for the first time to read */
+ ret = hns3_dbg_read_cmd(dbg_data, hns3_dbg_cmd[index].cmd,
+ read_buf, hns3_dbg_cmd[index].buf_len);
+ if (ret)
+@@ -1050,8 +1051,10 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
+
+ size = simple_read_from_buffer(buffer, count, ppos, read_buf,
+ strlen(read_buf));
+- if (size > 0)
++ if (size > 0) {
++ mutex_unlock(&handle->dbgfs_lock);
+ return size;
++ }
+
+ out:
+ /* free the buffer for the last read operation */
+@@ -1060,6 +1063,7 @@ out:
+ *save_buf = NULL;
+ }
+
++ mutex_unlock(&handle->dbgfs_lock);
+ return ret;
+ }
+
+@@ -1132,6 +1136,8 @@ int hns3_dbg_init(struct hnae3_handle *handle)
+ debugfs_create_dir(hns3_dbg_dentry[i].name,
+ handle->hnae3_dbgfs);
+
++ mutex_init(&handle->dbgfs_lock);
++
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
+ if ((hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
+ ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2) ||
+@@ -1158,6 +1164,7 @@ int hns3_dbg_init(struct hnae3_handle *handle)
+ return 0;
+
+ out:
++ mutex_destroy(&handle->dbgfs_lock);
+ debugfs_remove_recursive(handle->hnae3_dbgfs);
+ handle->hnae3_dbgfs = NULL;
+ return ret;
+@@ -1173,6 +1180,7 @@ void hns3_dbg_uninit(struct hnae3_handle *handle)
+ hns3_dbg_cmd[i].buf = NULL;
+ }
+
++ mutex_destroy(&handle->dbgfs_lock);
+ debugfs_remove_recursive(handle->hnae3_dbgfs);
+ handle->hnae3_dbgfs = NULL;
+ }
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+index 5ebd96f6833d6..526fb56c84f24 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+@@ -985,6 +985,7 @@ static int hns3_set_reset(struct net_device *netdev, u32 *flags)
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
+ const struct hnae3_ae_ops *ops = h->ae_algo->ops;
+ const struct hns3_reset_type_map *rst_type_map;
++ enum ethtool_reset_flags rst_flags;
+ u32 i, size;
+
+ if (ops->ae_dev_resetting && ops->ae_dev_resetting(h))
+@@ -1004,6 +1005,7 @@ static int hns3_set_reset(struct net_device *netdev, u32 *flags)
+ for (i = 0; i < size; i++) {
+ if (rst_type_map[i].rst_flags == *flags) {
+ rst_type = rst_type_map[i].rst_type;
++ rst_flags = rst_type_map[i].rst_flags;
+ break;
+ }
+ }
+@@ -1019,6 +1021,8 @@ static int hns3_set_reset(struct net_device *netdev, u32 *flags)
+
+ ops->reset_event(h->pdev, h);
+
++ *flags &= ~rst_flags;
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
+index 91cb578f56b80..375ebf105a9aa 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
+@@ -129,7 +129,7 @@ static int hclge_ets_sch_mode_validate(struct hclge_dev *hdev,
+ u32 total_ets_bw = 0;
+ u8 i;
+
+- 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 !=
+@@ -286,28 +286,24 @@ err_out:
+
+ static int hclge_ieee_getpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
+ {
+- u64 requests[HNAE3_MAX_TC], indications[HNAE3_MAX_TC];
+ struct hclge_vport *vport = hclge_get_vport(h);
+ struct hclge_dev *hdev = vport->back;
+ int ret;
+- u8 i;
+
+ memset(pfc, 0, sizeof(*pfc));
+ pfc->pfc_cap = hdev->pfc_max;
+ pfc->pfc_en = hdev->tm_info.pfc_en;
+
+- ret = hclge_pfc_tx_stats_get(hdev, requests);
+- if (ret)
++ ret = hclge_mac_update_stats(hdev);
++ if (ret) {
++ dev_err(&hdev->pdev->dev,
++ "failed to update MAC stats, ret = %d.\n", ret);
+ return ret;
++ }
+
+- ret = hclge_pfc_rx_stats_get(hdev, indications);
+- if (ret)
+- return ret;
++ hclge_pfc_tx_stats_get(hdev, pfc->requests);
++ hclge_pfc_rx_stats_get(hdev, pfc->indications);
+
+- for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
+- pfc->requests[i] = requests[i];
+- pfc->indications[i] = indications[i];
+- }
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+index d891390d492f6..66c407d0d507e 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+@@ -26,8 +26,6 @@
+ #include "hclge_devlink.h"
+
+ #define HCLGE_NAME "hclge"
+-#define HCLGE_STATS_READ(p, offset) (*(u64 *)((u8 *)(p) + (offset)))
+-#define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f))
+
+ #define HCLGE_BUF_SIZE_UNIT 256U
+ #define HCLGE_BUF_MUL_BY 2
+@@ -548,7 +546,7 @@ static int hclge_mac_query_reg_num(struct hclge_dev *hdev, u32 *desc_num)
+ return 0;
+ }
+
+-static int hclge_mac_update_stats(struct hclge_dev *hdev)
++int hclge_mac_update_stats(struct hclge_dev *hdev)
+ {
+ u32 desc_num;
+ int ret;
+@@ -2498,7 +2496,7 @@ static int hclge_init_roce_base_info(struct hclge_vport *vport)
+ if (hdev->num_msi < hdev->num_nic_msi + hdev->num_roce_msi)
+ return -EINVAL;
+
+- roce->rinfo.base_vector = hdev->roce_base_vector;
++ roce->rinfo.base_vector = hdev->num_nic_msi;
+
+ roce->rinfo.netdev = nic->kinfo.netdev;
+ roce->rinfo.roce_io_base = hdev->hw.io_base;
+@@ -2534,10 +2532,6 @@ static int hclge_init_msi(struct hclge_dev *hdev)
+ hdev->num_msi = vectors;
+ hdev->num_msi_left = vectors;
+
+- hdev->base_msi_vector = pdev->irq;
+- hdev->roce_base_vector = hdev->base_msi_vector +
+- hdev->num_nic_msi;
+-
+ hdev->vector_status = devm_kcalloc(&pdev->dev, hdev->num_msi,
+ sizeof(u16), GFP_KERNEL);
+ if (!hdev->vector_status) {
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+index 69cd8f87b4c86..2fa6e14c96e5b 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+@@ -824,6 +824,9 @@ struct hclge_vf_vlan_cfg {
+ (y) = (_k_ ^ ~_v_) & (_k_); \
+ } while (0)
+
++#define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f))
++#define HCLGE_STATS_READ(p, offset) (*(u64 *)((u8 *)(p) + (offset)))
++
+ #define HCLGE_MAC_TNL_LOG_SIZE 8
+ #define HCLGE_VPORT_NUM 256
+ struct hclge_dev {
+@@ -876,12 +879,10 @@ struct hclge_dev {
+ u16 num_msi;
+ u16 num_msi_left;
+ u16 num_msi_used;
+- u32 base_msi_vector;
+ u16 *vector_status;
+ int *vector_irq;
+ u16 num_nic_msi; /* Num of nic vectors for this PF */
+ u16 num_roce_msi; /* Num of roce vectors for this PF */
+- int roce_base_vector;
+
+ unsigned long service_timer_period;
+ unsigned long service_timer_previous;
+@@ -1138,4 +1139,5 @@ void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
+ int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
+ int hclge_push_vf_link_status(struct hclge_vport *vport);
+ int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en);
++int hclge_mac_update_stats(struct hclge_dev *hdev);
+ #endif
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+index 95074e91a8466..429652a8cde16 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+@@ -113,50 +113,50 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
+ return 0;
+ }
+
+-static int hclge_pfc_stats_get(struct hclge_dev *hdev,
+- enum hclge_opcode_type opcode, u64 *stats)
+-{
+- struct hclge_desc desc[HCLGE_TM_PFC_PKT_GET_CMD_NUM];
+- int ret, i, j;
+-
+- if (!(opcode == HCLGE_OPC_QUERY_PFC_RX_PKT_CNT ||
+- opcode == HCLGE_OPC_QUERY_PFC_TX_PKT_CNT))
+- return -EINVAL;
+-
+- for (i = 0; i < HCLGE_TM_PFC_PKT_GET_CMD_NUM - 1; i++) {
+- hclge_cmd_setup_basic_desc(&desc[i], opcode, true);
+- desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+- }
+-
+- hclge_cmd_setup_basic_desc(&desc[i], opcode, true);
++static const u16 hclge_pfc_tx_stats_offset[] = {
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri0_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri1_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri2_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri3_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri4_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri5_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri6_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri7_pkt_num)
++};
+
+- ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_TM_PFC_PKT_GET_CMD_NUM);
+- if (ret)
+- return ret;
++static const u16 hclge_pfc_rx_stats_offset[] = {
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri0_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri1_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri2_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri3_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri4_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri5_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri6_pkt_num),
++ HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri7_pkt_num)
++};
+
+- for (i = 0; i < HCLGE_TM_PFC_PKT_GET_CMD_NUM; i++) {
+- struct hclge_pfc_stats_cmd *pfc_stats =
+- (struct hclge_pfc_stats_cmd *)desc[i].data;
++static void hclge_pfc_stats_get(struct hclge_dev *hdev, bool tx, u64 *stats)
++{
++ const u16 *offset;
++ int i;
+
+- for (j = 0; j < HCLGE_TM_PFC_NUM_GET_PER_CMD; j++) {
+- u32 index = i * HCLGE_TM_PFC_PKT_GET_CMD_NUM + j;
++ if (tx)
++ offset = hclge_pfc_tx_stats_offset;
++ else
++ offset = hclge_pfc_rx_stats_offset;
+
+- if (index < HCLGE_MAX_TC_NUM)
+- stats[index] =
+- le64_to_cpu(pfc_stats->pkt_num[j]);
+- }
+- }
+- return 0;
++ for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
++ stats[i] = HCLGE_STATS_READ(&hdev->mac_stats, offset[i]);
+ }
+
+-int hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats)
++void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats)
+ {
+- return hclge_pfc_stats_get(hdev, HCLGE_OPC_QUERY_PFC_RX_PKT_CNT, stats);
++ hclge_pfc_stats_get(hdev, false, stats);
+ }
+
+-int hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats)
++void hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats)
+ {
+- return hclge_pfc_stats_get(hdev, HCLGE_OPC_QUERY_PFC_TX_PKT_CNT, stats);
++ hclge_pfc_stats_get(hdev, true, stats);
+ }
+
+ int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx)
+@@ -1123,7 +1123,6 @@ static int hclge_tm_pri_tc_base_dwrr_cfg(struct hclge_dev *hdev)
+
+ 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;
+@@ -1136,13 +1135,7 @@ static int hclge_tm_ets_tc_dwrr_cfg(struct hclge_dev *hdev)
+ 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];
+ }
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+index 2ee9b795f71dc..1db7f40b45255 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+@@ -228,8 +228,8 @@ int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
+ int hclge_tm_init_hw(struct hclge_dev *hdev, bool init);
+ 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);
++void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats);
++void 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);
+ int hclge_tm_get_qset_num(struct hclge_dev *hdev, u16 *qset_num);
+ int hclge_tm_get_pri_num(struct hclge_dev *hdev, u8 *pri_num);
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+index cf00ad7bb881f..fee7d9e79f8c3 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+@@ -703,9 +703,9 @@ static int hclgevf_set_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size)
+ 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);
+@@ -2557,7 +2557,7 @@ static int hclgevf_init_roce_base_info(struct hclgevf_dev *hdev)
+ hdev->num_msi_left == 0)
+ return -EINVAL;
+
+- roce->rinfo.base_vector = hdev->roce_base_vector;
++ roce->rinfo.base_vector = hdev->roce_base_msix_offset;
+
+ roce->rinfo.netdev = nic->kinfo.netdev;
+ roce->rinfo.roce_io_base = hdev->hw.io_base;
+@@ -2823,9 +2823,6 @@ static int hclgevf_init_msi(struct hclgevf_dev *hdev)
+ hdev->num_msi = vectors;
+ hdev->num_msi_left = vectors;
+
+- hdev->base_msi_vector = pdev->irq;
+- hdev->roce_base_vector = pdev->irq + hdev->roce_base_msix_offset;
+-
+ hdev->vector_status = devm_kcalloc(&pdev->dev, hdev->num_msi,
+ sizeof(u16), GFP_KERNEL);
+ if (!hdev->vector_status) {
+@@ -3013,7 +3010,10 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client,
+
+ /* un-init roce, if it exists */
+ if (hdev->roce_client) {
++ while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state))
++ msleep(HCLGEVF_WAIT_RESET_DONE);
+ clear_bit(HCLGEVF_STATE_ROCE_REGISTERED, &hdev->state);
++
+ hdev->roce_client->ops->uninit_instance(&hdev->roce, 0);
+ hdev->roce_client = NULL;
+ hdev->roce.client = NULL;
+@@ -3022,6 +3022,8 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client,
+ /* un-init nic/unic, if this was not called by roce client */
+ if (client->ops->uninit_instance && hdev->nic_client &&
+ client->type != HNAE3_CLIENT_ROCE) {
++ while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state))
++ msleep(HCLGEVF_WAIT_RESET_DONE);
+ clear_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state);
+
+ client->ops->uninit_instance(&hdev->nic, 0);
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+index 28288d7e33032..f6f736c0091c0 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+@@ -109,6 +109,8 @@
+ #define HCLGEVF_VF_RST_ING 0x07008
+ #define HCLGEVF_VF_RST_ING_BIT BIT(16)
+
++#define HCLGEVF_WAIT_RESET_DONE 100
++
+ #define HCLGEVF_RSS_IND_TBL_SIZE 512
+ #define HCLGEVF_RSS_SET_BITMAP_MSK 0xffff
+ #define HCLGEVF_RSS_KEY_SIZE 40
+@@ -308,8 +310,6 @@ struct hclgevf_dev {
+ u16 num_nic_msix; /* Num of nic vectors for this VF */
+ u16 num_roce_msix; /* Num of roce vectors for this VF */
+ u16 roce_base_msix_offset;
+- int roce_base_vector;
+- u32 base_msi_vector;
+ u16 *vector_status;
+ int *vector_irq;
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
+index fdc66fae09601..c5ac6ecf36e10 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
+@@ -114,7 +114,8 @@ int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev,
+
+ memcpy(&req->msg, send_msg, sizeof(struct hclge_vf_to_pf_msg));
+
+- trace_hclge_vf_mbx_send(hdev, req);
++ if (test_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state))
++ trace_hclge_vf_mbx_send(hdev, req);
+
+ /* synchronous send */
+ if (need_resp) {
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
+index 6aa6ff89a7651..352ffe982d849 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.c
++++ b/drivers/net/ethernet/ibm/ibmvnic.c
+@@ -1724,8 +1724,6 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
+ ind_bufp = &tx_scrq->ind_buf;
+
+ 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++;
+@@ -2567,7 +2565,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
+
+ if (adapter->state == VNIC_PROBING) {
+ netdev_warn(netdev, "Adapter reset during probe\n");
+- adapter->init_done_rc = EAGAIN;
++ adapter->init_done_rc = -EAGAIN;
+ ret = EAGAIN;
+ goto err;
+ }
+@@ -5069,11 +5067,6 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
+ */
+ adapter->login_pending = false;
+
+- if (!completion_done(&adapter->init_done)) {
+- complete(&adapter->init_done);
+- adapter->init_done_rc = -EIO;
+- }
+-
+ if (adapter->state == VNIC_DOWN)
+ rc = ibmvnic_reset(adapter, VNIC_RESET_PASSIVE_INIT);
+ else
+@@ -5094,6 +5087,13 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
+ rc);
+ adapter->failover_pending = false;
+ }
++
++ if (!completion_done(&adapter->init_done)) {
++ complete(&adapter->init_done);
++ if (!adapter->init_done_rc)
++ adapter->init_done_rc = -EAGAIN;
++ }
++
+ break;
+ case IBMVNIC_CRQ_INIT_COMPLETE:
+ dev_info(dev, "Partner initialization complete\n");
+@@ -5414,6 +5414,9 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter)
+ 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:
+@@ -5558,7 +5561,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ }
+
+ rc = ibmvnic_reset_init(adapter, false);
+- } while (rc == EAGAIN);
++ } while (rc == -EAGAIN);
+
+ /* We are ignoring the error from ibmvnic_reset_init() assuming that the
+ * partner is not ready. CRQ is not active. When the partner becomes
+diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
+index 09ae1939e6db4..36d52246bdc66 100644
+--- a/drivers/net/ethernet/intel/e100.c
++++ b/drivers/net/ethernet/intel/e100.c
+@@ -3003,9 +3003,10 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+
++ netif_device_detach(netdev);
++
+ if (netif_running(netdev))
+ e100_down(nic);
+- netif_device_detach(netdev);
+
+ if ((nic->flags & wol_magic) | e100_asf(nic)) {
+ /* enable reverse auto-negotiation */
+@@ -3022,7 +3023,7 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
+ *enable_wake = false;
+ }
+
+- pci_clear_master(pdev);
++ pci_disable_device(pdev);
+ }
+
+ static int __e100_power_off(struct pci_dev *pdev, bool wake)
+@@ -3042,8 +3043,6 @@ static int __maybe_unused e100_suspend(struct device *dev_d)
+
+ __e100_shutdown(to_pci_dev(dev_d), &wake);
+
+- device_wakeup_disable(dev_d);
+-
+ return 0;
+ }
+
+@@ -3051,6 +3050,14 @@ static int __maybe_unused e100_resume(struct device *dev_d)
+ {
+ struct net_device *netdev = dev_get_drvdata(dev_d);
+ struct nic *nic = netdev_priv(netdev);
++ int err;
++
++ err = pci_enable_device(to_pci_dev(dev_d));
++ if (err) {
++ netdev_err(netdev, "Resume cannot enable PCI device, aborting\n");
++ return err;
++ }
++ pci_set_master(to_pci_dev(dev_d));
+
+ /* disable reverse auto-negotiation */
+ if (nic->phy == phy_82552_v) {
+@@ -3062,10 +3069,11 @@ static int __maybe_unused e100_resume(struct device *dev_d)
+ smartspeed & ~(E100_82552_REV_ANEG));
+ }
+
+- netif_device_attach(netdev);
+ if (netif_running(netdev))
+ e100_up(nic);
+
++ netif_device_attach(netdev);
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
+index 39fb3d57c0574..b10bc59c5700f 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e.h
++++ b/drivers/net/ethernet/intel/i40e/i40e.h
+@@ -161,6 +161,7 @@ enum i40e_vsi_state_t {
+ __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__,
+ };
+@@ -1247,6 +1248,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_ptp_alloc_pins(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);
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+index 291e61ac3e448..2c1b1da1220ec 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+@@ -553,6 +553,14 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
+ dev_info(&pf->pdev->dev, "vsi %d not found\n", vsi_seid);
+ return;
+ }
++ if (vsi->type != I40E_VSI_MAIN &&
++ vsi->type != I40E_VSI_FDIR &&
++ vsi->type != I40E_VSI_VMDQ2) {
++ dev_info(&pf->pdev->dev,
++ "vsi %d type %d descriptor rings not available\n",
++ vsi_seid, vsi->type);
++ return;
++ }
+ if (type == RING_TYPE_XDP && !i40e_enabled_xdp_vsi(vsi)) {
+ dev_info(&pf->pdev->dev, "XDP not enabled on VSI %d\n", vsi_seid);
+ return;
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
+index e04b540cedc85..76d0b809d1340 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
+@@ -1790,6 +1790,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
+ bool is_add)
+ {
+ struct i40e_pf *pf = vsi->back;
++ u16 num_tc_qps = 0;
+ u16 sections = 0;
+ u8 netdev_tc = 0;
+ u16 numtc = 1;
+@@ -1797,13 +1798,33 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
+ 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
++ */
++ 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;
++ }
+
+ /* 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++) {
+@@ -1881,15 +1902,11 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
+ }
+ 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) {
+@@ -2623,7 +2640,8 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
+
+ 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) {
+@@ -5426,6 +5444,58 @@ static void i40e_vsi_update_queue_map(struct i40e_vsi *vsi,
+ sizeof(vsi->info.tc_mapping));
+ }
+
++/**
++ * 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
+@@ -5716,24 +5786,6 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
+ INIT_LIST_HEAD(&vsi->ch_list);
+ }
+
+-/**
+- * 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
+@@ -6240,26 +6292,15 @@ int i40e_create_queue_channel(struct i40e_vsi *vsi,
+ /* 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
+@@ -7912,12 +7953,20 @@ config_tc:
+ 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];
+@@ -8482,9 +8531,8 @@ static int i40e_configure_clsflower(struct i40e_vsi *vsi,
+ 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;
+ }
+
+@@ -13771,7 +13819,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 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) {
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+index 472f56b360b8c..2ea4deb8fc44c 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+@@ -183,17 +183,18 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
+ /***********************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
+@@ -211,9 +212,14 @@ static inline void i40e_vc_disable_vf(struct i40e_vf *vf)
+ 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);
+ }
+
+ /**
+@@ -674,14 +680,13 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
+ 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));
+
+@@ -719,6 +724,10 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
+ }
+ 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;
+
+@@ -1939,6 +1948,32 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf,
+ return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0);
+ }
+
++/**
++ * 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
+@@ -1999,7 +2034,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -2105,20 +2140,6 @@ err:
+ return ret;
+ }
+
+-/**
+- * 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_vc_config_promiscuous_mode_msg
+ * @vf: pointer to the VF info
+@@ -2136,7 +2157,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -2217,13 +2238,14 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -2310,9 +2332,15 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
+ 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:
+@@ -2366,7 +2394,7 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -2538,7 +2566,7 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
+ 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 error_param;
+ }
+@@ -2588,7 +2616,7 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
+ 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) {
+@@ -2607,8 +2635,7 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
+ } 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;
+ }
+
+@@ -2634,7 +2661,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
+
+ 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;
+ }
+@@ -2751,7 +2778,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+@@ -2823,7 +2850,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+@@ -2967,7 +2994,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+@@ -3087,9 +3114,9 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3118,9 +3145,9 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3153,7 +3180,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3189,7 +3216,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3214,7 +3241,7 @@ static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3240,7 +3267,7 @@ static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3467,7 +3494,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3598,7 +3625,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3707,7 +3734,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3796,15 +3823,9 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
+
+ /* 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;
+
+@@ -3824,7 +3845,7 @@ static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
+ 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;
+ }
+@@ -3844,8 +3865,7 @@ static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
+ }
+
+ /* 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;
+
+@@ -3907,7 +3927,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
+ 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:
+@@ -4161,7 +4181,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+ /* 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:
+@@ -4169,34 +4189,6 @@ error_param:
+ return ret;
+ }
+
+-/**
+- * 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
+@@ -4253,19 +4245,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
+ /* 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];
+- }
+-
++ 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];
+ /* Locked once because multiple functions below iterate list */
+ spin_lock_bh(&vsi->mac_filter_hash_lock);
+
+@@ -4641,7 +4623,7 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
+ 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");
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+index 091e32c1bb46f..49575a640a84c 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+@@ -18,6 +18,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,
+diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
+index 68c80f04113c8..0ae6da2992d01 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf.h
++++ b/drivers/net/ethernet/intel/iavf/iavf.h
+@@ -39,6 +39,7 @@
+ #include "iavf_txrx.h"
+ #include "iavf_fdir.h"
+ #include "iavf_adv_rss.h"
++#include <linux/bitmap.h>
+
+ #define DEFAULT_DEBUG_LEVEL_SHIFT 3
+ #define PFX "iavf: "
+@@ -304,6 +305,7 @@ struct iavf_adapter {
+ #define IAVF_FLAG_AQ_DEL_FDIR_FILTER BIT(26)
+ #define IAVF_FLAG_AQ_ADD_ADV_RSS_CFG BIT(27)
+ #define IAVF_FLAG_AQ_DEL_ADV_RSS_CFG BIT(28)
++#define IAVF_FLAG_AQ_REQUEST_STATS BIT(29)
+
+ /* OS defined structs */
+ struct net_device *netdev;
+@@ -397,6 +399,7 @@ int iavf_up(struct iavf_adapter *adapter);
+ void iavf_down(struct iavf_adapter *adapter);
+ int iavf_process_config(struct iavf_adapter *adapter);
+ void iavf_schedule_reset(struct iavf_adapter *adapter);
++void iavf_schedule_request_stats(struct iavf_adapter *adapter);
+ void iavf_reset(struct iavf_adapter *adapter);
+ void iavf_set_ethtool_ops(struct net_device *netdev);
+ void iavf_update_stats(struct iavf_adapter *adapter);
+@@ -454,4 +457,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
+ void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
+ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+ const u8 *macaddr);
++int iavf_lock_timeout(struct mutex *lock, unsigned int msecs);
+ #endif /* _IAVF_H_ */
+diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+index 5a359a0a20ecc..461f5237a2f88 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
++++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+@@ -354,6 +354,9 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ unsigned int i;
+
++ /* Explicitly request stats refresh */
++ iavf_schedule_request_stats(adapter);
++
+ iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
+
+ rcu_read_lock();
+@@ -612,23 +615,44 @@ static int iavf_set_ringparam(struct net_device *netdev,
+ 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);
++ 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 = clamp_t(u32, ring->rx_pending,
+- IAVF_MIN_RXD,
+- IAVF_MAX_RXD);
+- new_rx_count = ALIGN(new_rx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
++ 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;
+@@ -723,12 +747,31 @@ static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
+ *
+ * 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);
+@@ -751,6 +794,7 @@ static void iavf_set_itr_per_queue(struct iavf_adapter *adapter,
+ * 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;
+ }
+
+ /**
+@@ -792,9 +836,11 @@ static int __iavf_set_coalesce(struct net_device *netdev,
+ */
+ 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);
+@@ -1776,6 +1822,7 @@ static int iavf_set_channels(struct net_device *netdev,
+ {
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u32 num_req = ch->combined_count;
++ int i;
+
+ if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+ adapter->num_tc) {
+@@ -1786,7 +1833,7 @@ static int iavf_set_channels(struct net_device *netdev,
+ /* All of these should have already been checked by ethtool before this
+ * even gets to us, but just to be sure.
+ */
+- if (num_req > adapter->vsi_res->num_queue_pairs)
++ if (num_req == 0 || num_req > adapter->vsi_res->num_queue_pairs)
+ return -EINVAL;
+
+ if (num_req == adapter->num_active_queues)
+@@ -1798,6 +1845,20 @@ static int iavf_set_channels(struct net_device *netdev,
+ adapter->num_req_queues = num_req;
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
+ iavf_schedule_reset(adapter);
++
++ /* wait for the reset is done */
++ for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) {
++ msleep(IAVF_RESET_WAIT_MS);
++ if (adapter->flags & IAVF_FLAG_RESET_PENDING)
++ continue;
++ break;
++ }
++ if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
++ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
++ adapter->num_active_queues = num_req;
++ return -EOPNOTSUPP;
++ }
++
+ return 0;
+ }
+
+@@ -1844,14 +1905,13 @@ static int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+
+ 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;
+ }
+diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
+index cada4e0e40b48..4f3b025daa14f 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
+@@ -138,7 +138,7 @@ enum iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw,
+ *
+ * Returns 0 on success, negative on failure
+ **/
+-static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs)
++int iavf_lock_timeout(struct mutex *lock, unsigned int msecs)
+ {
+ unsigned int wait, delay = 10;
+
+@@ -165,6 +165,19 @@ void iavf_schedule_reset(struct iavf_adapter *adapter)
+ }
+ }
+
++/**
++ * iavf_schedule_request_stats - Set the flags and schedule statistics request
++ * @adapter: board private structure
++ *
++ * Sets IAVF_FLAG_AQ_REQUEST_STATS flag so iavf_watchdog_task() will explicitly
++ * request and refresh ethtool stats
++ **/
++void iavf_schedule_request_stats(struct iavf_adapter *adapter)
++{
++ adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_STATS;
++ mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
++}
++
+ /**
+ * iavf_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+@@ -687,6 +700,21 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan)
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+ }
+
++/**
++ * iavf_restore_filters
++ * @adapter: board private structure
++ *
++ * Restore existing non MAC filters when VF netdev comes back up
++ **/
++static void iavf_restore_filters(struct iavf_adapter *adapter)
++{
++ u16 vid;
++
++ /* re-add all VLAN filters */
++ for_each_set_bit(vid, adapter->vsi.active_vlans, VLAN_N_VID)
++ iavf_add_vlan(adapter, vid);
++}
++
+ /**
+ * iavf_vlan_rx_add_vid - Add a VLAN filter to a device
+ * @netdev: network device struct
+@@ -700,8 +728,11 @@ static int iavf_vlan_rx_add_vid(struct net_device *netdev,
+
+ if (!VLAN_ALLOWED(adapter))
+ return -EIO;
++
+ if (iavf_add_vlan(adapter, vid) == NULL)
+ return -ENOMEM;
++
++ set_bit(vid, adapter->vsi.active_vlans);
+ return 0;
+ }
+
+@@ -716,11 +747,10 @@ static int iavf_vlan_rx_kill_vid(struct net_device *netdev,
+ {
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+- if (VLAN_ALLOWED(adapter)) {
+- iavf_del_vlan(adapter, vid);
+- return 0;
+- }
+- return -EIO;
++ iavf_del_vlan(adapter, vid);
++ clear_bit(vid, adapter->vsi.active_vlans);
++
++ return 0;
+ }
+
+ /**
+@@ -1630,8 +1660,7 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
+ 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;
+@@ -1679,6 +1708,11 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
+ iavf_del_adv_rss_cfg(adapter);
+ return 0;
+ }
++ if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_STATS) {
++ iavf_request_stats(adapter);
++ return 0;
++ }
++
+ return -EAGAIN;
+ }
+
+@@ -2074,8 +2108,8 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
+
+ iavf_free_misc_irq(adapter);
+ iavf_reset_interrupt_capability(adapter);
+- iavf_free_queues(adapter);
+ iavf_free_q_vectors(adapter);
++ iavf_free_queues(adapter);
+ memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE);
+ iavf_shutdown_adminq(&adapter->hw);
+ adapter->netdev->flags &= ~IFF_UP;
+@@ -2103,7 +2137,6 @@ static void iavf_reset_task(struct work_struct *work)
+ 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;
+ u32 reg_val;
+ int i = 0, err;
+@@ -2166,6 +2199,7 @@ static void iavf_reset_task(struct work_struct *work)
+ }
+
+ pci_set_master(adapter->pdev);
++ pci_restore_msi_state(adapter->pdev);
+
+ if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
+ dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
+@@ -2243,11 +2277,6 @@ continue_reset:
+ list_for_each_entry(f, &adapter->mac_filter_list, list) {
+ f->add = true;
+ }
+- /* re-add all VLAN filters */
+- list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
+- vlf->add = true;
+- }
+-
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+
+ /* check if TCs are running and re-add all cloud filters */
+@@ -2261,7 +2290,6 @@ continue_reset:
+ spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
+- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
+ iavf_misc_irq_enable(adapter);
+
+@@ -2356,7 +2384,7 @@ static void iavf_adminq_task(struct work_struct *work)
+
+ /* 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) {
+@@ -3041,8 +3069,10 @@ static int iavf_configure_clsflower(struct iavf_adapter *adapter,
+ return -ENOMEM;
+
+ while (!mutex_trylock(&adapter->crit_lock)) {
+- if (--count == 0)
+- goto err;
++ if (--count == 0) {
++ kfree(filter);
++ return err;
++ }
+ udelay(1);
+ }
+
+@@ -3053,11 +3083,11 @@ static int iavf_configure_clsflower(struct iavf_adapter *adapter,
+ /* 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 */
+@@ -3247,6 +3277,9 @@ static int iavf_open(struct net_device *netdev)
+
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+
++ /* Restore VLAN filters that were removed with IFF_DOWN */
++ iavf_restore_filters(adapter);
++
+ iavf_configure(adapter);
+
+ iavf_up_complete(adapter);
+@@ -3354,11 +3387,16 @@ static int iavf_set_features(struct net_device *netdev,
+ {
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+- /* Don't allow changing VLAN_RX flag when adapter is not capable
+- * of VLAN offload
++ /* Don't allow enabling VLAN features when adapter is not capable
++ * of VLAN offload/filtering
+ */
+ if (!VLAN_ALLOWED(adapter)) {
+- if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX)
++ netdev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_RX |
++ NETIF_F_HW_VLAN_CTAG_TX |
++ NETIF_F_HW_VLAN_CTAG_FILTER);
++ if (features & (NETIF_F_HW_VLAN_CTAG_RX |
++ NETIF_F_HW_VLAN_CTAG_TX |
++ NETIF_F_HW_VLAN_CTAG_FILTER))
+ return -EINVAL;
+ } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+@@ -3442,7 +3480,8 @@ static netdev_features_t iavf_fix_features(struct net_device *netdev,
+ {
+ 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);
+diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+index 3c735968e1b85..08302ab35d687 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+@@ -607,7 +607,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
+ if (f->add)
+ count++;
+ }
+- if (!count) {
++ if (!count || !VLAN_ALLOWED(adapter)) {
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+ return;
+@@ -673,9 +673,19 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
+
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
+
+- list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+- if (f->remove)
++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
++ /* since VLAN capabilities are not allowed, we dont want to send
++ * a VLAN delete request because it will most likely fail and
++ * create unnecessary errors/noise, so just free the VLAN
++ * filters marked for removal to enable bailing out before
++ * sending a virtchnl message
++ */
++ if (f->remove && !VLAN_ALLOWED(adapter)) {
++ list_del(&f->list);
++ kfree(f);
++ } else if (f->remove) {
+ count++;
++ }
+ }
+ if (!count) {
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
+@@ -784,6 +794,8 @@ void iavf_request_stats(struct iavf_adapter *adapter)
+ /* no error message, this isn't crucial */
+ return;
+ }
++
++ adapter->aq_required &= ~IAVF_FLAG_AQ_REQUEST_STATS;
+ adapter->current_op = VIRTCHNL_OP_GET_STATS;
+ vqs.vsi_id = adapter->vsi_res->vsi_id;
+ /* queue maps are ignored for this message - only the vsi is used */
+@@ -1722,8 +1734,37 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
+ }
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
+ iavf_add_filter(adapter, adapter->hw.mac.addr);
++
++ if (VLAN_ALLOWED(adapter)) {
++ if (!list_empty(&adapter->vlan_filter_list)) {
++ struct iavf_vlan_filter *vlf;
++
++ /* re-add all VLAN filters over virtchnl */
++ list_for_each_entry(vlf,
++ &adapter->vlan_filter_list,
++ list)
++ vlf->add = true;
++
++ adapter->aq_required |=
++ IAVF_FLAG_AQ_ADD_VLAN_FILTER;
++ }
++ }
++
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
+ iavf_process_config(adapter);
++
++ /* unlock crit_lock before acquiring rtnl_lock as other
++ * processes holding rtnl_lock could be waiting for the same
++ * crit_lock
++ */
++ mutex_unlock(&adapter->crit_lock);
++ rtnl_lock();
++ netdev_update_features(adapter->netdev);
++ rtnl_unlock();
++ if (iavf_lock_timeout(&adapter->crit_lock, 10000))
++ dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n",
++ __FUNCTION__);
++
+ }
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES:
+diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
+index 3c4f08d20414e..fba8f021c397d 100644
+--- a/drivers/net/ethernet/intel/ice/ice.h
++++ b/drivers/net/ethernet/intel/ice/ice.h
+@@ -139,13 +139,10 @@
+ #define ice_for_each_q_vector(vsi, i) \
+ for ((i) = 0; (i) < (vsi)->num_q_vectors; (i)++)
+
+-#define ICE_UCAST_PROMISC_BITS (ICE_PROMISC_UCAST_TX | ICE_PROMISC_MCAST_TX | \
+- ICE_PROMISC_UCAST_RX | ICE_PROMISC_MCAST_RX)
++#define ICE_UCAST_PROMISC_BITS (ICE_PROMISC_UCAST_TX | ICE_PROMISC_UCAST_RX)
+
+ #define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_TX | \
+- ICE_PROMISC_MCAST_TX | \
+ ICE_PROMISC_UCAST_RX | \
+- ICE_PROMISC_MCAST_RX | \
+ ICE_PROMISC_VLAN_TX | \
+ ICE_PROMISC_VLAN_RX)
+
+@@ -306,10 +303,6 @@ struct ice_vsi {
+ spinlock_t arfs_lock; /* protects aRFS hash table and filter state */
+ atomic_t *arfs_last_fltr_id;
+
+- /* devlink port data */
+- struct devlink_port devlink_port;
+- bool devlink_port_registered;
+-
+ u16 max_frame;
+ u16 rx_buf_len;
+
+@@ -421,6 +414,9 @@ struct ice_pf {
+ struct devlink_region *nvm_region;
+ struct devlink_region *devcaps_region;
+
++ /* devlink port data */
++ struct devlink_port devlink_port;
++
+ /* OS reserved IRQ details */
+ struct msix_entry *msix_entries;
+ struct ice_res_tracker *irq_tracker;
+diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
+index c36057efc7ae3..f74610442bda7 100644
+--- a/drivers/net/ethernet/intel/ice/ice_base.c
++++ b/drivers/net/ethernet/intel/ice/ice_base.c
+@@ -909,7 +909,7 @@ ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
+ } else if (status == ICE_ERR_DOES_NOT_EXIST) {
+ dev_dbg(ice_pf_to_dev(vsi->back), "LAN Tx queues do not exist, nothing to disable\n");
+ } else if (status) {
+- dev_err(ice_pf_to_dev(vsi->back), "Failed to disable LAN Tx queues, error: %s\n",
++ dev_dbg(ice_pf_to_dev(vsi->back), "Failed to disable LAN Tx queues, error: %s\n",
+ ice_stat_str(status));
+ return -ENODEV;
+ }
+diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c
+index da7288bdc9a3f..2ec5d5cb72803 100644
+--- a/drivers/net/ethernet/intel/ice/ice_devlink.c
++++ b/drivers/net/ethernet/intel/ice/ice_devlink.c
+@@ -526,60 +526,115 @@ void ice_devlink_unregister(struct ice_pf *pf)
+ }
+
+ /**
+- * ice_devlink_create_port - Create a devlink port for this VSI
+- * @vsi: the VSI to create a port for
++ * ice_devlink_create_pf_port - Create a devlink port for this PF
++ * @pf: the PF to create a devlink port for
+ *
+- * Create and register a devlink_port for this VSI.
++ * Create and register a devlink_port for this PF.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+-int ice_devlink_create_port(struct ice_vsi *vsi)
++int ice_devlink_create_pf_port(struct ice_pf *pf)
+ {
+ struct devlink_port_attrs attrs = {};
+- struct ice_port_info *pi;
++ struct devlink_port *devlink_port;
+ struct devlink *devlink;
++ struct ice_vsi *vsi;
+ struct device *dev;
+- struct ice_pf *pf;
+ int err;
+
+- /* Currently we only create devlink_port instances for PF VSIs */
+- if (vsi->type != ICE_VSI_PF)
+- return -EINVAL;
+-
+- pf = vsi->back;
+- devlink = priv_to_devlink(pf);
+ dev = ice_pf_to_dev(pf);
+- pi = pf->hw.port_info;
++
++ devlink_port = &pf->devlink_port;
++
++ vsi = ice_get_main_vsi(pf);
++ if (!vsi)
++ return -EIO;
+
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+- attrs.phys.port_number = pi->lport;
+- devlink_port_attrs_set(&vsi->devlink_port, &attrs);
+- err = devlink_port_register(devlink, &vsi->devlink_port, vsi->idx);
++ attrs.phys.port_number = pf->hw.bus.func;
++ devlink_port_attrs_set(devlink_port, &attrs);
++ devlink = priv_to_devlink(pf);
++
++ err = devlink_port_register(devlink, devlink_port, vsi->idx);
+ if (err) {
+- dev_err(dev, "devlink_port_register failed: %d\n", err);
++ dev_err(dev, "Failed to create devlink port for PF %d, error %d\n",
++ pf->hw.pf_id, err);
+ return err;
+ }
+
+- vsi->devlink_port_registered = true;
++ return 0;
++}
++
++/**
++ * ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF
++ * @pf: the PF to cleanup
++ *
++ * Unregisters the devlink_port structure associated with this PF.
++ */
++void ice_devlink_destroy_pf_port(struct ice_pf *pf)
++{
++ struct devlink_port *devlink_port;
++
++ devlink_port = &pf->devlink_port;
++
++ devlink_port_type_clear(devlink_port);
++ devlink_port_unregister(devlink_port);
++}
++
++/**
++ * ice_devlink_create_vf_port - Create a devlink port for this VF
++ * @vf: the VF to create a port for
++ *
++ * Create and register a devlink_port for this VF.
++ *
++ * Return: zero on success or an error code on failure.
++ */
++int ice_devlink_create_vf_port(struct ice_vf *vf)
++{
++ struct devlink_port_attrs attrs = {};
++ struct devlink_port *devlink_port;
++ struct devlink *devlink;
++ struct ice_vsi *vsi;
++ struct device *dev;
++ struct ice_pf *pf;
++ int err;
++
++ pf = vf->pf;
++ dev = ice_pf_to_dev(pf);
++ vsi = ice_get_vf_vsi(vf);
++ devlink_port = &vf->devlink_port;
++
++ attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
++ attrs.pci_vf.pf = pf->hw.bus.func;
++ attrs.pci_vf.vf = vf->vf_id;
++
++ devlink_port_attrs_set(devlink_port, &attrs);
++ devlink = priv_to_devlink(pf);
++
++ err = devlink_port_register(devlink, devlink_port, vsi->idx);
++ if (err) {
++ dev_err(dev, "Failed to create devlink port for VF %d, error %d\n",
++ vf->vf_id, err);
++ return err;
++ }
+
+ return 0;
+ }
+
+ /**
+- * ice_devlink_destroy_port - Destroy the devlink_port for this VSI
+- * @vsi: the VSI to cleanup
++ * ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF
++ * @vf: the VF to cleanup
+ *
+- * Unregisters the devlink_port structure associated with this VSI.
++ * Unregisters the devlink_port structure associated with this VF.
+ */
+-void ice_devlink_destroy_port(struct ice_vsi *vsi)
++void ice_devlink_destroy_vf_port(struct ice_vf *vf)
+ {
+- if (!vsi->devlink_port_registered)
+- return;
++ struct devlink_port *devlink_port;
+
+- devlink_port_type_clear(&vsi->devlink_port);
+- devlink_port_unregister(&vsi->devlink_port);
++ devlink_port = &vf->devlink_port;
+
+- vsi->devlink_port_registered = false;
++ devlink_port_type_clear(devlink_port);
++ devlink_port_unregister(devlink_port);
+ }
+
+ /**
+diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.h b/drivers/net/ethernet/intel/ice/ice_devlink.h
+index e07e74426bde8..e30284ccbed4c 100644
+--- a/drivers/net/ethernet/intel/ice/ice_devlink.h
++++ b/drivers/net/ethernet/intel/ice/ice_devlink.h
+@@ -8,8 +8,10 @@ struct ice_pf *ice_allocate_pf(struct device *dev);
+
+ int ice_devlink_register(struct ice_pf *pf);
+ void ice_devlink_unregister(struct ice_pf *pf);
+-int ice_devlink_create_port(struct ice_vsi *vsi);
+-void ice_devlink_destroy_port(struct ice_vsi *vsi);
++int ice_devlink_create_pf_port(struct ice_pf *pf);
++void ice_devlink_destroy_pf_port(struct ice_pf *pf);
++int ice_devlink_create_vf_port(struct ice_vf *vf);
++void ice_devlink_destroy_vf_port(struct ice_vf *vf);
+
+ void ice_devlink_init_regions(struct ice_pf *pf);
+ void ice_devlink_destroy_regions(struct ice_pf *pf);
+diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
+index b718e196af2a4..62bf879dc6232 100644
+--- a/drivers/net/ethernet/intel/ice/ice_lib.c
++++ b/drivers/net/ethernet/intel/ice/ice_lib.c
+@@ -83,8 +83,13 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
+ if (!vsi->rx_rings)
+ goto err_rings;
+
+- /* XDP will have vsi->alloc_txq Tx queues as well, so double the size */
+- vsi->txq_map = devm_kcalloc(dev, (2 * vsi->alloc_txq),
++ /* txq_map needs to have enough space to track both Tx (stack) rings
++ * and XDP rings; at this point vsi->num_xdp_txq might not be set,
++ * so use num_possible_cpus() as we want to always provide XDP ring
++ * per CPU, regardless of queue count settings from user that might
++ * have come from ethtool's set_channels() callback;
++ */
++ vsi->txq_map = devm_kcalloc(dev, (vsi->alloc_txq + num_possible_cpus()),
+ sizeof(*vsi->txq_map), GFP_KERNEL);
+
+ if (!vsi->txq_map)
+@@ -2860,7 +2865,8 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ }
+
+- ice_devlink_destroy_port(vsi);
++ if (vsi->type == ICE_VSI_PF)
++ ice_devlink_destroy_pf_port(pf);
+
+ if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
+ ice_rss_clean(vsi);
+diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
+index 06fa93e597fbc..819c32a721e84 100644
+--- a/drivers/net/ethernet/intel/ice/ice_main.c
++++ b/drivers/net/ethernet/intel/ice/ice_main.c
+@@ -2497,7 +2497,18 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog)
+ ice_stat_str(status));
+ goto clear_xdp_rings;
+ }
+- ice_vsi_assign_bpf_prog(vsi, prog);
++
++ /* assign the prog only when it's not already present on VSI;
++ * this flow is a subject of both ethtool -L and ndo_bpf flows;
++ * VSI rebuild that happens under ethtool -L can expose us to
++ * the bpf_prog refcount issues as we would be swapping same
++ * bpf_prog pointers from vsi->xdp_prog and calling bpf_prog_put
++ * on it as it would be treated as an 'old_prog'; for ndo_bpf
++ * this is not harmful as dev_xdp_install bumps the refcount
++ * before calling the op exposed by the driver;
++ */
++ if (!ice_is_xdp_ena_vsi(vsi))
++ ice_vsi_assign_bpf_prog(vsi, prog);
+
+ return 0;
+ clear_xdp_rings:
+@@ -2643,6 +2654,11 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
+ if (xdp_ring_err)
+ NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed");
+ } else {
++ /* safe to call even when prog == vsi->xdp_prog as
++ * dev_xdp_install in net/core/dev.c incremented prog's
++ * refcount so corresponding bpf_prog_put won't cause
++ * underflow
++ */
+ ice_vsi_assign_bpf_prog(vsi, prog);
+ }
+
+@@ -4170,11 +4186,11 @@ static int ice_register_netdev(struct ice_pf *pf)
+ set_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ netif_carrier_off(vsi->netdev);
+ netif_tx_stop_all_queues(vsi->netdev);
+- err = ice_devlink_create_port(vsi);
++ err = ice_devlink_create_pf_port(pf);
+ if (err)
+ goto err_devlink_create;
+
+- devlink_port_type_eth_set(&vsi->devlink_port, vsi->netdev);
++ devlink_port_type_eth_set(&pf->devlink_port, vsi->netdev);
+
+ return 0;
+ err_devlink_create:
+@@ -4600,9 +4616,6 @@ static void ice_remove(struct pci_dev *pdev)
+ 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;
+@@ -5608,6 +5621,9 @@ static int ice_up_complete(struct ice_vsi *vsi)
+ netif_carrier_on(vsi->netdev);
+ }
+
++ /* clear this now, and the first stats read will be used as baseline */
++ vsi->stat_offsets_loaded = false;
++
+ ice_service_task_schedule(pf);
+
+ return 0;
+diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
+index d1ef3d48a4b03..ac27a4fe8b94c 100644
+--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
+@@ -459,7 +459,7 @@ static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
+ scaled_ppm = -scaled_ppm;
+ }
+
+- while ((u64)scaled_ppm > div_u64(U64_MAX, incval)) {
++ while ((u64)scaled_ppm > div64_u64(U64_MAX, incval)) {
+ /* handle overflow by scaling down the scaled_ppm and
+ * the divisor, losing some precision
+ */
+@@ -1182,19 +1182,16 @@ static void ice_ptp_tx_tstamp_work(struct kthread_work *work)
+ if (err)
+ continue;
+
+- /* Check if the timestamp is valid */
+- if (!(raw_tstamp & ICE_PTP_TS_VALID))
++ /* Check if the timestamp is invalid or stale */
++ if (!(raw_tstamp & ICE_PTP_TS_VALID) ||
++ raw_tstamp == tx->tstamps[idx].cached_tstamp)
+ continue;
+
+- /* clear the timestamp register, so that it won't show valid
+- * again when re-used.
+- */
+- ice_clear_phy_tstamp(hw, tx->quad, phy_idx);
+-
+ /* The timestamp is valid, so we'll go ahead and clear this
+ * index and then send the timestamp up to the stack.
+ */
+ spin_lock(&tx->lock);
++ tx->tstamps[idx].cached_tstamp = raw_tstamp;
+ clear_bit(idx, tx->in_use);
+ skb = tx->tstamps[idx].skb;
+ tx->tstamps[idx].skb = NULL;
+diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h
+index e1c787bd5b967..8cdd6f7046b73 100644
+--- a/drivers/net/ethernet/intel/ice/ice_ptp.h
++++ b/drivers/net/ethernet/intel/ice/ice_ptp.h
+@@ -46,15 +46,21 @@ struct ice_perout_channel {
+ * struct ice_tx_tstamp - Tracking for a single Tx timestamp
+ * @skb: pointer to the SKB for this timestamp request
+ * @start: jiffies when the timestamp was first requested
++ * @cached_tstamp: last read timestamp
+ *
+ * This structure tracks a single timestamp request. The SKB pointer is
+ * provided when initiating a request. The start time is used to ensure that
+ * we discard old requests that were not fulfilled within a 2 second time
+ * window.
++ * Timestamp values in the PHY are read only and do not get cleared except at
++ * hardware reset or when a new timestamp value is captured. The cached_tstamp
++ * field is used to detect the case where a new timestamp has not yet been
++ * captured, ensuring that we avoid sending stale timestamp data to the stack.
+ */
+ struct ice_tx_tstamp {
+ struct sk_buff *skb;
+ unsigned long start;
++ u64 cached_tstamp;
+ };
+
+ /**
+diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+index e93430ab37f1e..a78e8f00cf71b 100644
+--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+@@ -251,7 +251,7 @@ ice_vc_hash_field_match_type ice_vc_hash_field_list_comms[] = {
+ * ice_get_vf_vsi - get VF's VSI based on the stored index
+ * @vf: VF used to get VSI
+ */
+-static struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf)
++struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf)
+ {
+ return vf->pf->vsi[vf->lan_vsi_idx];
+ }
+@@ -634,8 +634,7 @@ void ice_free_vfs(struct ice_pf *pf)
+
+ /* Avoid wait time by stopping all VFs at the same time */
+ ice_for_each_vf(pf, i)
+- if (test_bit(ICE_VF_STATE_QS_ENA, pf->vf[i].vf_states))
+- ice_dis_vf_qs(&pf->vf[i]);
++ ice_dis_vf_qs(&pf->vf[i]);
+
+ tmp = pf->num_alloc_vfs;
+ pf->num_qps_per_vf = 0;
+@@ -1570,6 +1569,7 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
+ ice_vc_set_default_allowlist(vf);
+
+ ice_vf_fdir_exit(vf);
++ ice_vf_fdir_init(vf);
+ /* clean VF control VSI when resetting VFs since it should be
+ * setup only when VF creates its first FDIR rule.
+ */
+@@ -1645,8 +1645,7 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
+
+ vsi = ice_get_vf_vsi(vf);
+
+- if (test_bit(ICE_VF_STATE_QS_ENA, vf->vf_states))
+- ice_dis_vf_qs(vf);
++ ice_dis_vf_qs(vf);
+
+ /* Call Disable LAN Tx queue AQ whether or not queues are
+ * enabled. This is needed for successful completion of VFR.
+@@ -1697,6 +1696,7 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
+ }
+
+ ice_vf_fdir_exit(vf);
++ ice_vf_fdir_init(vf);
+ /* clean VF control VSI when resetting VF since it should be setup
+ * only when VF creates its first FDIR rule.
+ */
+@@ -2954,6 +2954,7 @@ bool ice_is_any_vf_in_promisc(struct ice_pf *pf)
+ static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg)
+ {
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
++ enum ice_status mcast_status = 0, ucast_status = 0;
+ bool rm_promisc, alluni = false, allmulti = false;
+ struct virtchnl_promisc_info *info =
+ (struct virtchnl_promisc_info *)msg;
+@@ -3043,52 +3044,51 @@ static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg)
+ goto error_param;
+ }
+ } else {
+- enum ice_status status;
+- u8 promisc_m;
+-
+- if (alluni) {
+- if (vf->port_vlan_info || vsi->num_vlan)
+- promisc_m = ICE_UCAST_VLAN_PROMISC_BITS;
+- else
+- promisc_m = ICE_UCAST_PROMISC_BITS;
+- } else if (allmulti) {
+- if (vf->port_vlan_info || vsi->num_vlan)
+- promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
+- else
+- promisc_m = ICE_MCAST_PROMISC_BITS;
++ u8 mcast_m, ucast_m;
++
++ if (vf->port_vlan_info || vsi->num_vlan > 1) {
++ mcast_m = ICE_MCAST_VLAN_PROMISC_BITS;
++ ucast_m = ICE_UCAST_VLAN_PROMISC_BITS;
+ } else {
+- if (vf->port_vlan_info || vsi->num_vlan)
+- promisc_m = ICE_UCAST_VLAN_PROMISC_BITS;
+- else
+- promisc_m = ICE_UCAST_PROMISC_BITS;
++ mcast_m = ICE_MCAST_PROMISC_BITS;
++ ucast_m = ICE_UCAST_PROMISC_BITS;
+ }
+
+- /* Configure multicast/unicast with or without VLAN promiscuous
+- * mode
+- */
+- status = ice_vf_set_vsi_promisc(vf, vsi, promisc_m, rm_promisc);
+- if (status) {
+- dev_err(dev, "%sable Tx/Rx filter promiscuous mode on VF-%d failed, error: %s\n",
+- rm_promisc ? "dis" : "en", vf->vf_id,
+- ice_stat_str(status));
+- v_ret = ice_err_to_virt_err(status);
+- goto error_param;
+- } else {
+- dev_dbg(dev, "%sable Tx/Rx filter promiscuous mode on VF-%d succeeded\n",
+- rm_promisc ? "dis" : "en", vf->vf_id);
++ ucast_status = ice_vf_set_vsi_promisc(vf, vsi, ucast_m,
++ !alluni);
++ if (ucast_status) {
++ dev_err(dev, "%sable Tx/Rx filter promiscuous mode on VF-%d failed\n",
++ alluni ? "en" : "dis", vf->vf_id);
++ v_ret = ice_err_to_virt_err(ucast_status);
++ }
++
++ mcast_status = ice_vf_set_vsi_promisc(vf, vsi, mcast_m,
++ !allmulti);
++ if (mcast_status) {
++ dev_err(dev, "%sable Tx/Rx filter promiscuous mode on VF-%d failed\n",
++ allmulti ? "en" : "dis", vf->vf_id);
++ v_ret = ice_err_to_virt_err(mcast_status);
+ }
+ }
+
+- if (allmulti &&
+- !test_and_set_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
+- dev_info(dev, "VF %u successfully set multicast promiscuous mode\n", vf->vf_id);
+- else if (!allmulti && test_and_clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
+- dev_info(dev, "VF %u successfully unset multicast promiscuous mode\n", vf->vf_id);
++ if (!mcast_status) {
++ if (allmulti &&
++ !test_and_set_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
++ dev_info(dev, "VF %u successfully set multicast promiscuous mode\n",
++ vf->vf_id);
++ else if (!allmulti && test_and_clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
++ dev_info(dev, "VF %u successfully unset multicast promiscuous mode\n",
++ vf->vf_id);
++ }
+
+- if (alluni && !test_and_set_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states))
+- dev_info(dev, "VF %u successfully set unicast promiscuous mode\n", vf->vf_id);
+- else if (!alluni && test_and_clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states))
+- dev_info(dev, "VF %u successfully unset unicast promiscuous mode\n", vf->vf_id);
++ if (!ucast_status) {
++ if (alluni && !test_and_set_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states))
++ dev_info(dev, "VF %u successfully set unicast promiscuous mode\n",
++ vf->vf_id);
++ else if (!alluni && test_and_clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states))
++ dev_info(dev, "VF %u successfully unset unicast promiscuous mode\n",
++ vf->vf_id);
++ }
+
+ error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+@@ -3762,6 +3762,7 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+ struct device *dev = ice_pf_to_dev(vf->pf);
+ u8 *mac_addr = vc_ether_addr->addr;
+ enum ice_status status;
++ int ret = 0;
+
+ /* device MAC already added */
+ if (ether_addr_equal(mac_addr, vf->dev_lan_addr.addr))
+@@ -3774,20 +3775,23 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+
+ status = ice_fltr_add_mac(vsi, mac_addr, ICE_FWD_TO_VSI);
+ if (status == ICE_ERR_ALREADY_EXISTS) {
+- dev_err(dev, "MAC %pM already exists for VF %d\n", mac_addr,
++ dev_dbg(dev, "MAC %pM already exists for VF %d\n", mac_addr,
+ vf->vf_id);
+- return -EEXIST;
++ /* don't return since we might need to update
++ * the primary MAC in ice_vfhw_mac_add() below
++ */
++ ret = -EEXIST;
+ } else if (status) {
+ dev_err(dev, "Failed to add MAC %pM for VF %d\n, error %s\n",
+ mac_addr, vf->vf_id, ice_stat_str(status));
+ return -EIO;
++ } else {
++ vf->num_mac++;
+ }
+
+ ice_vfhw_mac_add(vf, vc_ether_addr);
+
+- vf->num_mac++;
+-
+- return 0;
++ return ret;
+ }
+
+ /**
+diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
+index 842cb077df861..38b4dc82c5c18 100644
+--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
+@@ -111,9 +111,13 @@ struct ice_vf {
+ struct ice_mdd_vf_events mdd_rx_events;
+ struct ice_mdd_vf_events mdd_tx_events;
+ DECLARE_BITMAP(opcodes_allowlist, VIRTCHNL_OP_MAX);
++
++ /* devlink port data */
++ struct devlink_port devlink_port;
+ };
+
+ #ifdef CONFIG_PCI_IOV
++struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf);
+ void ice_process_vflr_event(struct ice_pf *pf);
+ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs);
+ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
+@@ -171,6 +175,11 @@ static inline void ice_print_vfs_mdd_events(struct ice_pf *pf) { }
+ static inline void ice_print_vf_rx_mdd_event(struct ice_vf *vf) { }
+ static inline void ice_restore_all_vfs_msi_state(struct pci_dev *pdev) { }
+
++static inline struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf)
++{
++ return NULL;
++}
++
+ static inline bool
+ ice_is_malicious_vf(struct ice_pf __always_unused *pf,
+ struct ice_rq_event_info __always_unused *event,
+diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
+index 751de06019a0e..533199d819501 100644
+--- a/drivers/net/ethernet/intel/igb/igb_main.c
++++ b/drivers/net/ethernet/intel/igb/igb_main.c
+@@ -7641,6 +7641,20 @@ static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf,
+ 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 */
+@@ -7654,20 +7668,6 @@ static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf,
+ }
+ 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);
+@@ -8019,7 +8019,7 @@ static int igb_poll(struct napi_struct *napi, int budget)
+ if (likely(napi_complete_done(napi, work_done)))
+ igb_ring_irq_enable(q_vector);
+
+- return min(work_done, budget - 1);
++ return work_done;
+ }
+
+ /**
+diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
+index d32e72d953c8d..d051918dfdff9 100644
+--- a/drivers/net/ethernet/intel/igbvf/netdev.c
++++ b/drivers/net/ethernet/intel/igbvf/netdev.c
+@@ -2861,6 +2861,7 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ return 0;
+
+ err_hw_init:
++ netif_napi_del(&adapter->rx_ring->napi);
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+ err_sw_init:
+diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c
+index b2ef9fde97b38..b6807e16eea93 100644
+--- a/drivers/net/ethernet/intel/igc/igc_i225.c
++++ b/drivers/net/ethernet/intel/igc/igc_i225.c
+@@ -636,7 +636,7 @@ s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
+ ltrv = rd32(IGC_LTRMAXV);
+ if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
+ ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
+- (scale_min << IGC_LTRMAXV_SCALE_SHIFT);
++ (scale_max << IGC_LTRMAXV_SCALE_SHIFT);
+ wr32(IGC_LTRMAXV, ltrv);
+ }
+ }
+diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
+index 0f021909b430a..30568e3544cda 100644
+--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
+@@ -773,7 +773,7 @@ static bool igc_is_crosststamp_supported(struct igc_adapter *adapter)
+
+ static struct system_counterval_t igc_device_tstamp_to_system(u64 tstamp)
+ {
+-#if IS_ENABLED(CONFIG_X86_TSC)
++#if IS_ENABLED(CONFIG_X86_TSC) && !defined(CONFIG_UML)
+ return convert_art_ns_to_tsc(tstamp);
+ #else
+ return (struct system_counterval_t) { };
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+index 13c4782b920a7..750b02bb2fdc2 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+@@ -5526,6 +5526,10 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
+ if (!speed && hw->mac.ops.get_link_capabilities) {
+ ret = hw->mac.ops.get_link_capabilities(hw, &speed,
+ &autoneg);
++ /* remove NBASE-T speeds from default autonegotiation
++ * to accommodate broken network switches in the field
++ * which cannot cope with advertised NBASE-T speeds
++ */
+ speed &= ~(IXGBE_LINK_SPEED_5GB_FULL |
+ IXGBE_LINK_SPEED_2_5GB_FULL);
+ }
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+index 9724ffb165189..e4b50c7781ffa 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+@@ -3405,6 +3405,9 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
+ /* 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 ||
+diff --git a/drivers/net/ethernet/litex/litex_liteeth.c b/drivers/net/ethernet/litex/litex_liteeth.c
+index a9bdbf0dcfe1e..5bb1cc8a2ce13 100644
+--- a/drivers/net/ethernet/litex/litex_liteeth.c
++++ b/drivers/net/ethernet/litex/litex_liteeth.c
+@@ -289,7 +289,6 @@ static int liteeth_remove(struct platform_device *pdev)
+ struct net_device *netdev = platform_get_drvdata(pdev);
+
+ unregister_netdev(netdev);
+- free_netdev(netdev);
+
+ return 0;
+ }
+diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
+index 62a97c46fba05..ef878973b8597 100644
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -429,12 +429,14 @@ static const struct of_device_id orion_mdio_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, orion_mdio_match);
+
++#ifdef CONFIG_ACPI
+ static const struct acpi_device_id orion_mdio_acpi_match[] = {
+ { "MRVL0100", BUS_TYPE_SMI },
+ { "MRVL0101", BUS_TYPE_XSMI },
+ { },
+ };
+ MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match);
++#endif
+
+ static struct platform_driver orion_mdio_driver = {
+ .probe = orion_mdio_probe,
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+index d5c92e43f89e6..2baa909290b3b 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+@@ -1605,7 +1605,7 @@ static void mvpp22_gop_fca_set_periodic_timer(struct mvpp2_port *port)
+ mvpp22_gop_fca_enable_periodic(port, true);
+ }
+
+-static int mvpp22_gop_init(struct mvpp2_port *port)
++static int mvpp22_gop_init(struct mvpp2_port *port, phy_interface_t interface)
+ {
+ struct mvpp2 *priv = port->priv;
+ u32 val;
+@@ -1613,7 +1613,7 @@ static int mvpp22_gop_init(struct mvpp2_port *port)
+ if (!priv->sysctrl_base)
+ return 0;
+
+- switch (port->phy_interface) {
++ switch (interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+@@ -1743,15 +1743,15 @@ static void mvpp22_gop_setup_irq(struct mvpp2_port *port)
+ * lanes by the physical layer. This is why configurations like
+ * "PPv2 (2500BaseX) - COMPHY (2500SGMII)" are valid.
+ */
+-static int mvpp22_comphy_init(struct mvpp2_port *port)
++static int mvpp22_comphy_init(struct mvpp2_port *port,
++ phy_interface_t interface)
+ {
+ int ret;
+
+ if (!port->comphy)
+ return 0;
+
+- ret = phy_set_mode_ext(port->comphy, PHY_MODE_ETHERNET,
+- port->phy_interface);
++ ret = phy_set_mode_ext(port->comphy, PHY_MODE_ETHERNET, interface);
+ if (ret)
+ return ret;
+
+@@ -2172,7 +2172,8 @@ static void mvpp22_pcs_reset_assert(struct mvpp2_port *port)
+ writel(val & ~MVPP22_XPCS_CFG0_RESET_DIS, xpcs + MVPP22_XPCS_CFG0);
+ }
+
+-static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port)
++static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port,
++ phy_interface_t interface)
+ {
+ struct mvpp2 *priv = port->priv;
+ void __iomem *mpcs, *xpcs;
+@@ -2184,7 +2185,7 @@ static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port)
+ mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
+ xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);
+
+- switch (port->phy_interface) {
++ switch (interface) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
+ val |= MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX |
+@@ -2959,11 +2960,11 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
+ mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size);
+
+ if (priv->percpu_pools) {
+- err = xdp_rxq_info_reg(&rxq->xdp_rxq_short, port->dev, rxq->id, 0);
++ err = xdp_rxq_info_reg(&rxq->xdp_rxq_short, port->dev, rxq->logic_rxq, 0);
+ if (err < 0)
+ goto err_free_dma;
+
+- err = xdp_rxq_info_reg(&rxq->xdp_rxq_long, port->dev, rxq->id, 0);
++ err = xdp_rxq_info_reg(&rxq->xdp_rxq_long, port->dev, rxq->logic_rxq, 0);
+ if (err < 0)
+ goto err_unregister_rxq_short;
+
+@@ -4529,7 +4530,8 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
+ return rx_done;
+ }
+
+-static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
++static void mvpp22_mode_reconfigure(struct mvpp2_port *port,
++ phy_interface_t interface)
+ {
+ u32 ctrl3;
+
+@@ -4540,18 +4542,18 @@ static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
+ mvpp22_pcs_reset_assert(port);
+
+ /* comphy reconfiguration */
+- mvpp22_comphy_init(port);
++ mvpp22_comphy_init(port, interface);
+
+ /* gop reconfiguration */
+- mvpp22_gop_init(port);
++ mvpp22_gop_init(port, interface);
+
+- mvpp22_pcs_reset_deassert(port);
++ mvpp22_pcs_reset_deassert(port, interface);
+
+ if (mvpp2_port_supports_xlg(port)) {
+ ctrl3 = readl(port->base + MVPP22_XLG_CTRL3_REG);
+ ctrl3 &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+
+- if (mvpp2_is_xlg(port->phy_interface))
++ if (mvpp2_is_xlg(interface))
+ ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_10G;
+ else
+ ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
+@@ -4559,7 +4561,7 @@ static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
+ writel(ctrl3, port->base + MVPP22_XLG_CTRL3_REG);
+ }
+
+- if (mvpp2_port_supports_xlg(port) && mvpp2_is_xlg(port->phy_interface))
++ if (mvpp2_port_supports_xlg(port) && mvpp2_is_xlg(interface))
+ mvpp2_xlg_max_rx_size_set(port);
+ else
+ mvpp2_gmac_max_rx_size_set(port);
+@@ -4579,7 +4581,7 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
+ mvpp2_interrupts_enable(port);
+
+ if (port->priv->hw_version >= MVPP22)
+- mvpp22_mode_reconfigure(port);
++ mvpp22_mode_reconfigure(port, port->phy_interface);
+
+ if (port->phylink) {
+ phylink_start(port->phylink);
+@@ -5015,11 +5017,13 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
+ mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8);
+ }
+
++ if (port->xdp_prog && mtu > MVPP2_MAX_RX_BUF_SIZE) {
++ netdev_err(dev, "Illegal MTU value %d (> %d) for XDP mode\n",
++ mtu, (int)MVPP2_MAX_RX_BUF_SIZE);
++ return -EINVAL;
++ }
++
+ if (MVPP2_RX_PKT_SIZE(mtu) > MVPP2_BM_LONG_PKT_SIZE) {
+- if (port->xdp_prog) {
+- netdev_err(dev, "Jumbo frames are not supported with XDP\n");
+- return -EINVAL;
+- }
+ if (priv->percpu_pools) {
+ netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu);
+ mvpp2_bm_switch_buffers(priv, false);
+@@ -5305,8 +5309,8 @@ static int mvpp2_xdp_setup(struct mvpp2_port *port, struct netdev_bpf *bpf)
+ bool running = netif_running(port->dev);
+ bool reset = !prog != !port->xdp_prog;
+
+- if (port->dev->mtu > ETH_DATA_LEN) {
+- NL_SET_ERR_MSG_MOD(bpf->extack, "XDP is not supported with jumbo frames enabled");
++ if (port->dev->mtu > MVPP2_MAX_RX_BUF_SIZE) {
++ NL_SET_ERR_MSG_MOD(bpf->extack, "MTU too large for XDP");
+ return -EOPNOTSUPP;
+ }
+
+@@ -6477,6 +6481,9 @@ static int mvpp2__mac_prepare(struct phylink_config *config, unsigned int mode,
+ mvpp22_gop_mask_irq(port);
+
+ phy_power_off(port->comphy);
++
++ /* Reconfigure the serdes lanes */
++ mvpp22_mode_reconfigure(port, interface);
+ }
+ }
+
+@@ -6531,9 +6538,6 @@ static int mvpp2_mac_finish(struct phylink_config *config, unsigned int mode,
+ port->phy_interface != interface) {
+ port->phy_interface = interface;
+
+- /* Reconfigure the serdes lanes */
+- mvpp22_mode_reconfigure(port);
+-
+ /* Unmask interrupts */
+ mvpp22_gop_unmask_irq(port);
+ }
+@@ -6960,7 +6964,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
+ * driver does this, we can remove this code.
+ */
+ if (port->comphy) {
+- err = mvpp22_comphy_init(port);
++ err = mvpp22_comphy_init(port, port->phy_interface);
+ if (err == 0)
+ phy_power_off(port->comphy);
+ }
+@@ -7453,7 +7457,7 @@ static int mvpp2_probe(struct platform_device *pdev)
+
+ 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++) {
+diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig
+index 3f982ccf2c85f..639893d870550 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/Kconfig
++++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig
+@@ -31,6 +31,7 @@ config NDC_DIS_DYNAMIC_CACHING
+ config OCTEONTX2_PF
+ tristate "Marvell OcteonTX2 NIC Physical Function driver"
+ select OCTEONTX2_MBOX
++ select NET_DEVLINK
+ depends on (64BIT && COMPILE_TEST) || ARM64
+ depends on PCI
+ depends on PTP_1588_CLOCK_OPTIONAL
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+index 35836903b7fbc..90dc5343827f0 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+@@ -2281,7 +2281,7 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw,
+ goto free_regions;
+ break;
+ default:
+- return err;
++ goto free_regions;
+ }
+
+ mw->mbox_wq = alloc_workqueue(name,
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+index 53df7fff92c40..53a3e8de1a51e 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+@@ -1493,6 +1493,44 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
+ mutex_unlock(&mbox->lock);
+ }
+
++static void otx2_do_set_rx_mode(struct otx2_nic *pf)
++{
++ struct net_device *netdev = pf->netdev;
++ struct nix_rx_mode *req;
++ bool promisc = false;
++
++ if (!(netdev->flags & IFF_UP))
++ return;
++
++ if ((netdev->flags & IFF_PROMISC) ||
++ (netdev_uc_count(netdev) > OTX2_MAX_UNICAST_FLOWS)) {
++ promisc = true;
++ }
++
++ /* Write unicast address to mcam entries or del from mcam */
++ if (!promisc && netdev->priv_flags & IFF_UNICAST_FLT)
++ __dev_uc_sync(netdev, otx2_add_macfilter, otx2_del_macfilter);
++
++ mutex_lock(&pf->mbox.lock);
++ req = otx2_mbox_alloc_msg_nix_set_rx_mode(&pf->mbox);
++ if (!req) {
++ mutex_unlock(&pf->mbox.lock);
++ return;
++ }
++
++ req->mode = NIX_RX_MODE_UCAST;
++
++ if (promisc)
++ req->mode |= NIX_RX_MODE_PROMISC;
++ if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
++ req->mode |= NIX_RX_MODE_ALLMULTI;
++
++ req->mode |= NIX_RX_MODE_USE_MCE;
++
++ otx2_sync_mbox_msg(&pf->mbox);
++ mutex_unlock(&pf->mbox.lock);
++}
++
+ int otx2_open(struct net_device *netdev)
+ {
+ struct otx2_nic *pf = netdev_priv(netdev);
+@@ -1646,6 +1684,8 @@ int otx2_open(struct net_device *netdev)
+ if (err)
+ goto err_tx_stop_queues;
+
++ otx2_do_set_rx_mode(pf);
++
+ return 0;
+
+ err_tx_stop_queues:
+@@ -1791,43 +1831,11 @@ static void otx2_set_rx_mode(struct net_device *netdev)
+ queue_work(pf->otx2_wq, &pf->rx_mode_work);
+ }
+
+-static void otx2_do_set_rx_mode(struct work_struct *work)
++static void otx2_rx_mode_wrk_handler(struct work_struct *work)
+ {
+ struct otx2_nic *pf = container_of(work, struct otx2_nic, rx_mode_work);
+- struct net_device *netdev = pf->netdev;
+- struct nix_rx_mode *req;
+- bool promisc = false;
+-
+- if (!(netdev->flags & IFF_UP))
+- return;
+-
+- if ((netdev->flags & IFF_PROMISC) ||
+- (netdev_uc_count(netdev) > OTX2_MAX_UNICAST_FLOWS)) {
+- promisc = true;
+- }
+
+- /* Write unicast address to mcam entries or del from mcam */
+- if (!promisc && netdev->priv_flags & IFF_UNICAST_FLT)
+- __dev_uc_sync(netdev, otx2_add_macfilter, otx2_del_macfilter);
+-
+- mutex_lock(&pf->mbox.lock);
+- req = otx2_mbox_alloc_msg_nix_set_rx_mode(&pf->mbox);
+- if (!req) {
+- mutex_unlock(&pf->mbox.lock);
+- return;
+- }
+-
+- req->mode = NIX_RX_MODE_UCAST;
+-
+- if (promisc)
+- req->mode |= NIX_RX_MODE_PROMISC;
+- if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+- req->mode |= NIX_RX_MODE_ALLMULTI;
+-
+- req->mode |= NIX_RX_MODE_USE_MCE;
+-
+- otx2_sync_mbox_msg(&pf->mbox);
+- mutex_unlock(&pf->mbox.lock);
++ otx2_do_set_rx_mode(pf);
+ }
+
+ static int otx2_set_features(struct net_device *netdev,
+@@ -2358,7 +2366,7 @@ static int otx2_wq_init(struct otx2_nic *pf)
+ if (!pf->otx2_wq)
+ return -ENOMEM;
+
+- INIT_WORK(&pf->rx_mode_work, otx2_do_set_rx_mode);
++ INIT_WORK(&pf->rx_mode_work, otx2_rx_mode_wrk_handler);
+ INIT_WORK(&pf->reset_task, otx2_reset_task);
+ return 0;
+ }
+diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
+index 3ce6ccd0f5394..b4599fe4ca8da 100644
+--- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
++++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
+@@ -497,8 +497,8 @@ int prestera_bridge_port_join(struct net_device *br_dev,
+
+ br_port = prestera_bridge_port_add(bridge, port->dev);
+ if (IS_ERR(br_port)) {
+- err = PTR_ERR(br_port);
+- goto err_brport_create;
++ prestera_bridge_put(bridge);
++ return PTR_ERR(br_port);
+ }
+
+ err = switchdev_bridge_port_offload(br_port->dev, port->dev, NULL,
+@@ -519,8 +519,6 @@ err_port_join:
+ switchdev_bridge_port_unoffload(br_port->dev, NULL, NULL, NULL);
+ err_switchdev_offload:
+ prestera_bridge_port_put(br_port);
+-err_brport_create:
+- prestera_bridge_put(bridge);
+ return err;
+ }
+
+@@ -1124,7 +1122,7 @@ static int prestera_switchdev_blk_event(struct notifier_block *unused,
+ prestera_port_obj_attr_set);
+ break;
+ default:
+- err = -EOPNOTSUPP;
++ return NOTIFY_DONE;
+ }
+
+ return notifier_from_errno(err);
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+index ef518b1040f72..fde521b1eecad 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+@@ -663,7 +663,7 @@ void __init mlx4_en_init_ptys2ethtool_map(void)
+ 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 @@ void __init mlx4_en_init_ptys2ethtool_map(void)
+ 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);
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+index 8af7f28273225..3bd3603873e32 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+@@ -2286,9 +2286,14 @@ int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv,
+ 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,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+index db5dfff585c99..bea35530c2d0b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+@@ -334,6 +334,9 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
+ case MLX5_CMD_OP_PAGE_FAULT_RESUME:
+ case MLX5_CMD_OP_QUERY_ESW_FUNCTIONS:
+ case MLX5_CMD_OP_DEALLOC_SF:
++ case MLX5_CMD_OP_DESTROY_UCTX:
++ case MLX5_CMD_OP_DESTROY_UMEM:
++ case MLX5_CMD_OP_MODIFY_RQT:
+ return MLX5_CMD_STAT_OK;
+
+ case MLX5_CMD_OP_QUERY_HCA_CAP:
+@@ -439,7 +442,6 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
+ case MLX5_CMD_OP_MODIFY_TIS:
+ case MLX5_CMD_OP_QUERY_TIS:
+ case MLX5_CMD_OP_CREATE_RQT:
+- case MLX5_CMD_OP_MODIFY_RQT:
+ case MLX5_CMD_OP_QUERY_RQT:
+
+ case MLX5_CMD_OP_CREATE_FLOW_TABLE:
+@@ -459,9 +461,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
+ case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_CREATE_UCTX:
+- case MLX5_CMD_OP_DESTROY_UCTX:
+ case MLX5_CMD_OP_CREATE_UMEM:
+- case MLX5_CMD_OP_DESTROY_UMEM:
+ case MLX5_CMD_OP_ALLOC_MEMIC:
+ case MLX5_CMD_OP_MODIFY_XRQ:
+ case MLX5_CMD_OP_RELEASE_XRQ_ERROR:
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+index 02e77ffe5c3e4..5371ad0a12eb5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+@@ -164,13 +164,14 @@ int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+ MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
+ MLX5_SET(destroy_cq_in, in, uid, cq->uid);
+ err = mlx5_cmd_exec_in(dev, destroy_cq, in);
++ if (err)
++ return err;
+
+ synchronize_irq(cq->irqn);
+-
+ mlx5_cq_put(cq);
+ wait_for_completion(&cq->free);
+
+- return err;
++ return 0;
+ }
+ EXPORT_SYMBOL(mlx5_core_destroy_cq);
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
+index 07c8d9811bc81..10d195042ab55 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
+@@ -507,6 +507,8 @@ void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+ if (!mlx5_debugfs_root)
+ return;
+
+- if (cq->dbg)
++ if (cq->dbg) {
+ rem_res_tree(cq->dbg);
++ cq->dbg = NULL;
++ }
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index dcf9f27ba2efd..d7576b6fa43b7 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -625,7 +625,6 @@ static int mlx5_devlink_eth_param_register(struct devlink *devlink)
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
+ value);
+- devlink_param_publish(devlink, &enable_eth_param);
+ return 0;
+ }
+
+@@ -636,7 +635,6 @@ static void mlx5_devlink_eth_param_unregister(struct devlink *devlink)
+ if (!mlx5_eth_supported(dev))
+ return;
+
+- devlink_param_unpublish(devlink, &enable_eth_param);
+ devlink_param_unregister(devlink, &enable_eth_param);
+ }
+
+@@ -672,7 +670,6 @@ static int mlx5_devlink_rdma_param_register(struct devlink *devlink)
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
+ value);
+- devlink_param_publish(devlink, &enable_rdma_param);
+ return 0;
+ }
+
+@@ -681,7 +678,6 @@ static void mlx5_devlink_rdma_param_unregister(struct devlink *devlink)
+ if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND))
+ return;
+
+- devlink_param_unpublish(devlink, &enable_rdma_param);
+ devlink_param_unregister(devlink, &enable_rdma_param);
+ }
+
+@@ -706,7 +702,6 @@ static int mlx5_devlink_vnet_param_register(struct devlink *devlink)
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
+ value);
+- devlink_param_publish(devlink, &enable_rdma_param);
+ return 0;
+ }
+
+@@ -717,7 +712,6 @@ static void mlx5_devlink_vnet_param_unregister(struct devlink *devlink)
+ if (!mlx5_vnet_supported(dev))
+ return;
+
+- devlink_param_unpublish(devlink, &enable_vnet_param);
+ devlink_param_unregister(devlink, &enable_vnet_param);
+ }
+
+@@ -799,16 +793,12 @@ int mlx5_devlink_register(struct devlink *devlink)
+ {
+ int err;
+
+- err = devlink_register(devlink);
+- if (err)
+- return err;
+-
+ err = devlink_params_register(devlink, mlx5_devlink_params,
+ ARRAY_SIZE(mlx5_devlink_params));
+ if (err)
+- goto params_reg_err;
++ return err;
++
+ mlx5_devlink_set_params_init_values(devlink);
+- devlink_params_publish(devlink);
+
+ err = mlx5_devlink_auxdev_params_register(devlink);
+ if (err)
+@@ -825,8 +815,6 @@ traps_reg_err:
+ auxdev_reg_err:
+ devlink_params_unregister(devlink, mlx5_devlink_params,
+ ARRAY_SIZE(mlx5_devlink_params));
+-params_reg_err:
+- devlink_unregister(devlink);
+ return err;
+ }
+
+@@ -834,8 +822,6 @@ void mlx5_devlink_unregister(struct devlink *devlink)
+ {
+ mlx5_devlink_traps_unregister(devlink);
+ mlx5_devlink_auxdev_params_unregister(devlink);
+- devlink_params_unpublish(devlink);
+ devlink_params_unregister(devlink, mlx5_devlink_params,
+ ARRAY_SIZE(mlx5_devlink_params));
+- devlink_unregister(devlink);
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index 03a7a4ce5cd5e..c10a107a3ea53 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -244,6 +244,17 @@ enum mlx5e_priv_flag {
+
+ #define MLX5E_GET_PFLAG(params, pflag) (!!((params)->pflags & (BIT(pflag))))
+
++enum packet_merge {
++ MLX5E_PACKET_MERGE_NONE,
++ MLX5E_PACKET_MERGE_LRO,
++ MLX5E_PACKET_MERGE_SHAMPO,
++};
++
++struct mlx5e_packet_merge_param {
++ enum packet_merge type;
++ u32 timeout;
++};
++
+ struct mlx5e_params {
+ u8 log_sq_size;
+ u8 rq_wq_type;
+@@ -258,13 +269,12 @@ struct mlx5e_params {
+ bool tunneled_offload_en;
+ struct dim_cq_moder rx_cq_moderation;
+ struct dim_cq_moder tx_cq_moderation;
+- bool lro_en;
++ struct mlx5e_packet_merge_param packet_merge;
+ u8 tx_min_inline_mode;
+ bool vlan_strip_disable;
+ bool scatter_fcs_en;
+ bool rx_dim_enabled;
+ bool tx_dim_enabled;
+- u32 lro_timeout;
+ u32 pflags;
+ struct bpf_prog *xdp_prog;
+ struct mlx5e_xsk *xsk;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+index 3cbb596821e89..15f441a1b80c2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+@@ -87,7 +87,8 @@ bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params,
+ u32 linear_frag_sz = max(mlx5e_rx_get_linear_frag_sz(params, xsk),
+ mlx5e_rx_get_linear_frag_sz(params, NULL));
+
+- return !params->lro_en && linear_frag_sz <= PAGE_SIZE;
++ return params->packet_merge.type == MLX5E_PACKET_MERGE_NONE &&
++ linear_frag_sz <= PAGE_SIZE;
+ }
+
+ bool mlx5e_verify_rx_mpwqe_strides(struct mlx5_core_dev *mdev,
+@@ -164,19 +165,8 @@ u16 mlx5e_get_rq_headroom(struct mlx5_core_dev *mdev,
+ mlx5e_rx_is_linear_skb(params, xsk) :
+ mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk);
+
+- return is_linear_skb ? mlx5e_get_linear_rq_headroom(params, xsk) : 0;
+-}
+-
+-struct mlx5e_lro_param mlx5e_get_lro_param(struct mlx5e_params *params)
+-{
+- struct mlx5e_lro_param lro_param;
+-
+- lro_param = (struct mlx5e_lro_param) {
+- .enabled = params->lro_en,
+- .timeout = params->lro_timeout,
+- };
+-
+- return lro_param;
++ return is_linear_skb || params->packet_merge.type == MLX5E_PACKET_MERGE_SHAMPO ?
++ mlx5e_get_linear_rq_headroom(params, xsk) : 0;
+ }
+
+ u16 mlx5e_calc_sq_stop_room(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
+@@ -485,10 +475,11 @@ static void mlx5e_build_rx_cq_param(struct mlx5_core_dev *mdev,
+
+ static u8 rq_end_pad_mode(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
+ {
++ bool lro_en = params->packet_merge.type == MLX5E_PACKET_MERGE_LRO;
+ bool ro = pcie_relaxed_ordering_enabled(mdev->pdev) &&
+ MLX5_CAP_GEN(mdev, relaxed_ordering_write);
+
+- return ro && params->lro_en ?
++ return ro && lro_en ?
+ MLX5_WQ_END_PAD_MODE_NONE : MLX5_WQ_END_PAD_MODE_ALIGN;
+ }
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+index 879ad46d754e1..e9593f5f06610 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+@@ -11,11 +11,6 @@ struct mlx5e_xsk_param {
+ u16 chunk_size;
+ };
+
+-struct mlx5e_lro_param {
+- bool enabled;
+- u32 timeout;
+-};
+-
+ struct mlx5e_cq_param {
+ u32 cqc[MLX5_ST_SZ_DW(cqc)];
+ struct mlx5_wq_param wq;
+@@ -125,7 +120,6 @@ u8 mlx5e_mpwqe_get_log_num_strides(struct mlx5_core_dev *mdev,
+ u16 mlx5e_get_rq_headroom(struct mlx5_core_dev *mdev,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+-struct mlx5e_lro_param mlx5e_get_lro_param(struct mlx5e_params *params);
+
+ /* Build queue parameters */
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c
+index 625cd49ef96c5..7b55b14d47ef7 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c
+@@ -127,7 +127,7 @@ mlx5e_rss_get_tt_config(struct mlx5e_rss *rss, enum mlx5_traffic_types tt)
+
+ static int mlx5e_rss_create_tir(struct mlx5e_rss *rss,
+ enum mlx5_traffic_types tt,
+- const struct mlx5e_lro_param *init_lro_param,
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ bool inner)
+ {
+ struct mlx5e_rss_params_traffic_type rss_tt;
+@@ -161,7 +161,7 @@ static int mlx5e_rss_create_tir(struct mlx5e_rss *rss,
+ rqtn = mlx5e_rqt_get_rqtn(&rss->rqt);
+ mlx5e_tir_builder_build_rqt(builder, rss->mdev->mlx5e_res.hw_objs.td.tdn,
+ rqtn, rss->inner_ft_support);
+- mlx5e_tir_builder_build_lro(builder, init_lro_param);
++ mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param);
+ rss_tt = mlx5e_rss_get_tt_config(rss, tt);
+ mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner);
+
+@@ -198,14 +198,14 @@ static void mlx5e_rss_destroy_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types
+ }
+
+ static int mlx5e_rss_create_tirs(struct mlx5e_rss *rss,
+- const struct mlx5e_lro_param *init_lro_param,
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ bool inner)
+ {
+ enum mlx5_traffic_types tt, max_tt;
+ int err;
+
+ for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
+- err = mlx5e_rss_create_tir(rss, tt, init_lro_param, inner);
++ err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
+ if (err)
+ goto err_destroy_tirs;
+ }
+@@ -297,7 +297,7 @@ int mlx5e_rss_init_no_tirs(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
+
+ int mlx5e_rss_init(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
+ bool inner_ft_support, u32 drop_rqn,
+- const struct mlx5e_lro_param *init_lro_param)
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param)
+ {
+ int err;
+
+@@ -305,12 +305,12 @@ int mlx5e_rss_init(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
+ if (err)
+ goto err_out;
+
+- err = mlx5e_rss_create_tirs(rss, init_lro_param, false);
++ err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, false);
+ if (err)
+ goto err_destroy_rqt;
+
+ if (inner_ft_support) {
+- err = mlx5e_rss_create_tirs(rss, init_lro_param, true);
++ err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, true);
+ if (err)
+ goto err_destroy_tirs;
+ }
+@@ -372,7 +372,7 @@ u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
+ */
+ int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
+ enum mlx5_traffic_types tt,
+- const struct mlx5e_lro_param *init_lro_param,
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ bool inner, u32 *tirn)
+ {
+ struct mlx5e_tir *tir;
+@@ -381,7 +381,7 @@ int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
+ if (!tir) { /* TIR doesn't exist, create one */
+ int err;
+
+- err = mlx5e_rss_create_tir(rss, tt, init_lro_param, inner);
++ err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
+ if (err)
+ return err;
+ tir = rss_get_tir(rss, tt, inner);
+@@ -418,7 +418,8 @@ void mlx5e_rss_disable(struct mlx5e_rss *rss)
+ mlx5e_rqt_get_rqtn(&rss->rqt), rss->drop_rqn, err);
+ }
+
+-int mlx5e_rss_lro_set_param(struct mlx5e_rss *rss, struct mlx5e_lro_param *lro_param)
++int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss,
++ struct mlx5e_packet_merge_param *pkt_merge_param)
+ {
+ struct mlx5e_tir_builder *builder;
+ enum mlx5_traffic_types tt;
+@@ -428,7 +429,7 @@ int mlx5e_rss_lro_set_param(struct mlx5e_rss *rss, struct mlx5e_lro_param *lro_p
+ if (!builder)
+ return -ENOMEM;
+
+- mlx5e_tir_builder_build_lro(builder, lro_param);
++ mlx5e_tir_builder_build_packet_merge(builder, pkt_merge_param);
+
+ final_err = 0;
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h
+index d522a10dadf33..c6b2164163440 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h
+@@ -17,7 +17,7 @@ struct mlx5e_rss *mlx5e_rss_alloc(void);
+ void mlx5e_rss_free(struct mlx5e_rss *rss);
+ int mlx5e_rss_init(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
+ bool inner_ft_support, u32 drop_rqn,
+- const struct mlx5e_lro_param *init_lro_param);
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param);
+ int mlx5e_rss_init_no_tirs(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
+ bool inner_ft_support, u32 drop_rqn);
+ int mlx5e_rss_cleanup(struct mlx5e_rss *rss);
+@@ -30,13 +30,14 @@ u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
+ bool inner);
+ int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
+ enum mlx5_traffic_types tt,
+- const struct mlx5e_lro_param *init_lro_param,
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ bool inner, u32 *tirn);
+
+ void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns);
+ void mlx5e_rss_disable(struct mlx5e_rss *rss);
+
+-int mlx5e_rss_lro_set_param(struct mlx5e_rss *rss, struct mlx5e_lro_param *lro_param);
++int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss,
++ struct mlx5e_packet_merge_param *pkt_merge_param);
+ int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc);
+ int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir,
+ const u8 *key, const u8 *hfunc,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
+index 13056cb9757d4..0015a81eb9a17 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
+@@ -13,6 +13,9 @@ struct mlx5e_rx_res {
+ unsigned int max_nch;
+ u32 drop_rqn;
+
++ struct mlx5e_packet_merge_param pkt_merge_param;
++ struct rw_semaphore pkt_merge_param_sem;
++
+ struct mlx5e_rss *rss[MLX5E_MAX_NUM_RSS];
+ bool rss_active;
+ u32 rss_rqns[MLX5E_INDIR_RQT_SIZE];
+@@ -34,7 +37,7 @@ struct mlx5e_rx_res {
+ /* API for rx_res_rss_* */
+
+ static int mlx5e_rx_res_rss_init_def(struct mlx5e_rx_res *res,
+- const struct mlx5e_lro_param *init_lro_param,
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ unsigned int init_nch)
+ {
+ bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
+@@ -49,7 +52,7 @@ static int mlx5e_rx_res_rss_init_def(struct mlx5e_rx_res *res,
+ return -ENOMEM;
+
+ err = mlx5e_rss_init(rss, res->mdev, inner_ft_support, res->drop_rqn,
+- init_lro_param);
++ init_pkt_merge_param);
+ if (err)
+ goto err_rss_free;
+
+@@ -275,7 +278,7 @@ struct mlx5e_rx_res *mlx5e_rx_res_alloc(void)
+ }
+
+ static int mlx5e_rx_res_channels_init(struct mlx5e_rx_res *res,
+- const struct mlx5e_lro_param *init_lro_param)
++ const struct mlx5e_packet_merge_param *init_pkt_merge_param)
+ {
+ bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
+ struct mlx5e_tir_builder *builder;
+@@ -306,7 +309,7 @@ static int mlx5e_rx_res_channels_init(struct mlx5e_rx_res *res,
+ mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
+ mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt),
+ inner_ft_support);
+- mlx5e_tir_builder_build_lro(builder, init_lro_param);
++ mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param);
+ mlx5e_tir_builder_build_direct(builder);
+
+ err = mlx5e_tir_init(&res->channels[ix].direct_tir, builder, res->mdev, true);
+@@ -336,7 +339,7 @@ static int mlx5e_rx_res_channels_init(struct mlx5e_rx_res *res,
+ mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
+ mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
+ inner_ft_support);
+- mlx5e_tir_builder_build_lro(builder, init_lro_param);
++ mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param);
+ mlx5e_tir_builder_build_direct(builder);
+
+ err = mlx5e_tir_init(&res->channels[ix].xsk_tir, builder, res->mdev, true);
+@@ -392,6 +395,7 @@ static int mlx5e_rx_res_ptp_init(struct mlx5e_rx_res *res)
+ if (err)
+ goto out;
+
++ /* Separated from the channels RQs, does not share pkt_merge state with them */
+ mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
+ mlx5e_rqt_get_rqtn(&res->ptp.rqt),
+ inner_ft_support);
+@@ -437,7 +441,7 @@ static void mlx5e_rx_res_ptp_destroy(struct mlx5e_rx_res *res)
+
+ int mlx5e_rx_res_init(struct mlx5e_rx_res *res, struct mlx5_core_dev *mdev,
+ enum mlx5e_rx_res_features features, unsigned int max_nch,
+- u32 drop_rqn, const struct mlx5e_lro_param *init_lro_param,
++ u32 drop_rqn, const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ unsigned int init_nch)
+ {
+ int err;
+@@ -447,11 +451,14 @@ int mlx5e_rx_res_init(struct mlx5e_rx_res *res, struct mlx5_core_dev *mdev,
+ res->max_nch = max_nch;
+ res->drop_rqn = drop_rqn;
+
+- err = mlx5e_rx_res_rss_init_def(res, init_lro_param, init_nch);
++ res->pkt_merge_param = *init_pkt_merge_param;
++ init_rwsem(&res->pkt_merge_param_sem);
++
++ err = mlx5e_rx_res_rss_init_def(res, init_pkt_merge_param, init_nch);
+ if (err)
+ goto err_out;
+
+- err = mlx5e_rx_res_channels_init(res, init_lro_param);
++ err = mlx5e_rx_res_channels_init(res, init_pkt_merge_param);
+ if (err)
+ goto err_rss_destroy;
+
+@@ -513,7 +520,7 @@ u32 mlx5e_rx_res_get_tirn_ptp(struct mlx5e_rx_res *res)
+ return mlx5e_tir_get_tirn(&res->ptp.tir);
+ }
+
+-u32 mlx5e_rx_res_get_rqtn_direct(struct mlx5e_rx_res *res, unsigned int ix)
++static u32 mlx5e_rx_res_get_rqtn_direct(struct mlx5e_rx_res *res, unsigned int ix)
+ {
+ return mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt);
+ }
+@@ -645,7 +652,8 @@ int mlx5e_rx_res_xsk_deactivate(struct mlx5e_rx_res *res, unsigned int ix)
+ return err;
+ }
+
+-int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param *lro_param)
++int mlx5e_rx_res_packet_merge_set_param(struct mlx5e_rx_res *res,
++ struct mlx5e_packet_merge_param *pkt_merge_param)
+ {
+ struct mlx5e_tir_builder *builder;
+ int err, final_err;
+@@ -655,7 +663,10 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param
+ if (!builder)
+ return -ENOMEM;
+
+- mlx5e_tir_builder_build_lro(builder, lro_param);
++ down_write(&res->pkt_merge_param_sem);
++ res->pkt_merge_param = *pkt_merge_param;
++
++ mlx5e_tir_builder_build_packet_merge(builder, pkt_merge_param);
+
+ final_err = 0;
+
+@@ -665,7 +676,7 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param
+ if (!rss)
+ continue;
+
+- err = mlx5e_rss_lro_set_param(rss, lro_param);
++ err = mlx5e_rss_packet_merge_set_param(rss, pkt_merge_param);
+ if (err)
+ final_err = final_err ? : err;
+ }
+@@ -673,13 +684,14 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param
+ for (ix = 0; ix < res->max_nch; ix++) {
+ err = mlx5e_tir_modify(&res->channels[ix].direct_tir, builder);
+ if (err) {
+- mlx5_core_warn(res->mdev, "Failed to update LRO state of direct TIR %#x for channel %u: err = %d\n",
++ mlx5_core_warn(res->mdev, "Failed to update packet merge state of direct TIR %#x for channel %u: err = %d\n",
+ mlx5e_tir_get_tirn(&res->channels[ix].direct_tir), ix, err);
+ if (!final_err)
+ final_err = err;
+ }
+ }
+
++ up_write(&res->pkt_merge_param_sem);
+ mlx5e_tir_builder_free(builder);
+ return final_err;
+ }
+@@ -688,3 +700,31 @@ struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *
+ {
+ return mlx5e_rss_get_hash(res->rss[0]);
+ }
++
++int mlx5e_rx_res_tls_tir_create(struct mlx5e_rx_res *res, unsigned int rxq,
++ struct mlx5e_tir *tir)
++{
++ bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
++ struct mlx5e_tir_builder *builder;
++ u32 rqtn;
++ int err;
++
++ builder = mlx5e_tir_builder_alloc(false);
++ if (!builder)
++ return -ENOMEM;
++
++ rqtn = mlx5e_rx_res_get_rqtn_direct(res, rxq);
++
++ mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn, rqtn,
++ inner_ft_support);
++ mlx5e_tir_builder_build_direct(builder);
++ mlx5e_tir_builder_build_tls(builder);
++ down_read(&res->pkt_merge_param_sem);
++ mlx5e_tir_builder_build_packet_merge(builder, &res->pkt_merge_param);
++ err = mlx5e_tir_init(tir, builder, res->mdev, false);
++ up_read(&res->pkt_merge_param_sem);
++
++ mlx5e_tir_builder_free(builder);
++
++ return err;
++}
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
+index 4a15942d79f7d..b39b20a720e0f 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
+@@ -25,7 +25,7 @@ enum mlx5e_rx_res_features {
+ struct mlx5e_rx_res *mlx5e_rx_res_alloc(void);
+ int mlx5e_rx_res_init(struct mlx5e_rx_res *res, struct mlx5_core_dev *mdev,
+ enum mlx5e_rx_res_features features, unsigned int max_nch,
+- u32 drop_rqn, const struct mlx5e_lro_param *init_lro_param,
++ u32 drop_rqn, const struct mlx5e_packet_merge_param *init_pkt_merge_param,
+ unsigned int init_nch);
+ void mlx5e_rx_res_destroy(struct mlx5e_rx_res *res);
+ void mlx5e_rx_res_free(struct mlx5e_rx_res *res);
+@@ -37,9 +37,6 @@ u32 mlx5e_rx_res_get_tirn_rss(struct mlx5e_rx_res *res, enum mlx5_traffic_types
+ u32 mlx5e_rx_res_get_tirn_rss_inner(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt);
+ u32 mlx5e_rx_res_get_tirn_ptp(struct mlx5e_rx_res *res);
+
+-/* RQTN getters for modules that create their own TIRs */
+-u32 mlx5e_rx_res_get_rqtn_direct(struct mlx5e_rx_res *res, unsigned int ix);
+-
+ /* Activate/deactivate API */
+ void mlx5e_rx_res_channels_activate(struct mlx5e_rx_res *res, struct mlx5e_channels *chs);
+ void mlx5e_rx_res_channels_deactivate(struct mlx5e_rx_res *res);
+@@ -57,7 +54,8 @@ int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
+ u8 mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt);
+ int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt,
+ u8 rx_hash_fields);
+-int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param *lro_param);
++int mlx5e_rx_res_packet_merge_set_param(struct mlx5e_rx_res *res,
++ struct mlx5e_packet_merge_param *pkt_merge_param);
+
+ int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch);
+ int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx);
+@@ -68,4 +66,7 @@ struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx);
+ /* Workaround for hairpin */
+ struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res);
+
++/* Accel TIRs */
++int mlx5e_rx_res_tls_tir_create(struct mlx5e_rx_res *res, unsigned int rxq,
++ struct mlx5e_tir *tir);
+ #endif /* __MLX5_EN_RX_RES_H__ */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
+index 6c949abcd2e14..bc65151321ec2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
+@@ -1356,9 +1356,13 @@ mlx5_tc_ct_match_add(struct mlx5_tc_ct_priv *priv,
+ int
+ mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv *priv,
+ struct mlx5_flow_attr *attr,
++ struct mlx5e_tc_mod_hdr_acts *mod_acts,
+ const struct flow_action_entry *act,
+ struct netlink_ext_ack *extack)
+ {
++ bool clear_action = act->ct.action & TCA_CT_ACT_CLEAR;
++ int err;
++
+ if (!priv) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload of ct action isn't available");
+@@ -1369,6 +1373,17 @@ mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv *priv,
+ attr->ct_attr.ct_action = act->ct.action;
+ attr->ct_attr.nf_ft = act->ct.flow_table;
+
++ if (!clear_action)
++ goto out;
++
++ err = mlx5_tc_ct_entry_set_registers(priv, mod_acts, 0, 0, 0, 0);
++ if (err) {
++ NL_SET_ERR_MSG_MOD(extack, "Failed to set registers for ct clear");
++ return err;
++ }
++ attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
++
++out:
+ return 0;
+ }
+
+@@ -1898,23 +1913,16 @@ __mlx5_tc_ct_flow_offload_clear(struct mlx5_tc_ct_priv *ct_priv,
+
+ memcpy(pre_ct_attr, attr, attr_sz);
+
+- err = mlx5_tc_ct_entry_set_registers(ct_priv, mod_acts, 0, 0, 0, 0);
+- if (err) {
+- ct_dbg("Failed to set register for ct clear");
+- goto err_set_registers;
+- }
+-
+ mod_hdr = mlx5_modify_header_alloc(priv->mdev, ct_priv->ns_type,
+ mod_acts->num_actions,
+ mod_acts->actions);
+ if (IS_ERR(mod_hdr)) {
+ err = PTR_ERR(mod_hdr);
+ ct_dbg("Failed to add create ct clear mod hdr");
+- goto err_set_registers;
++ goto err_mod_hdr;
+ }
+
+ pre_ct_attr->modify_hdr = mod_hdr;
+- pre_ct_attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+
+ rule = mlx5_tc_rule_insert(priv, orig_spec, pre_ct_attr);
+ if (IS_ERR(rule)) {
+@@ -1930,7 +1938,7 @@ __mlx5_tc_ct_flow_offload_clear(struct mlx5_tc_ct_priv *ct_priv,
+
+ err_insert:
+ mlx5_modify_header_dealloc(priv->mdev, mod_hdr);
+-err_set_registers:
++err_mod_hdr:
+ netdev_warn(priv->netdev,
+ "Failed to offload ct clear flow, err %d\n", err);
+ kfree(pre_ct_attr);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
+index 363329f4aac61..99662af1e41a7 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
+@@ -110,6 +110,7 @@ int mlx5_tc_ct_add_no_trk_match(struct mlx5_flow_spec *spec);
+ int
+ mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv *priv,
+ struct mlx5_flow_attr *attr,
++ struct mlx5e_tc_mod_hdr_acts *mod_acts,
+ const struct flow_action_entry *act,
+ struct netlink_ext_ack *extack);
+
+@@ -172,6 +173,7 @@ mlx5_tc_ct_add_no_trk_match(struct mlx5_flow_spec *spec)
+ static inline int
+ mlx5_tc_ct_parse_action(struct mlx5_tc_ct_priv *priv,
+ struct mlx5_flow_attr *attr,
++ struct mlx5e_tc_mod_hdr_acts *mod_acts,
+ const struct flow_action_entry *act,
+ struct netlink_ext_ack *extack)
+ {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+index d1599b7b944bf..c340bf90354a0 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+@@ -102,6 +102,7 @@ struct mlx5e_tc_flow {
+ refcount_t refcnt;
+ struct rcu_head rcu_head;
+ struct completion init_done;
++ struct completion del_hw_done;
+ int tunnel_id; /* the mapped tunnel id of this flow */
+ struct mlx5_flow_attr *attr;
+ };
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+index 1c44c6c345f5d..ec0163d75dd25 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+@@ -221,8 +221,14 @@ static void mlx5e_take_tmp_flow(struct mlx5e_tc_flow *flow,
+ struct list_head *flow_list,
+ int index)
+ {
+- if (IS_ERR(mlx5e_flow_get(flow)))
++ if (IS_ERR(mlx5e_flow_get(flow))) {
++ /* Flow is being deleted concurrently. Wait for it to be
++ * unoffloaded from hardware, otherwise deleting encap will
++ * fail.
++ */
++ wait_for_completion(&flow->del_hw_done);
+ return;
++ }
+ wait_for_completion(&flow->init_done);
+
+ flow->tmp_entry_index = index;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tir.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tir.c
+index de936dc4bc483..a1afb8585e37f 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tir.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tir.c
+@@ -70,24 +70,24 @@ void mlx5e_tir_builder_build_rqt(struct mlx5e_tir_builder *builder, u32 tdn,
+ MLX5_SET(tirc, tirc, tunneled_offload_en, inner_ft_support);
+ }
+
+-void mlx5e_tir_builder_build_lro(struct mlx5e_tir_builder *builder,
+- const struct mlx5e_lro_param *lro_param)
++void mlx5e_tir_builder_build_packet_merge(struct mlx5e_tir_builder *builder,
++ const struct mlx5e_packet_merge_param *pkt_merge_param)
+ {
+ void *tirc = mlx5e_tir_builder_get_tirc(builder);
+ const unsigned int rough_max_l2_l3_hdr_sz = 256;
+
+ if (builder->modify)
+- MLX5_SET(modify_tir_in, builder->in, bitmask.lro, 1);
++ MLX5_SET(modify_tir_in, builder->in, bitmask.packet_merge, 1);
+
+- if (!lro_param->enabled)
++ if (pkt_merge_param->type == MLX5E_PACKET_MERGE_NONE)
+ return;
+
+- MLX5_SET(tirc, tirc, lro_enable_mask,
+- MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO |
+- MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO);
++ MLX5_SET(tirc, tirc, packet_merge_mask,
++ MLX5_TIRC_PACKET_MERGE_MASK_IPV4_LRO |
++ MLX5_TIRC_PACKET_MERGE_MASK_IPV6_LRO);
+ MLX5_SET(tirc, tirc, lro_max_ip_payload_size,
+ (MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ - rough_max_l2_l3_hdr_sz) >> 8);
+- MLX5_SET(tirc, tirc, lro_timeout_period_usecs, lro_param->timeout);
++ MLX5_SET(tirc, tirc, lro_timeout_period_usecs, pkt_merge_param->timeout);
+ }
+
+ static int mlx5e_hfunc_to_hw(u8 hfunc)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tir.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tir.h
+index e45149a78ed9d..857a84bcd53af 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tir.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tir.h
+@@ -18,7 +18,7 @@ struct mlx5e_rss_params_traffic_type {
+ };
+
+ struct mlx5e_tir_builder;
+-struct mlx5e_lro_param;
++struct mlx5e_packet_merge_param;
+
+ struct mlx5e_tir_builder *mlx5e_tir_builder_alloc(bool modify);
+ void mlx5e_tir_builder_free(struct mlx5e_tir_builder *builder);
+@@ -27,8 +27,8 @@ void mlx5e_tir_builder_clear(struct mlx5e_tir_builder *builder);
+ void mlx5e_tir_builder_build_inline(struct mlx5e_tir_builder *builder, u32 tdn, u32 rqn);
+ void mlx5e_tir_builder_build_rqt(struct mlx5e_tir_builder *builder, u32 tdn,
+ u32 rqtn, bool inner_ft_support);
+-void mlx5e_tir_builder_build_lro(struct mlx5e_tir_builder *builder,
+- const struct mlx5e_lro_param *lro_param);
++void mlx5e_tir_builder_build_packet_merge(struct mlx5e_tir_builder *builder,
++ const struct mlx5e_packet_merge_param *pkt_merge_param);
+ void mlx5e_tir_builder_build_rss(struct mlx5e_tir_builder *builder,
+ const struct mlx5e_rss_params_hash *rss_hash,
+ const struct mlx5e_rss_params_traffic_type *rss_tt,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+index fb5397324aa4f..2db9573a3fe69 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+@@ -191,7 +191,7 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
+ eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
+ eseg->swp_inner_l4_offset =
+ (skb->csum_start + skb->head - skb->data) / 2;
+- if (skb->protocol == htons(ETH_P_IPV6))
++ if (inner_ip_hdr(skb)->version == 6)
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ break;
+ default:
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
+index 62abce008c7b8..15711814d2d28 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
+@@ -55,6 +55,7 @@ struct mlx5e_ktls_offload_context_rx {
+ DECLARE_BITMAP(flags, MLX5E_NUM_PRIV_RX_FLAGS);
+
+ /* resync */
++ spinlock_t lock; /* protects resync fields */
+ struct mlx5e_ktls_rx_resync_ctx resync;
+ struct list_head list;
+ };
+@@ -99,25 +100,6 @@ mlx5e_ktls_rx_resync_create_resp_list(void)
+ return resp_list;
+ }
+
+-static int mlx5e_ktls_create_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir, u32 rqtn)
+-{
+- struct mlx5e_tir_builder *builder;
+- int err;
+-
+- builder = mlx5e_tir_builder_alloc(false);
+- if (!builder)
+- return -ENOMEM;
+-
+- mlx5e_tir_builder_build_rqt(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqtn, false);
+- mlx5e_tir_builder_build_direct(builder);
+- mlx5e_tir_builder_build_tls(builder);
+- err = mlx5e_tir_init(tir, builder, mdev, false);
+-
+- mlx5e_tir_builder_free(builder);
+-
+- return err;
+-}
+-
+ static void accel_rule_handle_work(struct work_struct *work)
+ {
+ struct mlx5e_ktls_offload_context_rx *priv_rx;
+@@ -386,14 +368,18 @@ static void resync_handle_seq_match(struct mlx5e_ktls_offload_context_rx *priv_r
+ struct mlx5e_icosq *sq;
+ bool trigger_poll;
+
+- memcpy(info->rec_seq, &priv_rx->resync.sw_rcd_sn_be, sizeof(info->rec_seq));
+-
+ sq = &c->async_icosq;
+ ktls_resync = sq->ktls_resync;
++ trigger_poll = false;
+
+ spin_lock_bh(&ktls_resync->lock);
+- list_add_tail(&priv_rx->list, &ktls_resync->list);
+- trigger_poll = !test_and_set_bit(MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC, &sq->state);
++ spin_lock_bh(&priv_rx->lock);
++ memcpy(info->rec_seq, &priv_rx->resync.sw_rcd_sn_be, sizeof(info->rec_seq));
++ if (list_empty(&priv_rx->list)) {
++ list_add_tail(&priv_rx->list, &ktls_resync->list);
++ trigger_poll = !test_and_set_bit(MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC, &sq->state);
++ }
++ spin_unlock_bh(&priv_rx->lock);
+ spin_unlock_bh(&ktls_resync->lock);
+
+ if (!trigger_poll)
+@@ -604,7 +590,6 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk,
+ struct mlx5_core_dev *mdev;
+ struct mlx5e_priv *priv;
+ int rxq, err;
+- u32 rqtn;
+
+ tls_ctx = tls_get_ctx(sk);
+ priv = netdev_priv(netdev);
+@@ -617,6 +602,8 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk,
+ if (err)
+ goto err_create_key;
+
++ INIT_LIST_HEAD(&priv_rx->list);
++ spin_lock_init(&priv_rx->lock);
+ priv_rx->crypto_info =
+ *(struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
+
+@@ -628,9 +615,7 @@ int mlx5e_ktls_add_rx(struct net_device *netdev, struct sock *sk,
+ priv_rx->sw_stats = &priv->tls->sw_stats;
+ mlx5e_set_ktls_rx_priv_ctx(tls_ctx, priv_rx);
+
+- rqtn = mlx5e_rx_res_get_rqtn_direct(priv->rx_res, rxq);
+-
+- err = mlx5e_ktls_create_tir(mdev, &priv_rx->tir, rqtn);
++ err = mlx5e_rx_res_tls_tir_create(priv->rx_res, rxq, &priv_rx->tir);
+ if (err)
+ goto err_create_tir;
+
+@@ -730,10 +715,14 @@ bool mlx5e_ktls_rx_handle_resync_list(struct mlx5e_channel *c, int budget)
+ priv_rx = list_first_entry(&local_list,
+ struct mlx5e_ktls_offload_context_rx,
+ list);
++ spin_lock(&priv_rx->lock);
+ cseg = post_static_params(sq, priv_rx);
+- if (IS_ERR(cseg))
++ if (IS_ERR(cseg)) {
++ spin_unlock(&priv_rx->lock);
+ break;
+- list_del(&priv_rx->list);
++ }
++ list_del_init(&priv_rx->list);
++ spin_unlock(&priv_rx->lock);
+ db_cseg = cseg;
+ }
+ if (db_cseg)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+index 9d451b8ee467c..dc9b8718c3c10 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+@@ -1954,8 +1954,8 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable)
+ return -EOPNOTSUPP;
+ if (!mlx5e_striding_rq_possible(mdev, &priv->channels.params))
+ return -EINVAL;
+- } else if (priv->channels.params.lro_en) {
+- netdev_warn(netdev, "Can't set legacy RQ with LRO, disable LRO first\n");
++ } else if (priv->channels.params.packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
++ netdev_warn(netdev, "Can't set legacy RQ with HW-GRO/LRO, disable them first\n");
+ return -EINVAL;
+ }
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+index 03693fa74a704..d32b70c62c949 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+@@ -411,7 +411,7 @@ static int flow_get_tirn(struct mlx5e_priv *priv,
+ u32 rss_context, u32 *tirn)
+ {
+ if (fs->flow_type & FLOW_RSS) {
+- struct mlx5e_lro_param lro_param;
++ struct mlx5e_packet_merge_param pkt_merge_param;
+ struct mlx5e_rss *rss;
+ u32 flow_type;
+ int err;
+@@ -426,8 +426,8 @@ static int flow_get_tirn(struct mlx5e_priv *priv,
+ if (tt < 0)
+ return -EINVAL;
+
+- lro_param = mlx5e_get_lro_param(&priv->channels.params);
+- err = mlx5e_rss_obtain_tirn(rss, tt, &lro_param, false, tirn);
++ pkt_merge_param = priv->channels.params.packet_merge;
++ err = mlx5e_rss_obtain_tirn(rss, tt, &pkt_merge_param, false, tirn);
+ if (err)
+ return err;
+ eth_rule->rss = rss;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 41ef6eb70a585..8cf5fbebd674b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -2185,17 +2185,14 @@ void mlx5e_close_channels(struct mlx5e_channels *chs)
+ chs->num = 0;
+ }
+
+-static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
++static int mlx5e_modify_tirs_packet_merge(struct mlx5e_priv *priv)
+ {
+ struct mlx5e_rx_res *res = priv->rx_res;
+- struct mlx5e_lro_param lro_param;
+
+- lro_param = mlx5e_get_lro_param(&priv->channels.params);
+-
+- return mlx5e_rx_res_lro_set_param(res, &lro_param);
++ return mlx5e_rx_res_packet_merge_set_param(res, &priv->channels.params.packet_merge);
+ }
+
+-static MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(mlx5e_modify_tirs_lro);
++static MLX5E_DEFINE_PREACTIVATE_WRAPPER_CTX(mlx5e_modify_tirs_packet_merge);
+
+ static int mlx5e_set_mtu(struct mlx5_core_dev *mdev,
+ struct mlx5e_params *params, u16 mtu)
+@@ -3270,16 +3267,25 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
+ }
+
+ new_params = *cur_params;
+- new_params.lro_en = enable;
+
+- if (cur_params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+- if (mlx5e_rx_mpwqe_is_linear_skb(mdev, cur_params, NULL) ==
+- mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_params, NULL))
+- reset = false;
++ if (enable)
++ new_params.packet_merge.type = MLX5E_PACKET_MERGE_LRO;
++ else if (new_params.packet_merge.type == MLX5E_PACKET_MERGE_LRO)
++ new_params.packet_merge.type = MLX5E_PACKET_MERGE_NONE;
++ else
++ goto out;
++
++ if (!(cur_params->packet_merge.type == MLX5E_PACKET_MERGE_SHAMPO &&
++ new_params.packet_merge.type == MLX5E_PACKET_MERGE_LRO)) {
++ if (cur_params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
++ if (mlx5e_rx_mpwqe_is_linear_skb(mdev, cur_params, NULL) ==
++ mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_params, NULL))
++ reset = false;
++ }
+ }
+
+ err = mlx5e_safe_switch_params(priv, &new_params,
+- mlx5e_modify_tirs_lro_ctx, NULL, reset);
++ mlx5e_modify_tirs_packet_merge_ctx, NULL, reset);
+ out:
+ mutex_unlock(&priv->state_lock);
+ return err;
+@@ -3606,7 +3612,7 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
+ goto out;
+ }
+
+- if (params->lro_en)
++ if (params->packet_merge.type == MLX5E_PACKET_MERGE_LRO)
+ reset = false;
+
+ if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+@@ -4063,8 +4069,8 @@ static int mlx5e_xdp_allowed(struct mlx5e_priv *priv, struct bpf_prog *prog)
+ struct net_device *netdev = priv->netdev;
+ struct mlx5e_params new_params;
+
+- if (priv->channels.params.lro_en) {
+- netdev_warn(netdev, "can't set XDP while LRO is on, disable LRO first\n");
++ if (priv->channels.params.packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
++ netdev_warn(netdev, "can't set XDP while HW-GRO/LRO is on, disable them first\n");
+ return -EINVAL;
+ }
+
+@@ -4321,9 +4327,10 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
+ params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+ /* No XSK params: checking the availability of striding RQ in general. */
+ if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
+- params->lro_en = !slow_pci_heuristic(mdev);
++ params->packet_merge.type = slow_pci_heuristic(mdev) ?
++ MLX5E_PACKET_MERGE_NONE : MLX5E_PACKET_MERGE_LRO;
+ }
+- params->lro_timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
++ params->packet_merge.timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
+
+ /* CQ moderation params */
+ rx_cq_period_mode = MLX5_CAP_GEN(mdev, cq_period_start_from_cqe) ?
+@@ -4608,7 +4615,6 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
+ {
+ struct mlx5_core_dev *mdev = priv->mdev;
+ enum mlx5e_rx_res_features features;
+- struct mlx5e_lro_param lro_param;
+ int err;
+
+ priv->rx_res = mlx5e_rx_res_alloc();
+@@ -4626,9 +4632,9 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
+ features = MLX5E_RX_RES_FEATURE_XSK | MLX5E_RX_RES_FEATURE_PTP;
+ if (priv->channels.params.tunneled_offload_en)
+ features |= MLX5E_RX_RES_FEATURE_INNER_FT;
+- lro_param = mlx5e_get_lro_param(&priv->channels.params);
+ err = mlx5e_rx_res_init(priv->rx_res, priv->mdev, features,
+- priv->max_nch, priv->drop_rq.rqn, &lro_param,
++ priv->max_nch, priv->drop_rq.rqn,
++ &priv->channels.params.packet_merge,
+ priv->channels.params.num_channels);
+ if (err)
+ goto err_close_drop_rq;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+index 0684ac6699b2d..edecd149dcab3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+@@ -793,7 +793,6 @@ int mlx5e_rep_bond_update(struct mlx5e_priv *priv, bool cleanup)
+ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
+ {
+ struct mlx5_core_dev *mdev = priv->mdev;
+- struct mlx5e_lro_param lro_param;
+ int err;
+
+ priv->rx_res = mlx5e_rx_res_alloc();
+@@ -808,9 +807,9 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
+ return err;
+ }
+
+- lro_param = mlx5e_get_lro_param(&priv->channels.params);
+ err = mlx5e_rx_res_init(priv->rx_res, priv->mdev, 0,
+- priv->max_nch, priv->drop_rq.rqn, &lro_param,
++ priv->max_nch, priv->drop_rq.rqn,
++ &priv->channels.params.packet_merge,
+ priv->channels.params.num_channels);
+ if (err)
+ goto err_close_drop_rq;
+@@ -1070,6 +1069,10 @@ static mlx5e_stats_grp_t mlx5e_ul_rep_stats_grps[] = {
+ &MLX5E_STATS_GRP(pme),
+ &MLX5E_STATS_GRP(channels),
+ &MLX5E_STATS_GRP(per_port_buff_congest),
++#ifdef CONFIG_MLX5_EN_IPSEC
++ &MLX5E_STATS_GRP(ipsec_sw),
++ &MLX5E_STATS_GRP(ipsec_hw),
++#endif
+ };
+
+ static unsigned int mlx5e_ul_rep_stats_grps_num(struct mlx5e_priv *priv)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 129ff7e0d65cc..e3b320b6d85b9 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -1544,6 +1544,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
+ else
+ mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
+ }
++ complete_all(&flow->del_hw_done);
+
+ if (mlx5_flow_has_geneve_opt(flow))
+ mlx5_geneve_tlv_option_del(priv->mdev->geneve);
+@@ -3457,7 +3458,9 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
+ attr->dest_chain = act->chain_index;
+ break;
+ case FLOW_ACTION_CT:
+- err = mlx5_tc_ct_parse_action(get_ct_priv(priv), attr, act, extack);
++ err = mlx5_tc_ct_parse_action(get_ct_priv(priv), attr,
++ &parse_attr->mod_hdr_acts,
++ act, extack);
+ if (err)
+ return err;
+
+@@ -4008,7 +4011,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
+ NL_SET_ERR_MSG_MOD(extack, "Sample action with connection tracking is not supported");
+ return -EOPNOTSUPP;
+ }
+- err = mlx5_tc_ct_parse_action(get_ct_priv(priv), attr, act, extack);
++ err = mlx5_tc_ct_parse_action(get_ct_priv(priv), attr,
++ &parse_attr->mod_hdr_acts,
++ act, extack);
+ if (err)
+ return err;
+
+@@ -4222,6 +4227,7 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
+ INIT_LIST_HEAD(&flow->l3_to_l2_reformat);
+ refcount_set(&flow->refcnt, 1);
+ init_completion(&flow->init_done);
++ init_completion(&flow->del_hw_done);
+
+ *__flow = flow;
+ *__parse_attr = parse_attr;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+index c6cc67cb4f6ad..d377ddc70fc70 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+@@ -130,7 +130,7 @@ static u32 esw_qos_calculate_min_rate_divider(struct mlx5_eswitch *esw,
+ /* If vports min rate divider is 0 but their group has bw_share configured, then
+ * need to set bw_share for vports to minimal value.
+ */
+- if (!group_level && !max_guarantee && group->bw_share)
++ if (!group_level && !max_guarantee && group && group->bw_share)
+ return 1;
+ return 0;
+ }
+@@ -423,7 +423,7 @@ static int esw_qos_vport_update_group(struct mlx5_eswitch *esw,
+ return err;
+
+ /* Recalculate bw share weights of old and new groups */
+- if (vport->qos.bw_share) {
++ if (vport->qos.bw_share || new_group->bw_share) {
+ esw_qos_normalize_vports_min_rate(esw, curr_group, extack);
+ esw_qos_normalize_vports_min_rate(esw, new_group, extack);
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+index ec136b4992045..51a8cecc4a7ce 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+@@ -1305,12 +1305,17 @@ abort:
+ */
+ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
+ {
++ bool toggle_lag;
+ int ret;
+
+ if (!mlx5_esw_allowed(esw))
+ return 0;
+
+- mlx5_lag_disable_change(esw->dev);
++ toggle_lag = esw->mode == MLX5_ESWITCH_NONE;
++
++ if (toggle_lag)
++ mlx5_lag_disable_change(esw->dev);
++
+ down_write(&esw->mode_lock);
+ if (esw->mode == MLX5_ESWITCH_NONE) {
+ ret = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY, num_vfs);
+@@ -1324,7 +1329,10 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
+ esw->esw_funcs.num_vfs = num_vfs;
+ }
+ up_write(&esw->mode_lock);
+- mlx5_lag_enable_change(esw->dev);
++
++ if (toggle_lag)
++ mlx5_lag_enable_change(esw->dev);
++
+ return ret;
+ }
+
+@@ -1572,6 +1580,11 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
+ esw->enabled_vports = 0;
+ esw->mode = MLX5_ESWITCH_NONE;
+ esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
++ if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
++ MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
++ esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
++ else
++ esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+
+ dev->priv.eswitch = esw;
+ BLOCKING_INIT_NOTIFIER_HEAD(&esw->n_head);
+@@ -1934,7 +1947,7 @@ free_out:
+ return err;
+ }
+
+-u8 mlx5_eswitch_mode(struct mlx5_core_dev *dev)
++u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
+ {
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+
+@@ -1948,7 +1961,7 @@ mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
+ struct mlx5_eswitch *esw;
+
+ esw = dev->priv.eswitch;
+- return mlx5_esw_allowed(esw) ? esw->offloads.encap :
++ return (mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS) ? esw->offloads.encap :
+ DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+ }
+ EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+index 0d461e38add37..f3f23fdc20229 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+@@ -2471,6 +2471,7 @@ static int esw_set_master_egress_rule(struct mlx5_core_dev *master,
+ struct mlx5_eswitch *esw = master->priv.eswitch;
+ struct mlx5_flow_table_attr ft_attr = {
+ .max_fte = 1, .prio = 0, .level = 0,
++ .flags = MLX5_FLOW_TABLE_OTHER_VPORT,
+ };
+ struct mlx5_flow_namespace *egress_ns;
+ struct mlx5_flow_table *acl;
+@@ -3141,12 +3142,6 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
+ u64 mapping_id;
+ int err;
+
+- if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) &&
+- MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap))
+- esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
+- else
+- esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+-
+ mutex_init(&esw->offloads.termtbl_mutex);
+ mlx5_rdma_enable_roce(esw->dev);
+
+@@ -3244,7 +3239,6 @@ void esw_offloads_disable(struct mlx5_eswitch *esw)
+ esw_offloads_metadata_uninit(esw);
+ mlx5_rdma_disable_roce(esw->dev);
+ mutex_destroy(&esw->offloads.termtbl_mutex);
+- esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+ }
+
+ static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
+@@ -3588,7 +3582,7 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
+ *encap = esw->offloads.encap;
+ unlock:
+ up_write(&esw->mode_lock);
+- return 0;
++ return err;
+ }
+
+ static bool
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+index 269ebb53eda67..cfde0a45b8b8a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+@@ -67,7 +67,7 @@ static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev,
+ MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE :
+ MLX5I_PARAMS_DEFAULT_LOG_RQ_SIZE;
+
+- params->lro_en = false;
++ params->packet_merge.type = MLX5E_PACKET_MERGE_NONE;
+ params->hard_mtu = MLX5_IB_GRH_BYTES + MLX5_IPOIB_HARD_LEN;
+ params->tunneled_offload_en = false;
+ }
+@@ -353,7 +353,6 @@ static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv)
+ static int mlx5i_init_rx(struct mlx5e_priv *priv)
+ {
+ struct mlx5_core_dev *mdev = priv->mdev;
+- struct mlx5e_lro_param lro_param;
+ int err;
+
+ priv->rx_res = mlx5e_rx_res_alloc();
+@@ -368,9 +367,9 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
+ goto err_destroy_q_counters;
+ }
+
+- lro_param = mlx5e_get_lro_param(&priv->channels.params);
+ err = mlx5e_rx_res_init(priv->rx_res, priv->mdev, 0,
+- priv->max_nch, priv->drop_rq.rqn, &lro_param,
++ priv->max_nch, priv->drop_rq.rqn,
++ &priv->channels.params.packet_merge,
+ priv->channels.params.num_channels);
+ if (err)
+ goto err_close_drop_rq;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+index d2105c1635c34..c19d9327095b2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+@@ -565,6 +565,7 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
+ bool is_bonded, is_in_lag, mode_supported;
+ int bond_status = 0;
+ int num_slaves = 0;
++ int changed = 0;
+ int idx;
+
+ if (!netif_is_lag_master(upper))
+@@ -601,27 +602,27 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
+ */
+ is_in_lag = num_slaves == MLX5_MAX_PORTS && bond_status == 0x3;
+
+- if (!mlx5_lag_is_ready(ldev) && is_in_lag) {
+- NL_SET_ERR_MSG_MOD(info->info.extack,
+- "Can't activate LAG offload, PF is configured with more than 64 VFs");
+- return 0;
+- }
+-
+ /* Lag mode must be activebackup or hash. */
+ mode_supported = tracker->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP ||
+ tracker->tx_type == NETDEV_LAG_TX_TYPE_HASH;
+
+- if (is_in_lag && !mode_supported)
+- NL_SET_ERR_MSG_MOD(info->info.extack,
+- "Can't activate LAG offload, TX type isn't supported");
+-
+ is_bonded = is_in_lag && mode_supported;
+ if (tracker->is_bonded != is_bonded) {
+ tracker->is_bonded = is_bonded;
+- return 1;
++ changed = 1;
+ }
+
+- return 0;
++ if (!is_in_lag)
++ return changed;
++
++ if (!mlx5_lag_is_ready(ldev))
++ NL_SET_ERR_MSG_MOD(info->info.extack,
++ "Can't activate LAG offload, PF is configured with more than 64 VFs");
++ else if (!mode_supported)
++ NL_SET_ERR_MSG_MOD(info->info.extack,
++ "Can't activate LAG offload, TX type isn't supported");
++
++ return changed;
+ }
+
+ static int mlx5_handle_changelowerstate_event(struct mlx5_lag *ldev,
+@@ -664,9 +665,6 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
+
+ ldev = container_of(this, struct mlx5_lag, nb);
+
+- if (!mlx5_lag_is_ready(ldev) && event == NETDEV_CHANGELOWERSTATE)
+- return NOTIFY_DONE;
+-
+ tracker = ldev->tracker;
+
+ switch (event) {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
+index 79482824c64ff..92b08fa07efae 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
+@@ -1537,6 +1537,7 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
+
+ pci_save_state(pdev);
++ devlink_register(devlink);
+ if (!mlx5_core_is_mp_slave(dev))
+ devlink_reload_enable(devlink);
+ return 0;
+@@ -1559,6 +1560,7 @@ static void remove_one(struct pci_dev *pdev)
+ struct devlink *devlink = priv_to_devlink(dev);
+
+ devlink_reload_disable(devlink);
++ devlink_unregister(devlink);
+ mlx5_crdump_disable(dev);
+ mlx5_drain_health_wq(dev);
+ mlx5_uninit_one(dev);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
+index 052f48068dc16..3cf272fa21646 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
+@@ -46,6 +46,7 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia
+ mlx5_core_warn(mdev, "mlx5_init_one err=%d\n", err);
+ goto init_one_err;
+ }
++ devlink_register(devlink);
+ devlink_reload_enable(devlink);
+ return 0;
+
+@@ -65,6 +66,7 @@ static void mlx5_sf_dev_remove(struct auxiliary_device *adev)
+
+ devlink = priv_to_devlink(sf_dev->mdev);
+ devlink_reload_disable(devlink);
++ devlink_unregister(devlink);
+ mlx5_uninit_one(sf_dev->mdev);
+ iounmap(sf_dev->mdev->iseg);
+ mlx5_mdev_uninit(sf_dev->mdev);
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+index 250c5a24264dc..edfdd44de579c 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+@@ -2131,7 +2131,7 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
+ max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
+ local_port = mlxsw_reg_pude_local_port_get(pude_pl);
+
+- if (WARN_ON_ONCE(local_port >= max_ports))
++ if (WARN_ON_ONCE(!local_port || local_port >= max_ports))
+ return;
+ mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ if (!mlxsw_sp_port)
+diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
+index 4d5a5d6595b3b..d64ce65a3c174 100644
+--- a/drivers/net/ethernet/microchip/lan743x_main.c
++++ b/drivers/net/ethernet/microchip/lan743x_main.c
+@@ -914,8 +914,7 @@ static int lan743x_phy_reset(struct lan743x_adapter *adapter)
+ }
+
+ 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;
+@@ -943,7 +942,6 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
+
+ phy_print_status(phydev);
+ if (phydev->state == PHY_RUNNING) {
+- struct ethtool_link_ksettings ksettings;
+ int remote_advertisement = 0;
+ int local_advertisement = 0;
+
+@@ -980,18 +978,14 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
+ }
+ lan743x_csr_write(adapter, MAC_CR, data);
+
+- 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);
+ }
+ }
+
+diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
+index a08e4f530c1c1..00b5e6860bf69 100644
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1175,12 +1175,6 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
+ 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:
+@@ -1299,7 +1293,10 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
+ 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;
+ }
+diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c
+index ca4686094701c..0a02d8bd0a3e5 100644
+--- a/drivers/net/ethernet/natsemi/xtsonic.c
++++ b/drivers/net/ethernet/natsemi/xtsonic.c
+@@ -120,7 +120,7 @@ static const struct net_device_ops xtsonic_netdev_ops = {
+ .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);
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
+index df203738511bf..0b1865e9f0b59 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
+@@ -565,7 +565,6 @@ struct nfp_net_dp {
+ * @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
+@@ -650,8 +649,6 @@ struct nfp_net {
+ irq_handler_t shared_handler;
+ char shared_name[IFNAMSIZ + 8];
+
+- u32 me_freq_mhz;
+-
+ bool link_up;
+ spinlock_t link_status_lock;
+
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+index 5bfa22accf2c9..850bfdf83d0a4 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+@@ -2067,7 +2067,7 @@ static int nfp_net_poll(struct napi_struct *napi, int budget)
+ if (napi_complete_done(napi, pkts_polled))
+ nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
+
+- if (r_vec->nfp_net->rx_coalesce_adapt_on) {
++ if (r_vec->nfp_net->rx_coalesce_adapt_on && r_vec->rx_ring) {
+ struct dim_sample dim_sample = {};
+ unsigned int start;
+ u64 pkts, bytes;
+@@ -2082,7 +2082,7 @@ static int nfp_net_poll(struct napi_struct *napi, int budget)
+ net_dim(&r_vec->rx_dim, dim_sample);
+ }
+
+- if (r_vec->nfp_net->tx_coalesce_adapt_on) {
++ if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) {
+ struct dim_sample dim_sample = {};
+ unsigned int start;
+ u64 pkts, bytes;
+@@ -3016,10 +3016,8 @@ static void nfp_net_rx_dim_work(struct work_struct *work)
+
+ /* copy RX interrupt coalesce parameters */
+ value = (moder.pkts << 16) | (factor * moder.usec);
+- rtnl_lock();
+ nn_writel(nn, NFP_NET_CFG_RXR_IRQ_MOD(r_vec->rx_ring->idx), value);
+ (void)nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_IRQMOD);
+- rtnl_unlock();
+
+ dim->state = DIM_START_MEASURE;
+ }
+@@ -3047,10 +3045,8 @@ static void nfp_net_tx_dim_work(struct work_struct *work)
+
+ /* copy TX interrupt coalesce parameters */
+ value = (moder.pkts << 16) | (factor * moder.usec);
+- rtnl_lock();
+ nn_writel(nn, NFP_NET_CFG_TXR_IRQ_MOD(r_vec->tx_ring->idx), value);
+ (void)nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_IRQMOD);
+- rtnl_unlock();
+
+ dim->state = DIM_START_MEASURE;
+ }
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+index 0685ece1f155d..be1a358baadb9 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+@@ -1343,7 +1343,7 @@ static int nfp_net_set_coalesce(struct net_device *netdev,
+ * 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
+diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+index d7ac0307797fd..34c0d2ddf9ef6 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+@@ -803,8 +803,10 @@ int nfp_cpp_area_cache_add(struct nfp_cpp *cpp, size_t size)
+ 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;
+diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
+index 065e9004598ee..999abcfe3310a 100644
+--- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
++++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
+@@ -1643,6 +1643,13 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+ 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);
+ }
+diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
+index 9837bdb89cd40..ee4c3bd28a934 100644
+--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
+@@ -1176,19 +1176,17 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
+ edev->devlink = qed_ops->common->devlink_register(cdev);
+ if (IS_ERR(edev->devlink)) {
+ DP_NOTICE(edev, "Cannot register devlink\n");
++ rc = PTR_ERR(edev->devlink);
+ edev->devlink = NULL;
+- /* Go on, we can live without devlink */
++ goto err3;
+ }
+ } else {
+ struct net_device *ndev = pci_get_drvdata(pdev);
++ struct qed_devlink *qdl;
+
+ edev = netdev_priv(ndev);
+-
+- if (edev->devlink) {
+- struct qed_devlink *qdl = devlink_priv(edev->devlink);
+-
+- qdl->cdev = cdev;
+- }
++ qdl = devlink_priv(edev->devlink);
++ qdl->cdev = cdev;
+ edev->cdev = cdev;
+ memset(&edev->stats, 0, sizeof(edev->stats));
+ memcpy(&edev->dev_info, &dev_info, sizeof(dev_info));
+diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
+index c00ad57575eab..4eb9ea280474f 100644
+--- a/drivers/net/ethernet/qlogic/qla3xxx.c
++++ b/drivers/net/ethernet/qlogic/qla3xxx.c
+@@ -3478,20 +3478,19 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
+
+ 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);
+diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+index d51bac7ba5afa..bd06076803295 100644
+--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+@@ -1077,8 +1077,14 @@ static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
+ 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 */
+diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
+index 518268ce20644..d35cafd422b1c 100644
+--- a/drivers/net/ethernet/sfc/ef100_nic.c
++++ b/drivers/net/ethernet/sfc/ef100_nic.c
+@@ -609,6 +609,9 @@ static size_t ef100_update_stats(struct efx_nic *efx,
+ ef100_common_stat_mask(mask);
+ ef100_ethtool_stat_mask(mask);
+
++ if (!mc_stats)
++ return 0;
++
+ efx_nic_copy_stats(efx, mc_stats);
+ efx_nic_update_stats(ef100_stat_desc, EF100_STAT_COUNT, mask,
+ stats, mc_stats, false);
+diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
+index bf1443539a1a4..bd552c7dffcb1 100644
+--- a/drivers/net/ethernet/sfc/ethtool_common.c
++++ b/drivers/net/ethernet/sfc/ethtool_common.c
+@@ -563,20 +563,14 @@ int efx_ethtool_get_link_ksettings(struct net_device *net_dev,
+ {
+ 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_mcdi_phy_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;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+index 6924a6aacbd53..c469abc91fa1b 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -33,6 +33,7 @@ struct rk_gmac_ops {
+ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
+ void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
++ bool regs_valid;
+ u32 regs[];
+ };
+
+@@ -1092,6 +1093,7 @@ static const struct rk_gmac_ops rk3568_ops = {
+ .set_to_rmii = rk3568_set_to_rmii,
+ .set_rgmii_speed = rk3568_set_gmac_speed,
+ .set_rmii_speed = rk3568_set_gmac_speed,
++ .regs_valid = true,
+ .regs = {
+ 0xfe2a0000, /* gmac0 */
+ 0xfe010000, /* gmac1 */
+@@ -1383,7 +1385,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
+ * to be distinguished.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (res) {
++ if (res && ops->regs_valid) {
+ int i = 0;
+
+ while (ops->regs[i]) {
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+index 85208128f135c..b7c2579c963b6 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+@@ -485,8 +485,28 @@ static int socfpga_dwmac_resume(struct device *dev)
+ }
+ #endif /* CONFIG_PM_SLEEP */
+
+-static SIMPLE_DEV_PM_OPS(socfpga_dwmac_pm_ops, stmmac_suspend,
+- socfpga_dwmac_resume);
++static int __maybe_unused socfpga_dwmac_runtime_suspend(struct device *dev)
++{
++ struct net_device *ndev = dev_get_drvdata(dev);
++ struct stmmac_priv *priv = netdev_priv(ndev);
++
++ stmmac_bus_clks_config(priv, false);
++
++ return 0;
++}
++
++static int __maybe_unused socfpga_dwmac_runtime_resume(struct device *dev)
++{
++ struct net_device *ndev = dev_get_drvdata(dev);
++ struct stmmac_priv *priv = netdev_priv(ndev);
++
++ return stmmac_bus_clks_config(priv, true);
++}
++
++static const struct dev_pm_ops socfpga_dwmac_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(stmmac_suspend, socfpga_dwmac_resume)
++ SET_RUNTIME_PM_OPS(socfpga_dwmac_runtime_suspend, socfpga_dwmac_runtime_resume, NULL)
++};
+
+ static const struct socfpga_dwmac_ops socfpga_gen5_ops = {
+ .set_phy_mode = socfpga_gen5_set_phy_mode,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index 43eead726886a..873b9e3e5da25 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -172,6 +172,19 @@ struct stmmac_flow_entry {
+ int is_l4;
+ };
+
++/* Rx Frame Steering */
++enum stmmac_rfs_type {
++ STMMAC_RFS_T_VLAN,
++ STMMAC_RFS_T_MAX,
++};
++
++struct stmmac_rfs_entry {
++ unsigned long cookie;
++ int in_use;
++ int type;
++ int tc;
++};
++
+ struct stmmac_priv {
+ /* Frequently used values are kept adjacent for cache effect */
+ u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
+@@ -289,6 +302,10 @@ struct stmmac_priv {
+ struct stmmac_tc_entry *tc_entries;
+ unsigned int flow_entries_max;
+ struct stmmac_flow_entry *flow_entries;
++ unsigned int rfs_entries_max[STMMAC_RFS_T_MAX];
++ unsigned int rfs_entries_cnt[STMMAC_RFS_T_MAX];
++ unsigned int rfs_entries_total;
++ struct stmmac_rfs_entry *rfs_entries;
+
+ /* Pulse Per Second output */
+ struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];
+@@ -314,6 +331,7 @@ int stmmac_mdio_reset(struct mii_bus *mii);
+ int stmmac_xpcs_setup(struct mii_bus *mii);
+ void stmmac_set_ethtool_ops(struct net_device *netdev);
+
++int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags);
+ void stmmac_ptp_register(struct stmmac_priv *priv);
+ void stmmac_ptp_unregister(struct stmmac_priv *priv);
+ int stmmac_open(struct net_device *dev);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 3d67d1fa36906..3422f0746d825 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -50,6 +50,13 @@
+ #include "dwxgmac2.h"
+ #include "hwif.h"
+
++/* As long as the interface is active, we keep the timestamping counter enabled
++ * with fine resolution and binary rollover. This avoid non-monotonic behavior
++ * (clock jumps) when changing timestamping settings at runtime.
++ */
++#define STMMAC_HWTS_ACTIVE (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \
++ PTP_TCR_TSCTRLSSR)
++
+ #define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)
+ #define TSO_MAX_BUFF_SIZE (SZ_16K - 1)
+
+@@ -511,6 +518,14 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
+ return true;
+ }
+
++static inline u32 stmmac_cdc_adjust(struct stmmac_priv *priv)
++{
++ /* Correct the clk domain crossing(CDC) error */
++ if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
++ return (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
++ return 0;
++}
++
+ /* stmmac_get_tx_hwtstamp - get HW TX timestamps
+ * @priv: driver private structure
+ * @p : descriptor pointer
+@@ -524,7 +539,6 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
+ {
+ struct skb_shared_hwtstamps shhwtstamp;
+ bool found = false;
+- s64 adjust = 0;
+ u64 ns = 0;
+
+ if (!priv->hwts_tx_en)
+@@ -543,12 +557,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
+ }
+
+ if (found) {
+- /* Correct the clk domain crossing(CDC) error */
+- if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) {
+- adjust += -(2 * (NSEC_PER_SEC /
+- priv->plat->clk_ptp_rate));
+- ns += adjust;
+- }
++ ns -= stmmac_cdc_adjust(priv);
+
+ memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp.hwtstamp = ns_to_ktime(ns);
+@@ -573,7 +582,6 @@ static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+ {
+ struct skb_shared_hwtstamps *shhwtstamp = NULL;
+ struct dma_desc *desc = p;
+- u64 adjust = 0;
+ u64 ns = 0;
+
+ if (!priv->hwts_rx_en)
+@@ -586,11 +594,7 @@ static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+ if (stmmac_get_rx_timestamp_status(priv, p, np, priv->adv_ts)) {
+ stmmac_get_timestamp(priv, desc, priv->adv_ts, &ns);
+
+- /* Correct the clk domain crossing(CDC) error */
+- if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) {
+- adjust += 2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate);
+- ns -= adjust;
+- }
++ ns -= stmmac_cdc_adjust(priv);
+
+ netdev_dbg(priv->dev, "get valid RX hw timestamp %llu\n", ns);
+ shhwtstamp = skb_hwtstamps(skb);
+@@ -616,8 +620,6 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+ {
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct hwtstamp_config config;
+- struct timespec64 now;
+- u64 temp = 0;
+ u32 ptp_v2 = 0;
+ u32 tstamp_all = 0;
+ u32 ptp_over_ipv4_udp = 0;
+@@ -626,11 +628,6 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+ u32 snap_type_sel = 0;
+ u32 ts_master_en = 0;
+ u32 ts_event_en = 0;
+- u32 sec_inc = 0;
+- u32 value = 0;
+- bool xmac;
+-
+- xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
+
+ if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
+ netdev_alert(priv->dev, "No support for HW time stamping\n");
+@@ -792,42 +789,17 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+ priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
+ priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;
+
+- if (!priv->hwts_tx_en && !priv->hwts_rx_en)
+- stmmac_config_hw_tstamping(priv, priv->ptpaddr, 0);
+- else {
+- value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
+- tstamp_all | ptp_v2 | ptp_over_ethernet |
+- ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
+- ts_master_en | snap_type_sel);
+- stmmac_config_hw_tstamping(priv, priv->ptpaddr, value);
+-
+- /* program Sub Second Increment reg */
+- stmmac_config_sub_second_increment(priv,
+- priv->ptpaddr, priv->plat->clk_ptp_rate,
+- xmac, &sec_inc);
+- temp = div_u64(1000000000ULL, sec_inc);
+-
+- /* Store sub second increment and flags for later use */
+- priv->sub_second_inc = sec_inc;
+- priv->systime_flags = value;
+-
+- /* calculate default added value:
+- * formula is :
+- * addend = (2^32)/freq_div_ratio;
+- * where, freq_div_ratio = 1e9ns/sec_inc
+- */
+- temp = (u64)(temp << 32);
+- priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate);
+- stmmac_config_addend(priv, priv->ptpaddr, priv->default_addend);
++ priv->systime_flags = STMMAC_HWTS_ACTIVE;
+
+- /* initialize system time */
+- ktime_get_real_ts64(&now);
+-
+- /* lower 32 bits of tv_sec are safe until y2106 */
+- stmmac_init_systime(priv, priv->ptpaddr,
+- (u32)now.tv_sec, now.tv_nsec);
++ if (priv->hwts_tx_en || priv->hwts_rx_en) {
++ priv->systime_flags |= tstamp_all | ptp_v2 |
++ ptp_over_ethernet | ptp_over_ipv6_udp |
++ ptp_over_ipv4_udp | ts_event_en |
++ ts_master_en | snap_type_sel;
+ }
+
++ stmmac_config_hw_tstamping(priv, priv->ptpaddr, priv->systime_flags);
++
+ memcpy(&priv->tstamp_config, &config, sizeof(config));
+
+ return copy_to_user(ifr->ifr_data, &config,
+@@ -855,6 +827,66 @@ static int stmmac_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
+ sizeof(*config)) ? -EFAULT : 0;
+ }
+
++/**
++ * stmmac_init_tstamp_counter - init hardware timestamping counter
++ * @priv: driver private structure
++ * @systime_flags: timestamping flags
++ * Description:
++ * Initialize hardware counter for packet timestamping.
++ * This is valid as long as the interface is open and not suspended.
++ * Will be rerun after resuming from suspend, case in which the timestamping
++ * flags updated by stmmac_hwtstamp_set() also need to be restored.
++ */
++int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags)
++{
++ bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
++ struct timespec64 now;
++ u32 sec_inc = 0;
++ u64 temp = 0;
++ int ret;
++
++ if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
++ return -EOPNOTSUPP;
++
++ ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
++ if (ret < 0) {
++ netdev_warn(priv->dev,
++ "failed to enable PTP reference clock: %pe\n",
++ ERR_PTR(ret));
++ return ret;
++ }
++
++ stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
++ priv->systime_flags = systime_flags;
++
++ /* program Sub Second Increment reg */
++ stmmac_config_sub_second_increment(priv, priv->ptpaddr,
++ priv->plat->clk_ptp_rate,
++ xmac, &sec_inc);
++ temp = div_u64(1000000000ULL, sec_inc);
++
++ /* Store sub second increment for later use */
++ priv->sub_second_inc = sec_inc;
++
++ /* calculate default added value:
++ * formula is :
++ * addend = (2^32)/freq_div_ratio;
++ * where, freq_div_ratio = 1e9ns/sec_inc
++ */
++ temp = (u64)(temp << 32);
++ priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate);
++ stmmac_config_addend(priv, priv->ptpaddr, priv->default_addend);
++
++ /* initialize system time */
++ ktime_get_real_ts64(&now);
++
++ /* lower 32 bits of tv_sec are safe until y2106 */
++ stmmac_init_systime(priv, priv->ptpaddr, (u32)now.tv_sec, now.tv_nsec);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(stmmac_init_tstamp_counter);
++
+ /**
+ * stmmac_init_ptp - init PTP
+ * @priv: driver private structure
+@@ -865,9 +897,11 @@ static int stmmac_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
+ static int stmmac_init_ptp(struct stmmac_priv *priv)
+ {
+ bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
++ int ret;
+
+- if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+- return -EOPNOTSUPP;
++ ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE);
++ if (ret)
++ return ret;
+
+ priv->adv_ts = 0;
+ /* Check if adv_ts can be enabled for dwmac 4.x / xgmac core */
+@@ -3271,10 +3305,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+ stmmac_mmc_setup(priv);
+
+ if (init_ptp) {
+- ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+- if (ret < 0)
+- netdev_warn(priv->dev, "failed to enable PTP reference clock: %d\n", ret);
+-
+ ret = stmmac_init_ptp(priv);
+ if (ret == -EOPNOTSUPP)
+ netdev_warn(priv->dev, "PTP not supported by HW\n");
+@@ -3764,6 +3794,8 @@ int stmmac_release(struct net_device *dev)
+ struct stmmac_priv *priv = netdev_priv(dev);
+ u32 chan;
+
++ netif_tx_disable(dev);
++
+ if (device_may_wakeup(priv->device))
+ phylink_speed_down(priv->phylink, false);
+ /* Stop and disconnect the PHY */
+@@ -5499,8 +5531,6 @@ static int stmmac_set_features(struct net_device *netdev,
+ netdev_features_t features)
+ {
+ struct stmmac_priv *priv = netdev_priv(netdev);
+- bool sph_en;
+- u32 chan;
+
+ /* Keep the COE Type in case of csum is supporting */
+ if (features & NETIF_F_RXCSUM)
+@@ -5512,10 +5542,13 @@ static int stmmac_set_features(struct net_device *netdev,
+ */
+ stmmac_rx_ipc(priv, priv->hw);
+
+- sph_en = (priv->hw->rx_csum > 0) && priv->sph;
++ if (priv->sph_cap) {
++ bool sph_en = (priv->hw->rx_csum > 0) && priv->sph;
++ u32 chan;
+
+- for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++)
+- stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan);
++ for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++)
++ stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan);
++ }
+
+ return 0;
+ }
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+index 232ac98943cd0..5d29f336315b7 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -816,7 +816,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
+ if (ret)
+ return ret;
+
+- clk_prepare_enable(priv->plat->clk_ptp_ref);
++ stmmac_init_tstamp_counter(priv, priv->systime_flags);
+ }
+
+ return 0;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+index 8160087ee92f2..d0a2b289f4603 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+@@ -232,11 +232,33 @@ static int tc_setup_cls_u32(struct stmmac_priv *priv,
+ }
+ }
+
++static int tc_rfs_init(struct stmmac_priv *priv)
++{
++ int i;
++
++ priv->rfs_entries_max[STMMAC_RFS_T_VLAN] = 8;
++
++ for (i = 0; i < STMMAC_RFS_T_MAX; i++)
++ priv->rfs_entries_total += priv->rfs_entries_max[i];
++
++ priv->rfs_entries = devm_kcalloc(priv->device,
++ priv->rfs_entries_total,
++ sizeof(*priv->rfs_entries),
++ GFP_KERNEL);
++ if (!priv->rfs_entries)
++ return -ENOMEM;
++
++ dev_info(priv->device, "Enabled RFS Flow TC (entries=%d)\n",
++ priv->rfs_entries_total);
++
++ return 0;
++}
++
+ static int tc_init(struct stmmac_priv *priv)
+ {
+ struct dma_features *dma_cap = &priv->dma_cap;
+ unsigned int count;
+- int i;
++ int ret, i;
+
+ if (dma_cap->l3l4fnum) {
+ priv->flow_entries_max = dma_cap->l3l4fnum;
+@@ -250,10 +272,14 @@ static int tc_init(struct stmmac_priv *priv)
+ for (i = 0; i < priv->flow_entries_max; i++)
+ priv->flow_entries[i].idx = i;
+
+- dev_info(priv->device, "Enabled Flow TC (entries=%d)\n",
++ dev_info(priv->device, "Enabled L3L4 Flow TC (entries=%d)\n",
+ priv->flow_entries_max);
+ }
+
++ ret = tc_rfs_init(priv);
++ if (ret)
++ return -ENOMEM;
++
+ if (!priv->plat->fpe_cfg) {
+ priv->plat->fpe_cfg = devm_kzalloc(priv->device,
+ sizeof(*priv->plat->fpe_cfg),
+@@ -607,16 +633,45 @@ static int tc_del_flow(struct stmmac_priv *priv,
+ return ret;
+ }
+
++static struct stmmac_rfs_entry *tc_find_rfs(struct stmmac_priv *priv,
++ struct flow_cls_offload *cls,
++ bool get_free)
++{
++ int i;
++
++ for (i = 0; i < priv->rfs_entries_total; i++) {
++ struct stmmac_rfs_entry *entry = &priv->rfs_entries[i];
++
++ if (entry->cookie == cls->cookie)
++ return entry;
++ if (get_free && entry->in_use == false)
++ return entry;
++ }
++
++ return NULL;
++}
++
+ #define VLAN_PRIO_FULL_MASK (0x07)
+
+ static int tc_add_vlan_flow(struct stmmac_priv *priv,
+ struct flow_cls_offload *cls)
+ {
++ struct stmmac_rfs_entry *entry = tc_find_rfs(priv, cls, false);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+ struct flow_dissector *dissector = rule->match.dissector;
+ int tc = tc_classid_to_hwtc(priv->dev, cls->classid);
+ struct flow_match_vlan match;
+
++ if (!entry) {
++ entry = tc_find_rfs(priv, cls, true);
++ if (!entry)
++ return -ENOENT;
++ }
++
++ if (priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN] >=
++ priv->rfs_entries_max[STMMAC_RFS_T_VLAN])
++ return -ENOENT;
++
+ /* Nothing to do here */
+ if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN))
+ return -EINVAL;
+@@ -638,6 +693,12 @@ static int tc_add_vlan_flow(struct stmmac_priv *priv,
+
+ prio = BIT(match.key->vlan_priority);
+ stmmac_rx_queue_prio(priv, priv->hw, prio, tc);
++
++ entry->in_use = true;
++ entry->cookie = cls->cookie;
++ entry->tc = tc;
++ entry->type = STMMAC_RFS_T_VLAN;
++ priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN]++;
+ }
+
+ return 0;
+@@ -646,20 +707,19 @@ static int tc_add_vlan_flow(struct stmmac_priv *priv,
+ static int tc_del_vlan_flow(struct stmmac_priv *priv,
+ struct flow_cls_offload *cls)
+ {
+- struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+- struct flow_dissector *dissector = rule->match.dissector;
+- int tc = tc_classid_to_hwtc(priv->dev, cls->classid);
++ struct stmmac_rfs_entry *entry = tc_find_rfs(priv, cls, false);
+
+- /* Nothing to do here */
+- if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN))
+- return -EINVAL;
++ if (!entry || !entry->in_use || entry->type != STMMAC_RFS_T_VLAN)
++ return -ENOENT;
+
+- if (tc < 0) {
+- netdev_err(priv->dev, "Invalid traffic class\n");
+- return -EINVAL;
+- }
++ stmmac_rx_queue_prio(priv, priv->hw, 0, entry->tc);
++
++ entry->in_use = false;
++ entry->cookie = 0;
++ entry->tc = 0;
++ entry->type = 0;
+
+- stmmac_rx_queue_prio(priv, priv->hw, 0, tc);
++ priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN]--;
+
+ return 0;
+ }
+@@ -786,8 +846,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
+ goto disable;
+ if (qopt->num_entries >= dep)
+ return -EINVAL;
+- if (!qopt->base_time)
+- return -ERANGE;
+ if (!qopt->cycle_time)
+ return -ERANGE;
+
+diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
+index 0c75e0576ee1f..1ef0aaef5c61c 100644
+--- a/drivers/net/ethernet/ti/cpsw_ale.c
++++ b/drivers/net/ethernet/ti/cpsw_ale.c
+@@ -1299,10 +1299,8 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
+ if (!ale)
+ return ERR_PTR(-ENOMEM);
+
+- ale->p0_untag_vid_mask =
+- devm_kmalloc_array(params->dev, BITS_TO_LONGS(VLAN_N_VID),
+- sizeof(unsigned long),
+- GFP_KERNEL);
++ ale->p0_untag_vid_mask = devm_bitmap_zalloc(params->dev, VLAN_N_VID,
++ GFP_KERNEL);
+ if (!ale->p0_untag_vid_mask)
+ return ERR_PTR(-ENOMEM);
+
+diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
+index e8291d8488391..d243ca5dfde00 100644
+--- a/drivers/net/ethernet/ti/davinci_emac.c
++++ b/drivers/net/ethernet/ti/davinci_emac.c
+@@ -420,8 +420,20 @@ static int emac_set_coalesce(struct net_device *ndev,
+ 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;
+
+diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
+index e9258a9f3702c..31bc02421dd4e 100644
+--- a/drivers/net/ifb.c
++++ b/drivers/net/ifb.c
+@@ -76,7 +76,9 @@ static void ifb_ri_tasklet(struct tasklet_struct *t)
+
+ while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
+ skb->redirected = 0;
++#ifdef CONFIG_NET_CLS_ACT
+ skb->tc_skip_classify = 1;
++#endif
+
+ u64_stats_update_begin(&txp->tsync);
+ txp->tx_packets++;
+diff --git a/drivers/net/ipa/ipa_cmd.c b/drivers/net/ipa/ipa_cmd.c
+index cff51731195aa..d57472ea077f2 100644
+--- a/drivers/net/ipa/ipa_cmd.c
++++ b/drivers/net/ipa/ipa_cmd.c
+@@ -661,22 +661,6 @@ void ipa_cmd_pipeline_clear_wait(struct ipa *ipa)
+ wait_for_completion(&ipa->completion);
+ }
+
+-void ipa_cmd_pipeline_clear(struct ipa *ipa)
+-{
+- u32 count = ipa_cmd_pipeline_clear_count();
+- struct gsi_trans *trans;
+-
+- trans = ipa_cmd_trans_alloc(ipa, count);
+- if (trans) {
+- ipa_cmd_pipeline_clear_add(trans);
+- gsi_trans_commit_wait(trans);
+- ipa_cmd_pipeline_clear_wait(ipa);
+- } else {
+- dev_err(&ipa->pdev->dev,
+- "error allocating %u entry tag transaction\n", count);
+- }
+-}
+-
+ static struct ipa_cmd_info *
+ ipa_cmd_info_alloc(struct ipa_endpoint *endpoint, u32 tre_count)
+ {
+diff --git a/drivers/net/ipa/ipa_cmd.h b/drivers/net/ipa/ipa_cmd.h
+index 69cd085d427db..05ed7e42e1842 100644
+--- a/drivers/net/ipa/ipa_cmd.h
++++ b/drivers/net/ipa/ipa_cmd.h
+@@ -163,12 +163,6 @@ u32 ipa_cmd_pipeline_clear_count(void);
+ */
+ void ipa_cmd_pipeline_clear_wait(struct ipa *ipa);
+
+-/**
+- * ipa_cmd_pipeline_clear() - Clear the hardware pipeline
+- * @ipa: - IPA pointer
+- */
+-void ipa_cmd_pipeline_clear(struct ipa *ipa);
+-
+ /**
+ * ipa_cmd_trans_alloc() - Allocate a transaction for the command TX endpoint
+ * @ipa: IPA pointer
+diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c
+index 5528d97110d56..03a1709934208 100644
+--- a/drivers/net/ipa/ipa_endpoint.c
++++ b/drivers/net/ipa/ipa_endpoint.c
+@@ -853,6 +853,7 @@ static void ipa_endpoint_init_hol_block_timer(struct ipa_endpoint *endpoint,
+ u32 offset;
+ u32 val;
+
++ /* This should only be changed when HOL_BLOCK_EN is disabled */
+ offset = IPA_REG_ENDP_INIT_HOL_BLOCK_TIMER_N_OFFSET(endpoint_id);
+ val = hol_block_timer_val(ipa, microseconds);
+ iowrite32(val, ipa->reg_virt + offset);
+@@ -868,6 +869,9 @@ ipa_endpoint_init_hol_block_enable(struct ipa_endpoint *endpoint, bool enable)
+ val = enable ? HOL_BLOCK_EN_FMASK : 0;
+ offset = IPA_REG_ENDP_INIT_HOL_BLOCK_EN_N_OFFSET(endpoint_id);
+ iowrite32(val, endpoint->ipa->reg_virt + offset);
++ /* When enabling, the register must be written twice for IPA v4.5+ */
++ if (enable && endpoint->ipa->version >= IPA_VERSION_4_5)
++ iowrite32(val, endpoint->ipa->reg_virt + offset);
+ }
+
+ void ipa_endpoint_modem_hol_block_clear_all(struct ipa *ipa)
+@@ -880,6 +884,7 @@ void ipa_endpoint_modem_hol_block_clear_all(struct ipa *ipa)
+ if (endpoint->toward_ipa || endpoint->ee_id != GSI_EE_MODEM)
+ continue;
+
++ ipa_endpoint_init_hol_block_enable(endpoint, false);
+ ipa_endpoint_init_hol_block_timer(endpoint, 0);
+ ipa_endpoint_init_hol_block_enable(endpoint, true);
+ }
+@@ -1631,8 +1636,6 @@ void ipa_endpoint_suspend(struct ipa *ipa)
+ if (ipa->modem_netdev)
+ ipa_modem_suspend(ipa->modem_netdev);
+
+- ipa_cmd_pipeline_clear(ipa);
+-
+ ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]);
+ ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]);
+ }
+diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
+index cdfa98a76e1f4..a448ec198bee1 100644
+--- a/drivers/net/ipa/ipa_main.c
++++ b/drivers/net/ipa/ipa_main.c
+@@ -28,6 +28,7 @@
+ #include "ipa_reg.h"
+ #include "ipa_mem.h"
+ #include "ipa_table.h"
++#include "ipa_smp2p.h"
+ #include "ipa_modem.h"
+ #include "ipa_uc.h"
+ #include "ipa_interrupt.h"
+@@ -801,6 +802,11 @@ static int ipa_remove(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ int ret;
+
++ /* Prevent the modem from triggering a call to ipa_setup(). This
++ * also ensures a modem-initiated setup that's underway completes.
++ */
++ ipa_smp2p_irq_disable_setup(ipa);
++
+ ret = pm_runtime_get_sync(dev);
+ if (WARN_ON(ret < 0))
+ goto out_power_put;
+diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c
+index ad116bcc0580e..d0ab4d70c303b 100644
+--- a/drivers/net/ipa/ipa_modem.c
++++ b/drivers/net/ipa/ipa_modem.c
+@@ -339,9 +339,6 @@ int ipa_modem_stop(struct ipa *ipa)
+ if (state != IPA_MODEM_STATE_RUNNING)
+ return -EBUSY;
+
+- /* Prevent the modem from triggering a call to ipa_setup() */
+- ipa_smp2p_disable(ipa);
+-
+ /* Clean up the netdev and endpoints if it was started */
+ if (netdev) {
+ struct ipa_priv *priv = netdev_priv(netdev);
+@@ -369,6 +366,9 @@ static void ipa_modem_crashed(struct ipa *ipa)
+ struct device *dev = &ipa->pdev->dev;
+ int ret;
+
++ /* Prevent the modem from triggering a call to ipa_setup() */
++ ipa_smp2p_irq_disable_setup(ipa);
++
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "error %d getting power to handle crash\n", ret);
+diff --git a/drivers/net/ipa/ipa_resource.c b/drivers/net/ipa/ipa_resource.c
+index e3da95d694099..06cec71993823 100644
+--- a/drivers/net/ipa/ipa_resource.c
++++ b/drivers/net/ipa/ipa_resource.c
+@@ -52,7 +52,7 @@ static bool ipa_resource_limits_valid(struct ipa *ipa,
+ return false;
+ }
+
+- group_count = data->rsrc_group_src_count;
++ group_count = data->rsrc_group_dst_count;
+ if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX)
+ return false;
+
+diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
+index df7639c39d716..2112336120391 100644
+--- a/drivers/net/ipa/ipa_smp2p.c
++++ b/drivers/net/ipa/ipa_smp2p.c
+@@ -53,7 +53,7 @@
+ * @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready
+ * @power_on: Whether IPA power is on
+ * @notified: Whether modem has been notified of power state
+- * @disabled: Whether setup ready interrupt handling is disabled
++ * @setup_disabled: Whether setup ready interrupt handler is disabled
+ * @mutex: Mutex protecting ready-interrupt/shutdown interlock
+ * @panic_notifier: Panic notifier structure
+ */
+@@ -67,7 +67,7 @@ struct ipa_smp2p {
+ u32 setup_ready_irq;
+ bool power_on;
+ bool notified;
+- bool disabled;
++ bool setup_disabled;
+ struct mutex mutex;
+ struct notifier_block panic_notifier;
+ };
+@@ -155,11 +155,9 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
+ struct device *dev;
+ int ret;
+
+- mutex_lock(&smp2p->mutex);
+-
+- if (smp2p->disabled)
+- goto out_mutex_unlock;
+- smp2p->disabled = true; /* If any others arrive, ignore them */
++ /* Ignore any (spurious) interrupts received after the first */
++ if (smp2p->ipa->setup_complete)
++ return IRQ_HANDLED;
+
+ /* Power needs to be active for setup */
+ dev = &smp2p->ipa->pdev->dev;
+@@ -176,8 +174,6 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
+ out_power_put:
+ pm_runtime_mark_last_busy(dev);
+ (void)pm_runtime_put_autosuspend(dev);
+-out_mutex_unlock:
+- mutex_unlock(&smp2p->mutex);
+
+ return IRQ_HANDLED;
+ }
+@@ -313,7 +309,7 @@ void ipa_smp2p_exit(struct ipa *ipa)
+ kfree(smp2p);
+ }
+
+-void ipa_smp2p_disable(struct ipa *ipa)
++void ipa_smp2p_irq_disable_setup(struct ipa *ipa)
+ {
+ struct ipa_smp2p *smp2p = ipa->smp2p;
+
+@@ -322,7 +318,10 @@ void ipa_smp2p_disable(struct ipa *ipa)
+
+ mutex_lock(&smp2p->mutex);
+
+- smp2p->disabled = true;
++ if (!smp2p->setup_disabled) {
++ disable_irq(smp2p->setup_ready_irq);
++ smp2p->setup_disabled = true;
++ }
+
+ mutex_unlock(&smp2p->mutex);
+ }
+diff --git a/drivers/net/ipa/ipa_smp2p.h b/drivers/net/ipa/ipa_smp2p.h
+index 99a9567896388..59cee31a73836 100644
+--- a/drivers/net/ipa/ipa_smp2p.h
++++ b/drivers/net/ipa/ipa_smp2p.h
+@@ -27,13 +27,12 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init);
+ void ipa_smp2p_exit(struct ipa *ipa);
+
+ /**
+- * ipa_smp2p_disable() - Prevent "ipa-setup-ready" interrupt handling
++ * ipa_smp2p_irq_disable_setup() - Disable the "setup ready" interrupt
+ * @ipa: IPA pointer
+ *
+- * Prevent handling of the "setup ready" interrupt from the modem.
+- * This is used before initiating shutdown of the driver.
++ * Disable the "ipa-setup-ready" interrupt from the modem.
+ */
+-void ipa_smp2p_disable(struct ipa *ipa);
++void ipa_smp2p_irq_disable_setup(struct ipa *ipa);
+
+ /**
+ * ipa_smp2p_notify_reset() - Reset modem notification state
+diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c
+index cad820568f751..966c3b4ad59d1 100644
+--- a/drivers/net/mdio/mdio-aspeed.c
++++ b/drivers/net/mdio/mdio-aspeed.c
+@@ -61,6 +61,13 @@ static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum)
+
+ 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,
+diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c
+index 90aafb56f1409..a438202129323 100644
+--- a/drivers/net/netdevsim/bpf.c
++++ b/drivers/net/netdevsim/bpf.c
+@@ -514,6 +514,7 @@ nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
+ goto err_free;
+ key = nmap->entry[i].key;
+ *key = i;
++ memset(nmap->entry[i].value, 0, offmap->map.value_size);
+ }
+ }
+
+diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
+index b03a0513eb7e7..2e7c1cc16cb93 100644
+--- a/drivers/net/netdevsim/ethtool.c
++++ b/drivers/net/netdevsim/ethtool.c
+@@ -77,7 +77,10 @@ static int nsim_set_ringparam(struct net_device *dev,
+ {
+ struct netdevsim *ns = netdev_priv(dev);
+
+- memcpy(&ns->ethtool.ring, ring, sizeof(ns->ethtool.ring));
++ ns->ethtool.ring.rx_pending = ring->rx_pending;
++ ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
++ ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
++ ns->ethtool.ring.tx_pending = ring->tx_pending;
+ return 0;
+ }
+
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index 5c928f827173c..aec0fcefdccd6 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -863,9 +863,9 @@ static int ksz9031_config_init(struct phy_device *phydev)
+ MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
+ tx_data_skews, 4, &update);
+
+- if (update && phydev->interface != PHY_INTERFACE_MODE_RGMII)
++ if (update && !phy_interface_is_rgmii(phydev))
+ phydev_warn(phydev,
+- "*-skew-ps values should be used only with phy-mode = \"rgmii\"\n");
++ "*-skew-ps values should be used only with RGMII PHY modes\n");
+
+ /* Silicon Errata Sheet (DS80000691D or DS80000692D):
+ * When the device links in the 1000BASE-T slave mode only,
+@@ -1593,8 +1593,9 @@ static struct phy_driver ksphy_driver[] = {
+ .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,
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index a3bfb156c83d7..beb2b66da1324 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -815,7 +815,12 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev,
+ phydev->mdix_ctrl = cmd->base.eth_tp_mdix_ctrl;
+
+ /* Restart the PHY */
+- _phy_start_aneg(phydev);
++ if (phy_is_started(phydev)) {
++ phydev->state = PHY_UP;
++ phy_trigger_machine(phydev);
++ } else {
++ _phy_start_aneg(phydev);
++ }
+
+ mutex_unlock(&phydev->lock);
+ return 0;
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 0a0abe8e4be0b..fef1416dcee4c 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -657,6 +657,7 @@ static void phylink_resolve(struct work_struct *w)
+ struct phylink_link_state link_state;
+ struct net_device *ndev = pl->netdev;
+ bool mac_config = false;
++ bool retrigger = false;
+ bool cur_link_state;
+
+ mutex_lock(&pl->state_mutex);
+@@ -670,6 +671,7 @@ static void phylink_resolve(struct work_struct *w)
+ link_state.link = false;
+ } else if (pl->mac_link_dropped) {
+ link_state.link = false;
++ retrigger = true;
+ } else {
+ switch (pl->cur_link_an_mode) {
+ case MLO_AN_PHY:
+@@ -686,6 +688,19 @@ static void phylink_resolve(struct work_struct *w)
+ case MLO_AN_INBAND:
+ phylink_mac_pcs_get_state(pl, &link_state);
+
++ /* The PCS may have a latching link-fail indicator.
++ * If the link was up, bring the link down and
++ * re-trigger the resolve. Otherwise, re-read the
++ * PCS state to get the current status of the link.
++ */
++ if (!link_state.link) {
++ if (cur_link_state)
++ retrigger = true;
++ else
++ phylink_mac_pcs_get_state(pl,
++ &link_state);
++ }
++
+ /* If we have a phy, the "up" state is the union of
+ * both the PHY and the MAC
+ */
+@@ -694,6 +709,15 @@ static void phylink_resolve(struct work_struct *w)
+
+ /* Only update if the PHY link is up */
+ if (pl->phydev && pl->phy_state.link) {
++ /* If the interface has changed, force a
++ * link down event if the link isn't already
++ * down, and re-resolve.
++ */
++ if (link_state.interface !=
++ pl->phy_state.interface) {
++ retrigger = true;
++ link_state.link = false;
++ }
+ link_state.interface = pl->phy_state.interface;
+
+ /* If we have a PHY, we need to update with
+@@ -736,7 +760,7 @@ static void phylink_resolve(struct work_struct *w)
+ else
+ phylink_link_up(pl, link_state);
+ }
+- if (!link_state.link && pl->mac_link_dropped) {
++ if (!link_state.link && retrigger) {
+ pl->mac_link_dropped = false;
+ queue_work(system_power_efficient_wq, &pl->resolve);
+ }
+@@ -1333,7 +1357,10 @@ void phylink_suspend(struct phylink *pl, bool mac_wol)
+ * but one would hope all packets have been sent. This
+ * also means phylink_resolve() will do nothing.
+ */
+- netif_carrier_off(pl->netdev);
++ if (pl->netdev)
++ netif_carrier_off(pl->netdev);
++ else
++ pl->old_link_state = false;
+
+ /* We do not call mac_link_down() here as we want the
+ * link to remain up to receive the WoL packets.
+@@ -1724,7 +1751,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
+ 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;
+
+ pause_state = 0;
+diff --git a/drivers/net/tun.c b/drivers/net/tun.c
+index fecc9a1d293ae..1572878c34031 100644
+--- a/drivers/net/tun.c
++++ b/drivers/net/tun.c
+@@ -1010,6 +1010,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct tun_struct *tun = netdev_priv(dev);
+ int txq = skb->queue_mapping;
++ struct netdev_queue *queue;
+ struct tun_file *tfile;
+ int len = skb->len;
+
+@@ -1054,6 +1055,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
+ 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);
+diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
+index 24753a4da7e60..e303b522efb50 100644
+--- a/drivers/net/usb/cdc_ncm.c
++++ b/drivers/net/usb/cdc_ncm.c
+@@ -181,6 +181,8 @@ static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
+ min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32);
+
+ max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
++ if (max == 0)
++ max = CDC_NCM_NTB_MAX_SIZE_TX; /* dwNtbOutMaxSize not set */
+
+ /* some devices set dwNtbOutMaxSize too low for the above default */
+ min = min(min, max);
+diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
+index 63cd72c5f580c..a0401a9dade5b 100644
+--- a/drivers/net/usb/lan78xx.c
++++ b/drivers/net/usb/lan78xx.c
+@@ -2228,7 +2228,7 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
+ 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 */
+diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
+index f329e39100a7d..d3da350777a4d 100644
+--- a/drivers/net/usb/r8152.c
++++ b/drivers/net/usb/r8152.c
+@@ -9603,12 +9603,9 @@ static int rtl8152_probe(struct usb_interface *intf,
+ netdev->hw_features &= ~NETIF_F_RXCSUM;
+ }
+
+- if (le16_to_cpu(udev->descriptor.idVendor) == VENDOR_ID_LENOVO) {
+- switch (le16_to_cpu(udev->descriptor.idProduct)) {
+- case DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2:
+- case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2:
+- tp->lenovo_macpassthru = 1;
+- }
++ if (udev->parent &&
++ le16_to_cpu(udev->parent->descriptor.idVendor) == VENDOR_ID_LENOVO) {
++ tp->lenovo_macpassthru = 1;
+ }
+
+ if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial &&
+diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
+index 26b1bd8e845b4..f91dabd65ecd8 100644
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -1049,6 +1049,14 @@ static const struct net_device_ops smsc95xx_netdev_ops = {
+ .ndo_set_features = smsc95xx_set_features,
+ };
+
++static void smsc95xx_handle_link_change(struct net_device *net)
++{
++ struct usbnet *dev = netdev_priv(net);
++
++ phy_print_status(net->phydev);
++ usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
++}
++
+ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
+ {
+ struct smsc95xx_priv *pdata;
+@@ -1153,6 +1161,17 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
+ dev->net->min_mtu = ETH_MIN_MTU;
+ dev->net->max_mtu = ETH_DATA_LEN;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
++
++ ret = phy_connect_direct(dev->net, pdata->phydev,
++ &smsc95xx_handle_link_change,
++ PHY_INTERFACE_MODE_MII);
++ if (ret) {
++ netdev_err(dev->net, "can't attach PHY to %s\n", pdata->mdiobus->id);
++ goto unregister_mdio;
++ }
++
++ phy_attached_info(dev->net->phydev);
++
+ return 0;
+
+ unregister_mdio:
+@@ -1170,47 +1189,25 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
+ {
+ struct smsc95xx_priv *pdata = dev->driver_priv;
+
++ phy_disconnect(dev->net->phydev);
+ mdiobus_unregister(pdata->mdiobus);
+ mdiobus_free(pdata->mdiobus);
+ netif_dbg(dev, ifdown, dev->net, "free pdata\n");
+ kfree(pdata);
+ }
+
+-static void smsc95xx_handle_link_change(struct net_device *net)
+-{
+- struct usbnet *dev = netdev_priv(net);
+-
+- phy_print_status(net->phydev);
+- usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
+-}
+-
+ static int smsc95xx_start_phy(struct usbnet *dev)
+ {
+- struct smsc95xx_priv *pdata = dev->driver_priv;
+- struct net_device *net = dev->net;
+- int ret;
++ phy_start(dev->net->phydev);
+
+- ret = smsc95xx_reset(dev);
+- if (ret < 0)
+- return ret;
+-
+- ret = phy_connect_direct(net, pdata->phydev,
+- &smsc95xx_handle_link_change,
+- PHY_INTERFACE_MODE_MII);
+- if (ret) {
+- netdev_err(net, "can't attach PHY to %s\n", pdata->mdiobus->id);
+- return ret;
+- }
+-
+- phy_attached_info(net->phydev);
+- phy_start(net->phydev);
+ return 0;
+ }
+
+-static int smsc95xx_disconnect_phy(struct usbnet *dev)
++static int smsc95xx_stop(struct usbnet *dev)
+ {
+- phy_stop(dev->net->phydev);
+- phy_disconnect(dev->net->phydev);
++ if (dev->net->phydev)
++ phy_stop(dev->net->phydev);
++
+ return 0;
+ }
+
+@@ -1965,7 +1962,7 @@ static const struct driver_info smsc95xx_info = {
+ .unbind = smsc95xx_unbind,
+ .link_reset = smsc95xx_link_reset,
+ .reset = smsc95xx_start_phy,
+- .stop = smsc95xx_disconnect_phy,
++ .stop = smsc95xx_stop,
+ .rx_fixup = smsc95xx_rx_fixup,
+ .tx_fixup = smsc95xx_tx_fixup,
+ .status = smsc95xx_status,
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 8799854bacb29..5b0215b7c1761 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -3261,7 +3261,7 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
+
+ #ifdef CONFIG_PCI_MSI
+ if (adapter->intr.type == VMXNET3_IT_MSIX) {
+- int i, nvec;
++ int i, nvec, nvec_allocated;
+
+ nvec = adapter->share_intr == VMXNET3_INTR_TXSHARE ?
+ 1 : adapter->num_tx_queues;
+@@ -3274,14 +3274,15 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
+ for (i = 0; i < nvec; i++)
+ adapter->intr.msix_entries[i].entry = i;
+
+- nvec = vmxnet3_acquire_msix_vectors(adapter, nvec);
+- if (nvec < 0)
++ nvec_allocated = vmxnet3_acquire_msix_vectors(adapter, nvec);
++ if (nvec_allocated < 0)
+ goto msix_err;
+
+ /* If we cannot allocate one MSIx vector per queue
+ * then limit the number of rx queues to 1
+ */
+- if (nvec == VMXNET3_LINUX_MIN_MSIX_VECT) {
++ if (nvec_allocated == VMXNET3_LINUX_MIN_MSIX_VECT &&
++ nvec != VMXNET3_LINUX_MIN_MSIX_VECT) {
+ if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
+ || adapter->num_rx_queues != 1) {
+ adapter->share_intr = VMXNET3_INTR_TXSHARE;
+@@ -3291,14 +3292,14 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
+ }
+ }
+
+- adapter->intr.num_intrs = nvec;
++ adapter->intr.num_intrs = nvec_allocated;
+ return;
+
+ msix_err:
+ /* If we cannot allocate MSIx vectors use only one rx queue */
+ dev_info(&adapter->pdev->dev,
+ "Failed to enable MSI-X, error %d. "
+- "Limiting #rx queues to 1, try MSI.\n", nvec);
++ "Limiting #rx queues to 1, try MSI.\n", nvec_allocated);
+
+ adapter->intr.type = VMXNET3_IT_MSI;
+ }
+diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
+index 662e261173539..b2242a082431c 100644
+--- a/drivers/net/vrf.c
++++ b/drivers/net/vrf.c
+@@ -35,6 +35,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.1"
+@@ -424,12 +425,26 @@ static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
+ 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);
+
+@@ -482,6 +497,7 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
+ /* 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++;
+@@ -508,6 +524,8 @@ static int vrf_ip_local_out(struct net *net, struct sock *sk,
+ {
+ 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))
+@@ -562,6 +580,7 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
+ 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++;
+@@ -626,8 +645,7 @@ static void vrf_finish_direct(struct sk_buff *skb)
+ skb_pull(skb, ETH_HLEN);
+ }
+
+- /* reset skb device */
+- nf_reset_ct(skb);
++ vrf_nf_reset_ct(skb);
+ }
+
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -641,7 +659,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
+ struct neighbour *neigh;
+ int ret;
+
+- nf_reset_ct(skb);
++ vrf_nf_reset_ct(skb);
+
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->dev = dev;
+@@ -772,6 +790,8 @@ static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
+ if (rt6_need_strict(&ipv6_hdr(skb)->daddr))
+ return skb;
+
++ 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);
+@@ -858,7 +878,7 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
+ struct neighbour *neigh;
+ bool is_v6gw = false;
+
+- 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)) {
+@@ -1001,6 +1021,8 @@ static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,
+ ipv4_is_lbcast(ip_hdr(skb)->daddr))
+ return skb;
+
++ 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);
+diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c
+index b7197e80f2264..9a4c8ff32d9dd 100644
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -163,7 +163,7 @@ static bool node_placement(struct allowedips_node __rcu *trie, const u8 *key,
+ return exact;
+ }
+
+-static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node)
++static inline void connect_node(struct allowedips_node __rcu **parent, u8 bit, struct allowedips_node *node)
+ {
+ node->parent_bit_packed = (unsigned long)parent | bit;
+ rcu_assign_pointer(*parent, node);
+diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c
+index 551ddaaaf5400..a46067c38bf5d 100644
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -98,6 +98,7 @@ static int wg_stop(struct net_device *dev)
+ {
+ struct wg_device *wg = netdev_priv(dev);
+ struct wg_peer *peer;
++ struct sk_buff *skb;
+
+ mutex_lock(&wg->device_update_lock);
+ list_for_each_entry(peer, &wg->peer_list, peer_list) {
+@@ -108,7 +109,9 @@ static int wg_stop(struct net_device *dev)
+ wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
+ }
+ mutex_unlock(&wg->device_update_lock);
+- skb_queue_purge(&wg->incoming_handshakes);
++ while ((skb = ptr_ring_consume(&wg->handshake_queue.ring)) != NULL)
++ kfree_skb(skb);
++ atomic_set(&wg->handshake_queue_len, 0);
+ wg_socket_reinit(wg, NULL, NULL);
+ return 0;
+ }
+@@ -235,14 +238,13 @@ static void wg_destruct(struct net_device *dev)
+ destroy_workqueue(wg->handshake_receive_wq);
+ destroy_workqueue(wg->handshake_send_wq);
+ destroy_workqueue(wg->packet_crypt_wq);
+- wg_packet_queue_free(&wg->decrypt_queue);
+- wg_packet_queue_free(&wg->encrypt_queue);
++ wg_packet_queue_free(&wg->handshake_queue, true);
++ wg_packet_queue_free(&wg->decrypt_queue, false);
++ wg_packet_queue_free(&wg->encrypt_queue, false);
+ rcu_barrier(); /* Wait for all the peers to be actually freed. */
+ wg_ratelimiter_uninit();
+ memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
+- skb_queue_purge(&wg->incoming_handshakes);
+ free_percpu(dev->tstats);
+- free_percpu(wg->incoming_handshakes_worker);
+ kvfree(wg->index_hashtable);
+ kvfree(wg->peer_hashtable);
+ mutex_unlock(&wg->device_update_lock);
+@@ -298,7 +300,6 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
+ init_rwsem(&wg->static_identity.lock);
+ mutex_init(&wg->socket_update_lock);
+ mutex_init(&wg->device_update_lock);
+- skb_queue_head_init(&wg->incoming_handshakes);
+ wg_allowedips_init(&wg->peer_allowedips);
+ wg_cookie_checker_init(&wg->cookie_checker, wg);
+ INIT_LIST_HEAD(&wg->peer_list);
+@@ -316,16 +317,10 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
+ if (!dev->tstats)
+ goto err_free_index_hashtable;
+
+- wg->incoming_handshakes_worker =
+- wg_packet_percpu_multicore_worker_alloc(
+- wg_packet_handshake_receive_worker, wg);
+- if (!wg->incoming_handshakes_worker)
+- goto err_free_tstats;
+-
+ wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
+ WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
+ if (!wg->handshake_receive_wq)
+- goto err_free_incoming_handshakes;
++ goto err_free_tstats;
+
+ wg->handshake_send_wq = alloc_workqueue("wg-kex-%s",
+ WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);
+@@ -347,10 +342,15 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
+ if (ret < 0)
+ goto err_free_encrypt_queue;
+
+- ret = wg_ratelimiter_init();
++ ret = wg_packet_queue_init(&wg->handshake_queue, wg_packet_handshake_receive_worker,
++ MAX_QUEUED_INCOMING_HANDSHAKES);
+ if (ret < 0)
+ goto err_free_decrypt_queue;
+
++ ret = wg_ratelimiter_init();
++ if (ret < 0)
++ goto err_free_handshake_queue;
++
+ ret = register_netdevice(dev);
+ if (ret < 0)
+ goto err_uninit_ratelimiter;
+@@ -367,18 +367,18 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
+
+ err_uninit_ratelimiter:
+ wg_ratelimiter_uninit();
++err_free_handshake_queue:
++ wg_packet_queue_free(&wg->handshake_queue, false);
+ err_free_decrypt_queue:
+- wg_packet_queue_free(&wg->decrypt_queue);
++ wg_packet_queue_free(&wg->decrypt_queue, false);
+ err_free_encrypt_queue:
+- wg_packet_queue_free(&wg->encrypt_queue);
++ wg_packet_queue_free(&wg->encrypt_queue, false);
+ err_destroy_packet_crypt:
+ destroy_workqueue(wg->packet_crypt_wq);
+ err_destroy_handshake_send:
+ destroy_workqueue(wg->handshake_send_wq);
+ err_destroy_handshake_receive:
+ destroy_workqueue(wg->handshake_receive_wq);
+-err_free_incoming_handshakes:
+- free_percpu(wg->incoming_handshakes_worker);
+ err_free_tstats:
+ free_percpu(dev->tstats);
+ err_free_index_hashtable:
+@@ -398,6 +398,7 @@ static struct rtnl_link_ops link_ops __read_mostly = {
+ static void wg_netns_pre_exit(struct net *net)
+ {
+ struct wg_device *wg;
++ struct wg_peer *peer;
+
+ rtnl_lock();
+ list_for_each_entry(wg, &device_list, device_list) {
+@@ -407,6 +408,8 @@ static void wg_netns_pre_exit(struct net *net)
+ mutex_lock(&wg->device_update_lock);
+ rcu_assign_pointer(wg->creating_net, NULL);
+ wg_socket_reinit(wg, NULL, NULL);
++ list_for_each_entry(peer, &wg->peer_list, peer_list)
++ wg_socket_clear_peer_endpoint_src(peer);
+ mutex_unlock(&wg->device_update_lock);
+ }
+ }
+diff --git a/drivers/net/wireguard/device.h b/drivers/net/wireguard/device.h
+index 854bc3d97150e..43c7cebbf50b0 100644
+--- a/drivers/net/wireguard/device.h
++++ b/drivers/net/wireguard/device.h
+@@ -39,21 +39,18 @@ struct prev_queue {
+
+ struct wg_device {
+ struct net_device *dev;
+- struct crypt_queue encrypt_queue, decrypt_queue;
++ struct crypt_queue encrypt_queue, decrypt_queue, handshake_queue;
+ struct sock __rcu *sock4, *sock6;
+ struct net __rcu *creating_net;
+ struct noise_static_identity static_identity;
+- struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
+- struct workqueue_struct *packet_crypt_wq;
+- struct sk_buff_head incoming_handshakes;
+- int incoming_handshake_cpu;
+- struct multicore_worker __percpu *incoming_handshakes_worker;
++ struct workqueue_struct *packet_crypt_wq,*handshake_receive_wq, *handshake_send_wq;
+ struct cookie_checker cookie_checker;
+ struct pubkey_hashtable *peer_hashtable;
+ struct index_hashtable *index_hashtable;
+ struct allowedips peer_allowedips;
+ struct mutex device_update_lock, socket_update_lock;
+ struct list_head device_list, peer_list;
++ atomic_t handshake_queue_len;
+ unsigned int num_peers, device_update_gen;
+ u32 fwmark;
+ u16 incoming_port;
+diff --git a/drivers/net/wireguard/queueing.c b/drivers/net/wireguard/queueing.c
+index 48e7b982a3073..1de413b19e342 100644
+--- a/drivers/net/wireguard/queueing.c
++++ b/drivers/net/wireguard/queueing.c
+@@ -38,11 +38,11 @@ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
+ return 0;
+ }
+
+-void wg_packet_queue_free(struct crypt_queue *queue)
++void wg_packet_queue_free(struct crypt_queue *queue, bool purge)
+ {
+ free_percpu(queue->worker);
+- WARN_ON(!__ptr_ring_empty(&queue->ring));
+- ptr_ring_cleanup(&queue->ring, NULL);
++ WARN_ON(!purge && !__ptr_ring_empty(&queue->ring));
++ ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL);
+ }
+
+ #define NEXT(skb) ((skb)->prev)
+diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h
+index 4ef2944a68bc9..e2388107f7fdc 100644
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -23,7 +23,7 @@ struct sk_buff;
+ /* queueing.c APIs: */
+ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
+ unsigned int len);
+-void wg_packet_queue_free(struct crypt_queue *queue);
++void wg_packet_queue_free(struct crypt_queue *queue, bool purge);
+ struct multicore_worker __percpu *
+ wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr);
+
+diff --git a/drivers/net/wireguard/ratelimiter.c b/drivers/net/wireguard/ratelimiter.c
+index 3fedd1d21f5ee..dd55e5c26f468 100644
+--- a/drivers/net/wireguard/ratelimiter.c
++++ b/drivers/net/wireguard/ratelimiter.c
+@@ -176,12 +176,12 @@ int wg_ratelimiter_init(void)
+ (1U << 14) / sizeof(struct hlist_head)));
+ max_entries = table_size * 8;
+
+- table_v4 = kvzalloc(table_size * sizeof(*table_v4), GFP_KERNEL);
++ table_v4 = kvcalloc(table_size, sizeof(*table_v4), GFP_KERNEL);
+ if (unlikely(!table_v4))
+ goto err_kmemcache;
+
+ #if IS_ENABLED(CONFIG_IPV6)
+- table_v6 = kvzalloc(table_size * sizeof(*table_v6), GFP_KERNEL);
++ table_v6 = kvcalloc(table_size, sizeof(*table_v6), GFP_KERNEL);
+ if (unlikely(!table_v6)) {
+ kvfree(table_v4);
+ goto err_kmemcache;
+diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c
+index 7dc84bcca2613..7b8df406c7737 100644
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -116,8 +116,8 @@ static void wg_receive_handshake_packet(struct wg_device *wg,
+ return;
+ }
+
+- under_load = skb_queue_len(&wg->incoming_handshakes) >=
+- MAX_QUEUED_INCOMING_HANDSHAKES / 8;
++ under_load = atomic_read(&wg->handshake_queue_len) >=
++ MAX_QUEUED_INCOMING_HANDSHAKES / 8;
+ if (under_load) {
+ last_under_load = ktime_get_coarse_boottime_ns();
+ } else if (last_under_load) {
+@@ -212,13 +212,14 @@ static void wg_receive_handshake_packet(struct wg_device *wg,
+
+ void wg_packet_handshake_receive_worker(struct work_struct *work)
+ {
+- struct wg_device *wg = container_of(work, struct multicore_worker,
+- work)->ptr;
++ struct crypt_queue *queue = container_of(work, struct multicore_worker, work)->ptr;
++ struct wg_device *wg = container_of(queue, struct wg_device, handshake_queue);
+ struct sk_buff *skb;
+
+- while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) {
++ while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
+ wg_receive_handshake_packet(wg, skb);
+ dev_kfree_skb(skb);
++ atomic_dec(&wg->handshake_queue_len);
+ cond_resched();
+ }
+ }
+@@ -553,22 +554,28 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb)
+ case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION):
+ case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE):
+ case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): {
+- int cpu;
+-
+- if (skb_queue_len(&wg->incoming_handshakes) >
+- MAX_QUEUED_INCOMING_HANDSHAKES ||
+- unlikely(!rng_is_initialized())) {
++ int cpu, ret = -EBUSY;
++
++ if (unlikely(!rng_is_initialized()))
++ goto drop;
++ if (atomic_read(&wg->handshake_queue_len) > MAX_QUEUED_INCOMING_HANDSHAKES / 2) {
++ if (spin_trylock_bh(&wg->handshake_queue.ring.producer_lock)) {
++ ret = __ptr_ring_produce(&wg->handshake_queue.ring, skb);
++ spin_unlock_bh(&wg->handshake_queue.ring.producer_lock);
++ }
++ } else
++ ret = ptr_ring_produce_bh(&wg->handshake_queue.ring, skb);
++ if (ret) {
++ drop:
+ net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n",
+ wg->dev->name, skb);
+ goto err;
+ }
+- skb_queue_tail(&wg->incoming_handshakes, skb);
+- /* Queues up a call to packet_process_queued_handshake_
+- * packets(skb):
+- */
+- cpu = wg_cpumask_next_online(&wg->incoming_handshake_cpu);
++ atomic_inc(&wg->handshake_queue_len);
++ cpu = wg_cpumask_next_online(&wg->handshake_queue.last_cpu);
++ /* Queues up a call to packet_process_queued_handshake_packets(skb): */
+ queue_work_on(cpu, wg->handshake_receive_wq,
+- &per_cpu_ptr(wg->incoming_handshakes_worker, cpu)->work);
++ &per_cpu_ptr(wg->handshake_queue.worker, cpu)->work);
+ break;
+ }
+ case cpu_to_le32(MESSAGE_DATA):
+diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c
+index 8c496b7471082..6f07b949cb81d 100644
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -308,7 +308,7 @@ void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer)
+ {
+ write_lock_bh(&peer->endpoint_lock);
+ memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6));
+- dst_cache_reset(&peer->endpoint_cache);
++ dst_cache_reset_now(&peer->endpoint_cache);
+ write_unlock_bh(&peer->endpoint_lock);
+ }
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 2f9be182fbfbb..64c7145b51a2e 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -2690,9 +2690,16 @@ static int ath10k_core_copy_target_iram(struct ath10k *ar)
+ int i, ret;
+ u32 len, remaining_len;
+
+- hw_mem = ath10k_coredump_get_mem_layout(ar);
++ /* copy target iram feature must work also when
++ * ATH10K_FW_CRASH_DUMP_RAM_DATA is disabled, so
++ * _ath10k_coredump_get_mem_layout() to accomplist that
++ */
++ hw_mem = _ath10k_coredump_get_mem_layout(ar);
+ if (!hw_mem)
+- return -ENOMEM;
++ /* if CONFIG_DEV_COREDUMP is disabled we get NULL, then
++ * just silently disable the feature by doing nothing
++ */
++ return 0;
+
+ for (i = 0; i < hw_mem->region_table.size; i++) {
+ tmp = &hw_mem->region_table.regions[i];
+diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
+index 7eb72290a925c..55e7e11d06d94 100644
+--- a/drivers/net/wireless/ath/ath10k/coredump.c
++++ b/drivers/net/wireless/ath/ath10k/coredump.c
+@@ -1447,11 +1447,17 @@ static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
+
+ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar)
+ {
+- int i;
+-
+ if (!test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask))
+ return NULL;
+
++ return _ath10k_coredump_get_mem_layout(ar);
++}
++EXPORT_SYMBOL(ath10k_coredump_get_mem_layout);
++
++const struct ath10k_hw_mem_layout *_ath10k_coredump_get_mem_layout(struct ath10k *ar)
++{
++ int i;
++
+ if (WARN_ON(ar->target_version == 0))
+ return NULL;
+
+@@ -1464,7 +1470,6 @@ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k
+
+ return NULL;
+ }
+-EXPORT_SYMBOL(ath10k_coredump_get_mem_layout);
+
+ struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
+ {
+diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h
+index 42404e246e0e9..240d705150888 100644
+--- a/drivers/net/wireless/ath/ath10k/coredump.h
++++ b/drivers/net/wireless/ath/ath10k/coredump.h
+@@ -176,6 +176,7 @@ int ath10k_coredump_register(struct ath10k *ar);
+ void ath10k_coredump_unregister(struct ath10k *ar);
+ void ath10k_coredump_destroy(struct ath10k *ar);
+
++const struct ath10k_hw_mem_layout *_ath10k_coredump_get_mem_layout(struct ath10k *ar);
+ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar);
+
+ #else /* CONFIG_DEV_COREDUMP */
+@@ -214,6 +215,12 @@ ath10k_coredump_get_mem_layout(struct ath10k *ar)
+ return NULL;
+ }
+
++static inline const struct ath10k_hw_mem_layout *
++_ath10k_coredump_get_mem_layout(struct ath10k *ar)
++{
++ return NULL;
++}
++
+ #endif /* CONFIG_DEV_COREDUMP */
+
+ #endif /* _COREDUMP_H_ */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index c272b290fa73d..1f73fbfee0c06 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -993,8 +993,12 @@ static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
+ 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;
+ }
+ }
+@@ -1048,7 +1052,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
+ 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);
+@@ -1494,7 +1498,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
+ 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;
+@@ -3422,7 +3426,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
+ 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
+@@ -5576,10 +5580,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
+ 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",
+@@ -5794,8 +5813,12 @@ err_vdev_delete:
+
+ 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;
+ }
+
+diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
+index 07e478f9a808c..80fcb917fe4e1 100644
+--- a/drivers/net/wireless/ath/ath10k/qmi.c
++++ b/drivers/net/wireless/ath/ath10k/qmi.c
+@@ -864,7 +864,8 @@ static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi)
+
+ ath10k_qmi_remove_msa_permission(qmi);
+ ath10k_core_free_board_files(ar);
+- if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
++ if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags) &&
++ !test_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags))
+ ath10k_snoc_fw_crashed_dump(ar);
+
+ ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND);
+diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
+index b746052737e0b..eb705214f3f0a 100644
+--- a/drivers/net/wireless/ath/ath10k/sdio.c
++++ b/drivers/net/wireless/ath/ath10k/sdio.c
+@@ -1363,8 +1363,11 @@ static void ath10k_rx_indication_async_work(struct work_struct *work)
+ ep->ep_ops.ep_rx_complete(ar, skb);
+ }
+
+- if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
++ if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) {
++ local_bh_disable();
+ napi_schedule(&ar->napi);
++ local_bh_enable();
++ }
+ }
+
+ static int ath10k_sdio_read_rtc_state(struct ath10k_sdio *ar_sdio, unsigned char *state)
+diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
+index ea00fbb156015..9513ab696fff1 100644
+--- a/drivers/net/wireless/ath/ath10k/snoc.c
++++ b/drivers/net/wireless/ath/ath10k/snoc.c
+@@ -12,6 +12,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/property.h>
+ #include <linux/regulator/consumer.h>
++#include <linux/remoteproc/qcom_rproc.h>
+ #include <linux/of_address.h>
+ #include <linux/iommu.h>
+
+@@ -1477,6 +1478,74 @@ void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)
+ mutex_unlock(&ar->dump_mutex);
+ }
+
++static int ath10k_snoc_modem_notify(struct notifier_block *nb, unsigned long action,
++ void *data)
++{
++ struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, nb);
++ struct ath10k *ar = ar_snoc->ar;
++ struct qcom_ssr_notify_data *notify_data = data;
++
++ switch (action) {
++ case QCOM_SSR_BEFORE_POWERUP:
++ ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem starting event\n");
++ clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
++ break;
++
++ case QCOM_SSR_AFTER_POWERUP:
++ ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem running event\n");
++ break;
++
++ case QCOM_SSR_BEFORE_SHUTDOWN:
++ ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem %s event\n",
++ notify_data->crashed ? "crashed" : "stopping");
++ if (!notify_data->crashed)
++ set_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
++ else
++ clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);
++ break;
++
++ case QCOM_SSR_AFTER_SHUTDOWN:
++ ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem offline event\n");
++ break;
++
++ default:
++ ath10k_err(ar, "received unrecognized event %lu\n", action);
++ break;
++ }
++
++ return NOTIFY_OK;
++}
++
++static int ath10k_modem_init(struct ath10k *ar)
++{
++ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
++ void *notifier;
++ int ret;
++
++ ar_snoc->nb.notifier_call = ath10k_snoc_modem_notify;
++
++ notifier = qcom_register_ssr_notifier("mpss", &ar_snoc->nb);
++ if (IS_ERR(notifier)) {
++ ret = PTR_ERR(notifier);
++ ath10k_err(ar, "failed to initialize modem notifier: %d\n", ret);
++ return ret;
++ }
++
++ ar_snoc->notifier = notifier;
++
++ return 0;
++}
++
++static void ath10k_modem_deinit(struct ath10k *ar)
++{
++ int ret;
++ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
++
++ ret = qcom_unregister_ssr_notifier(ar_snoc->notifier, &ar_snoc->nb);
++ if (ret)
++ ath10k_err(ar, "error %d unregistering notifier\n", ret);
++}
++
+ static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)
+ {
+ struct device *dev = ar->dev;
+@@ -1740,10 +1809,17 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
+ goto err_fw_deinit;
+ }
+
++ ret = ath10k_modem_init(ar);
++ if (ret)
++ goto err_qmi_deinit;
++
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
+
+ return 0;
+
++err_qmi_deinit:
++ ath10k_qmi_deinit(ar);
++
+ err_fw_deinit:
+ ath10k_fw_deinit(ar);
+
+@@ -1771,6 +1847,7 @@ static int ath10k_snoc_free_resources(struct ath10k *ar)
+ ath10k_fw_deinit(ar);
+ ath10k_snoc_free_irq(ar);
+ ath10k_snoc_release_resource(ar);
++ ath10k_modem_deinit(ar);
+ ath10k_qmi_deinit(ar);
+ ath10k_core_destroy(ar);
+
+diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
+index 5095d1893681b..d4bce17076960 100644
+--- a/drivers/net/wireless/ath/ath10k/snoc.h
++++ b/drivers/net/wireless/ath/ath10k/snoc.h
+@@ -6,6 +6,8 @@
+ #ifndef _SNOC_H_
+ #define _SNOC_H_
+
++#include <linux/notifier.h>
++
+ #include "hw.h"
+ #include "ce.h"
+ #include "qmi.h"
+@@ -45,6 +47,7 @@ struct ath10k_snoc_ce_irq {
+ enum ath10k_snoc_flags {
+ ATH10K_SNOC_FLAG_REGISTERED,
+ ATH10K_SNOC_FLAG_UNREGISTERING,
++ ATH10K_SNOC_FLAG_MODEM_STOPPED,
+ ATH10K_SNOC_FLAG_RECOVERY,
+ ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
+ };
+@@ -75,6 +78,8 @@ struct ath10k_snoc {
+ struct clk_bulk_data *clks;
+ size_t num_clks;
+ struct ath10k_qmi *qmi;
++ struct notifier_block nb;
++ void *notifier;
+ unsigned long flags;
+ bool xo_cal_supported;
+ u32 xo_cal_data;
+diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
+index 19b9c27e30e20..3d98f19c6ec8a 100644
+--- a/drivers/net/wireless/ath/ath10k/usb.c
++++ b/drivers/net/wireless/ath/ath10k/usb.c
+@@ -525,7 +525,7 @@ static int ath10k_usb_submit_ctrl_in(struct ath10k *ar,
+ 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",
+@@ -853,6 +853,11 @@ static int ath10k_usb_setup_pipe_resources(struct ath10k *ar,
+ le16_to_cpu(endpoint->wMaxPacketSize),
+ endpoint->bInterval);
+ }
++
++ /* Ignore broken descriptors. */
++ if (usb_endpoint_maxp(endpoint) == 0)
++ continue;
++
+ urbcount = 0;
+
+ pipe_num =
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index b8a4bbfe10b87..7c1c2658cb5f8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -2610,6 +2610,10 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+ 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,
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 41c1a3d339c25..01bfd09a9d88c 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -2066,7 +2066,9 @@ struct wmi_channel {
+ 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;
+@@ -2086,6 +2088,7 @@ struct wmi_channel_arg {
+ 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;
+diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c
+index 5e1f5437b4185..fd98ba5b1130b 100644
+--- a/drivers/net/wireless/ath/ath11k/dbring.c
++++ b/drivers/net/wireless/ath/ath11k/dbring.c
+@@ -8,8 +8,7 @@
+
+ static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
+ struct ath11k_dbring *ring,
+- struct ath11k_dbring_element *buff,
+- gfp_t gfp)
++ struct ath11k_dbring_element *buff)
+ {
+ struct ath11k_base *ab = ar->ab;
+ struct hal_srng *srng;
+@@ -35,7 +34,7 @@ static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
+ goto err;
+
+ spin_lock_bh(&ring->idr_lock);
+- buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, gfp);
++ buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, GFP_ATOMIC);
+ spin_unlock_bh(&ring->idr_lock);
+ if (buf_id < 0) {
+ ret = -ENOBUFS;
+@@ -72,8 +71,7 @@ err:
+ }
+
+ static int ath11k_dbring_fill_bufs(struct ath11k *ar,
+- struct ath11k_dbring *ring,
+- gfp_t gfp)
++ struct ath11k_dbring *ring)
+ {
+ struct ath11k_dbring_element *buff;
+ struct hal_srng *srng;
+@@ -92,11 +90,11 @@ static int ath11k_dbring_fill_bufs(struct ath11k *ar,
+ size = sizeof(*buff) + ring->buf_sz + align - 1;
+
+ while (num_remain > 0) {
+- buff = kzalloc(size, gfp);
++ buff = kzalloc(size, GFP_ATOMIC);
+ if (!buff)
+ break;
+
+- ret = ath11k_dbring_bufs_replenish(ar, ring, buff, gfp);
++ ret = ath11k_dbring_bufs_replenish(ar, ring, buff);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n",
+ num_remain, req_entries);
+@@ -176,7 +174,7 @@ int ath11k_dbring_buf_setup(struct ath11k *ar,
+ ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng);
+ ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng);
+
+- ret = ath11k_dbring_fill_bufs(ar, ring, GFP_KERNEL);
++ ret = ath11k_dbring_fill_bufs(ar, ring);
+
+ return ret;
+ }
+@@ -322,7 +320,7 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
+ }
+
+ memset(buff, 0, size);
+- ath11k_dbring_bufs_replenish(ar, ring, buff, GFP_ATOMIC);
++ ath11k_dbring_bufs_replenish(ar, ring, buff);
+ }
+
+ spin_unlock_bh(&srng->lock);
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index 9a224817630ae..0ae6bebff801d 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -2337,8 +2337,10 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
+ channel_num = meta_data;
+ center_freq = meta_data >> 16;
+
+- if (center_freq >= 5935 && center_freq <= 7105) {
++ if (center_freq >= ATH11K_MIN_6G_FREQ &&
++ center_freq <= ATH11K_MAX_6G_FREQ) {
+ rx_status->band = NL80211_BAND_6GHZ;
++ rx_status->freq = center_freq;
+ } else if (channel_num >= 1 && channel_num <= 14) {
+ rx_status->band = NL80211_BAND_2GHZ;
+ } else if (channel_num >= 36 && channel_num <= 173) {
+@@ -2356,8 +2358,9 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
+ rx_desc, sizeof(struct hal_rx_desc));
+ }
+
+- rx_status->freq = ieee80211_channel_to_frequency(channel_num,
+- rx_status->band);
++ if (rx_status->band != NL80211_BAND_6GHZ)
++ rx_status->freq = ieee80211_channel_to_frequency(channel_num,
++ rx_status->band);
+
+ ath11k_dp_rx_h_rate(ar, rx_desc, rx_status);
+ }
+@@ -3310,7 +3313,7 @@ static int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_ti
+
+ paddr = dma_map_single(ab->dev, defrag_skb->data,
+ defrag_skb->len + skb_tailroom(defrag_skb),
+- DMA_FROM_DEVICE);
++ DMA_TO_DEVICE);
+ if (dma_mapping_error(ab->dev, paddr))
+ return -ENOMEM;
+
+@@ -3375,7 +3378,7 @@ err_free_idr:
+ spin_unlock_bh(&rx_refill_ring->idr_lock);
+ err_unmap_dma:
+ dma_unmap_single(ab->dev, paddr, defrag_skb->len + skb_tailroom(defrag_skb),
+- DMA_FROM_DEVICE);
++ DMA_TO_DEVICE);
+ return ret;
+ }
+
+diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
+index e9b3689331ec2..89a64ebd620f3 100644
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -6590,7 +6590,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
+ ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
+
+ /* Apply the regd received during initialization */
+- ret = ath11k_regd_update(ar, true);
++ ret = ath11k_regd_update(ar);
+ if (ret) {
+ ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret);
+ goto err_unregister_hw;
+diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
+index 26c7ae242db67..49c0b1ad40a02 100644
+--- a/drivers/net/wireless/ath/ath11k/mhi.c
++++ b/drivers/net/wireless/ath/ath11k/mhi.c
+@@ -533,7 +533,11 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci,
+ ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
+ break;
+ case ATH11K_MHI_RESUME:
+- ret = mhi_pm_resume(ab_pci->mhi_ctrl);
++ /* Do force MHI resume as some devices like QCA6390, WCN6855
++ * are not in M3 state but they are functional. So just ignore
++ * the MHI state while resuming.
++ */
++ ret = mhi_pm_resume_force(ab_pci->mhi_ctrl);
+ break;
+ case ATH11K_MHI_TRIGGER_RDDM:
+ ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);
+diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
+index b5e34d670715e..4c5071b7d11dc 100644
+--- a/drivers/net/wireless/ath/ath11k/qmi.c
++++ b/drivers/net/wireless/ath/ath11k/qmi.c
+@@ -2707,8 +2707,10 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
+ list_del(&event->list);
+ spin_unlock(&qmi->event_lock);
+
+- if (test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))
++ if (test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)) {
++ kfree(event);
+ return;
++ }
+
+ switch (event->type) {
+ case ATH11K_QMI_EVENT_SERVER_ARRIVE:
+diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c
+index e1a1df169034b..92c59009a8ac2 100644
+--- a/drivers/net/wireless/ath/ath11k/reg.c
++++ b/drivers/net/wireless/ath/ath11k/reg.c
+@@ -198,7 +198,7 @@ static void ath11k_copy_regd(struct ieee80211_regdomain *regd_orig,
+ sizeof(struct ieee80211_reg_rule));
+ }
+
+-int ath11k_regd_update(struct ath11k *ar, bool init)
++int ath11k_regd_update(struct ath11k *ar)
+ {
+ struct ieee80211_regdomain *regd, *regd_copy = NULL;
+ int ret, regd_len, pdev_id;
+@@ -209,7 +209,10 @@ int ath11k_regd_update(struct ath11k *ar, bool init)
+
+ spin_lock_bh(&ab->base_lock);
+
+- if (init) {
++ /* Prefer the latest regd update over default if it's available */
++ if (ab->new_regd[pdev_id]) {
++ regd = ab->new_regd[pdev_id];
++ } else {
+ /* Apply the regd received during init through
+ * WMI_REG_CHAN_LIST_CC event. In case of failure to
+ * receive the regd, initialize with a default world
+@@ -222,8 +225,6 @@ int ath11k_regd_update(struct ath11k *ar, bool init)
+ "failed to receive default regd during init\n");
+ regd = (struct ieee80211_regdomain *)&ath11k_world_regd;
+ }
+- } else {
+- regd = ab->new_regd[pdev_id];
+ }
+
+ if (!regd) {
+@@ -683,7 +684,7 @@ void ath11k_regd_update_work(struct work_struct *work)
+ regd_update_work);
+ int ret;
+
+- ret = ath11k_regd_update(ar, false);
++ ret = ath11k_regd_update(ar);
+ if (ret) {
+ /* Firmware has already moved to the new regd. We need
+ * to maintain channel consistency across FW, Host driver
+diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h
+index 65d56d44796f6..5fb9dc03a74e8 100644
+--- a/drivers/net/wireless/ath/ath11k/reg.h
++++ b/drivers/net/wireless/ath/ath11k/reg.h
+@@ -31,6 +31,6 @@ void ath11k_regd_update_work(struct work_struct *work);
+ struct ieee80211_regdomain *
+ ath11k_reg_build_regd(struct ath11k_base *ab,
+ struct cur_regulatory_info *reg_info, bool intersect);
+-int ath11k_regd_update(struct ath11k *ar, bool init);
++int ath11k_regd_update(struct ath11k *ar);
+ int ath11k_reg_update_chan_list(struct ath11k *ar);
+ #endif
+diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
+index 6c253eae9d069..99c0b81e496bf 100644
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -1339,6 +1339,7 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar,
+ WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST) |
+ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+ cmd->req_type = type;
++ cmd->pdev_id = ar->pdev->pdev_id;
+
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+ "WMI bss chan info req type %d\n", type);
+@@ -5792,6 +5793,17 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
+
+ pdev_idx = reg_info->phy_id;
+
++ /* Avoid default reg rule updates sent during FW recovery if
++ * it is already available
++ */
++ spin_lock(&ab->base_lock);
++ if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) &&
++ ab->default_regd[pdev_idx]) {
++ spin_unlock(&ab->base_lock);
++ goto mem_free;
++ }
++ spin_unlock(&ab->base_lock);
++
+ if (pdev_idx >= ab->num_radios) {
+ /* Process the event for phy0 only if single_pdev_only
+ * is true. If pdev_idx is valid but not 0, discard the
+@@ -5829,10 +5841,10 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
+ }
+
+ spin_lock(&ab->base_lock);
+- if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
+- /* Once mac is registered, ar is valid and all CC events from
+- * fw is considered to be received due to user requests
+- * currently.
++ if (ab->default_regd[pdev_idx]) {
++ /* The initial rules from FW after WMI Init is to build
++ * the default regd. From then on, any rules updated for
++ * the pdev could be due to user reg changes.
+ * Free previously built regd before assigning the newly
+ * generated regd to ar. NULL pointer handling will be
+ * taken care by kfree itself.
+@@ -5842,13 +5854,9 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
+ ab->new_regd[pdev_idx] = regd;
+ ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+ } else {
+- /* Multiple events for the same *ar is not expected. But we
+- * can still clear any previously stored default_regd if we
+- * are receiving this event for the same radio by mistake.
+- * NULL pointer handling will be taken care by kfree itself.
++ /* This regd would be applied during mac registration and is
++ * held constant throughout for regd intersection purpose
+ */
+- kfree(ab->default_regd[pdev_idx]);
+- /* This regd would be applied during mac registration */
+ ab->default_regd[pdev_idx] = regd;
+ }
+ ab->dfs_region = reg_info->dfs_region;
+@@ -6119,8 +6127,10 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
+ if (rx_ev.status & WMI_RX_STATUS_ERR_MIC)
+ status->flag |= RX_FLAG_MMIC_ERROR;
+
+- if (rx_ev.chan_freq >= ATH11K_MIN_6G_FREQ) {
++ if (rx_ev.chan_freq >= ATH11K_MIN_6G_FREQ &&
++ rx_ev.chan_freq <= ATH11K_MAX_6G_FREQ) {
+ status->band = NL80211_BAND_6GHZ;
++ status->freq = rx_ev.chan_freq;
+ } else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) {
+ status->band = NL80211_BAND_2GHZ;
+ } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH11K_MAX_5G_CHAN) {
+@@ -6141,8 +6151,10 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
+
+ sband = &ar->mac.sbands[status->band];
+
+- status->freq = ieee80211_channel_to_frequency(rx_ev.channel,
+- status->band);
++ if (status->band != NL80211_BAND_6GHZ)
++ status->freq = ieee80211_channel_to_frequency(rx_ev.channel,
++ status->band);
++
+ status->signal = rx_ev.snr + ATH11K_DEFAULT_NOISE_FLOOR;
+ status->rate_idx = ath11k_mac_bitrate_to_idx(sband, rx_ev.rate / 100);
+
+@@ -6301,6 +6313,8 @@ static void ath11k_scan_event(struct ath11k_base *ab, struct sk_buff *skb)
+ ath11k_wmi_event_scan_start_failed(ar);
+ break;
+ case WMI_SCAN_EVENT_DEQUEUED:
++ __ath11k_mac_scan_finish(ar);
++ break;
+ case WMI_SCAN_EVENT_PREEMPTED:
+ case WMI_SCAN_EVENT_RESTARTED:
+ case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:
+diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
+index d35c47e0b19d4..0b7d337b36930 100644
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -2960,6 +2960,7 @@ struct wmi_pdev_bss_chan_info_req_cmd {
+ u32 tlv_header;
+ /* ref wmi_bss_chan_info_req_type */
+ u32 req_type;
++ u32 pdev_id;
+ } __packed;
+
+ struct wmi_ap_ps_peer_cmd {
+@@ -4056,7 +4057,6 @@ struct wmi_vdev_stopped_event {
+ } __packed;
+
+ struct wmi_pdev_bss_chan_info_event {
+- u32 pdev_id;
+ u32 freq; /* Units in MHz */
+ u32 noise_floor; /* units are dBm */
+ /* rx clear - how often the channel was unused */
+@@ -4074,6 +4074,7 @@ struct wmi_pdev_bss_chan_info_event {
+ /*rx_cycle cnt for my bss in 64bits format */
+ u32 rx_bss_cycle_count_low;
+ u32 rx_bss_cycle_count_high;
++ u32 pdev_id;
+ } __packed;
+
+ #define WMI_VDEV_INSTALL_KEY_COMPL_STATUS_SUCCESS 0
+diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
+index 5372e948e761d..aba70f35e574b 100644
+--- a/drivers/net/wireless/ath/ath6kl/usb.c
++++ b/drivers/net/wireless/ath/ath6kl/usb.c
+@@ -340,6 +340,11 @@ static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb)
+ 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 @@ static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
+ 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);
+diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
+index 139831539da37..98090e40e1cf4 100644
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -533,8 +533,10 @@ irqreturn_t ath_isr(int irq, void *dev)
+ 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
+diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
+index 80390495ea250..75cb53a3ec15e 100644
+--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
++++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
+@@ -183,10 +183,12 @@ static void channel_detector_exit(struct dfs_pattern_detector *dpd,
+ 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);
+diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
+index 8e1dbfda65386..aff04ef662663 100644
+--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
++++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
+@@ -403,8 +403,21 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
+ dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
+ ctl->skb->len, DMA_TO_DEVICE);
+ info = IEEE80211_SKB_CB(ctl->skb);
+- if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
+- /* Keep frame until TX status comes */
++ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
++ if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
++ info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
++ ieee80211_tx_status_irqsafe(wcn->hw, ctl->skb);
++ } else {
++ /* Wait for the TX ack indication or timeout... */
++ spin_lock(&wcn->dxe_lock);
++ if (WARN_ON(wcn->tx_ack_skb))
++ ieee80211_free_txskb(wcn->hw, wcn->tx_ack_skb);
++ wcn->tx_ack_skb = ctl->skb; /* Tracking ref */
++ mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10);
++ spin_unlock(&wcn->dxe_lock);
++ }
++ /* do not free, ownership transferred to mac80211 status cb */
++ } else {
+ ieee80211_free_txskb(wcn->hw, ctl->skb);
+ }
+
+@@ -426,7 +439,6 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
+ {
+ struct wcn36xx *wcn = (struct wcn36xx *)dev;
+ int int_src, int_reason;
+- bool transmitted = false;
+
+ wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
+
+@@ -466,7 +478,6 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
+ if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK |
+ WCN36XX_CH_STAT_INT_ED_MASK)) {
+ reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
+- transmitted = true;
+ }
+ }
+
+@@ -479,7 +490,6 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
+ WCN36XX_DXE_0_INT_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_L);
+
+-
+ if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_ERR_CLR,
+@@ -507,25 +517,8 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
+ if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK |
+ WCN36XX_CH_STAT_INT_ED_MASK)) {
+ reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
+- transmitted = true;
+- }
+- }
+-
+- spin_lock(&wcn->dxe_lock);
+- if (wcn->tx_ack_skb && transmitted) {
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(wcn->tx_ack_skb);
+-
+- /* TX complete, no need to wait for 802.11 ack indication */
+- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS &&
+- info->flags & IEEE80211_TX_CTL_NO_ACK) {
+- info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+- del_timer(&wcn->tx_ack_timer);
+- ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
+- wcn->tx_ack_skb = NULL;
+- ieee80211_wake_queues(wcn->hw);
+ }
+ }
+- spin_unlock(&wcn->dxe_lock);
+
+ return IRQ_HANDLED;
+ }
+@@ -613,6 +606,10 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
+ 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);
+@@ -623,9 +620,15 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
+ 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;
+ }
+diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
+index 455143c4164ee..de3bca043c2b3 100644
+--- a/drivers/net/wireless/ath/wcn36xx/hal.h
++++ b/drivers/net/wireless/ath/wcn36xx/hal.h
+@@ -359,6 +359,8 @@ enum wcn36xx_hal_host_msg_type {
+ WCN36XX_HAL_START_SCAN_OFFLOAD_RSP = 205,
+ WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ = 206,
+ WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP = 207,
++ WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ = 208,
++ WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP = 209,
+ WCN36XX_HAL_SCAN_OFFLOAD_IND = 210,
+
+ WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
+@@ -1353,6 +1355,36 @@ struct wcn36xx_hal_stop_scan_offload_rsp_msg {
+ u32 status;
+ } __packed;
+
++#define WCN36XX_HAL_CHAN_REG1_MIN_PWR_MASK 0x000000ff
++#define WCN36XX_HAL_CHAN_REG1_MAX_PWR_MASK 0x0000ff00
++#define WCN36XX_HAL_CHAN_REG1_REG_PWR_MASK 0x00ff0000
++#define WCN36XX_HAL_CHAN_REG1_CLASS_ID_MASK 0xff000000
++#define WCN36XX_HAL_CHAN_REG2_ANT_GAIN_MASK 0x000000ff
++#define WCN36XX_HAL_CHAN_INFO_FLAG_PASSIVE BIT(7)
++#define WCN36XX_HAL_CHAN_INFO_FLAG_DFS BIT(10)
++#define WCN36XX_HAL_CHAN_INFO_FLAG_HT BIT(11)
++#define WCN36XX_HAL_CHAN_INFO_FLAG_VHT BIT(12)
++#define WCN36XX_HAL_CHAN_INFO_PHY_11A 0
++#define WCN36XX_HAL_CHAN_INFO_PHY_11BG 1
++#define WCN36XX_HAL_DEFAULT_ANT_GAIN 6
++#define WCN36XX_HAL_DEFAULT_MIN_POWER 6
++
++struct wcn36xx_hal_channel_param {
++ u32 mhz;
++ u32 band_center_freq1;
++ u32 band_center_freq2;
++ u32 channel_info;
++ u32 reg_info_1;
++ u32 reg_info_2;
++} __packed;
++
++struct wcn36xx_hal_update_channel_list_req_msg {
++ struct wcn36xx_hal_msg_header header;
++
++ u8 num_channel;
++ struct wcn36xx_hal_channel_param channels[80];
++} __packed;
++
+ enum wcn36xx_hal_rate_index {
+ HW_RATE_INDEX_1MBPS = 0x82,
+ HW_RATE_INDEX_2MBPS = 0x84,
+diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
+index ec913ec991f3f..5d82aca370a72 100644
+--- a/drivers/net/wireless/ath/wcn36xx/main.c
++++ b/drivers/net/wireless/ath/wcn36xx/main.c
+@@ -135,7 +135,9 @@ static struct ieee80211_supported_band wcn_band_2ghz = {
+ .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,
+@@ -569,12 +571,14 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {
+ sta_priv->is_data_encrypted = true;
+ /* Reconfigure bss with encrypt_type */
+- if (NL80211_IFTYPE_STATION == vif->type)
++ if (NL80211_IFTYPE_STATION == vif->type) {
+ wcn36xx_smd_config_bss(wcn,
+ vif,
+ sta,
+ sta->addr,
+ true);
++ wcn36xx_smd_config_sta(wcn, vif, sta);
++ }
+
+ wcn36xx_smd_set_stakey(wcn,
+ vif_priv->encrypt_type,
+@@ -604,15 +608,6 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ }
+ }
+ }
+- /* FIXME: Only enable bmps support when encryption is enabled.
+- * For any reasons, when connected to open/no-security BSS,
+- * the wcn36xx controller in bmps mode does not forward
+- * 'wake-up' beacons despite AP sends DTIM with station AID.
+- * It could be due to a firmware issue or to the way driver
+- * configure the station.
+- */
+- if (vif->type == NL80211_IFTYPE_STATION)
+- vif_priv->allow_bmps = true;
+ break;
+ case DISABLE_KEY:
+ if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
+@@ -676,6 +671,7 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
+
+ mutex_unlock(&wcn->scan_lock);
+
++ wcn36xx_smd_update_channel_list(wcn, &hw_req->req);
+ return wcn36xx_smd_start_hw_scan(wcn, vif, &hw_req->req);
+ }
+
+@@ -913,7 +909,6 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
+ vif->addr,
+ bss_conf->aid);
+ vif_priv->sta_assoc = false;
+- vif_priv->allow_bmps = false;
+ wcn36xx_smd_set_link_st(wcn,
+ bss_conf->bssid,
+ vif->addr,
+@@ -1123,6 +1118,13 @@ static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
+ goto out;
+ ret = wcn36xx_smd_wlan_host_suspend_ind(wcn);
+ }
++
++ /* Disable IRQ, we don't want to handle any packet before mac80211 is
++ * resumed and ready to receive packets.
++ */
++ disable_irq(wcn->tx_irq);
++ disable_irq(wcn->rx_irq);
++
+ out:
+ mutex_unlock(&wcn->conf_mutex);
+ return ret;
+@@ -1145,6 +1147,10 @@ static int wcn36xx_resume(struct ieee80211_hw *hw)
+ wcn36xx_smd_ipv6_ns_offload(wcn, vif, false);
+ wcn36xx_smd_arp_offload(wcn, vif, false);
+ }
++
++ enable_irq(wcn->tx_irq);
++ enable_irq(wcn->rx_irq);
++
+ mutex_unlock(&wcn->conf_mutex);
+
+ return 0;
+@@ -1338,7 +1344,6 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
+ ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
+ ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS);
+- ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
+
+ wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.c b/drivers/net/wireless/ath/wcn36xx/pmc.c
+index 2d0780fefd477..2936aaf532738 100644
+--- a/drivers/net/wireless/ath/wcn36xx/pmc.c
++++ b/drivers/net/wireless/ath/wcn36xx/pmc.c
+@@ -23,10 +23,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
+ {
+ int ret = 0;
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+-
+- if (!vif_priv->allow_bmps)
+- return -ENOTSUPP;
+-
++ /* TODO: Make sure the TX chain clean */
+ ret = wcn36xx_smd_enter_bmps(wcn, vif);
+ if (!ret) {
+ wcn36xx_dbg(WCN36XX_DBG_PMC, "Entered BMPS\n");
+diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
+index 57fa857b290b7..70bffe3d87a12 100644
+--- a/drivers/net/wireless/ath/wcn36xx/smd.c
++++ b/drivers/net/wireless/ath/wcn36xx/smd.c
+@@ -16,6 +16,7 @@
+
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
++#include <linux/bitfield.h>
+ #include <linux/etherdevice.h>
+ #include <linux/firmware.h>
+ #include <linux/bitops.h>
+@@ -927,6 +928,86 @@ out:
+ return ret;
+ }
+
++int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_request *req)
++{
++ struct wcn36xx_hal_update_channel_list_req_msg *msg_body;
++ int ret, i;
++
++ msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);
++ if (!msg_body)
++ return -ENOMEM;
++
++ INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ);
++
++ msg_body->num_channel = min_t(u8, req->n_channels, sizeof(msg_body->channels));
++ for (i = 0; i < msg_body->num_channel; i++) {
++ struct wcn36xx_hal_channel_param *param = &msg_body->channels[i];
++ u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER;
++ u32 ant_gain = WCN36XX_HAL_DEFAULT_ANT_GAIN;
++
++ param->mhz = req->channels[i]->center_freq;
++ param->band_center_freq1 = req->channels[i]->center_freq;
++ param->band_center_freq2 = 0;
++
++ if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_PASSIVE;
++
++ if (req->channels[i]->flags & IEEE80211_CHAN_RADAR)
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_DFS;
++
++ if (req->channels[i]->band == NL80211_BAND_5GHZ) {
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_HT;
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_VHT;
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11A;
++ } else {
++ param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11BG;
++ }
++
++ if (min_power > req->channels[i]->max_power)
++ min_power = req->channels[i]->max_power;
++
++ if (req->channels[i]->max_antenna_gain)
++ ant_gain = req->channels[i]->max_antenna_gain;
++
++ u32p_replace_bits(&param->reg_info_1, min_power,
++ WCN36XX_HAL_CHAN_REG1_MIN_PWR_MASK);
++ u32p_replace_bits(&param->reg_info_1, req->channels[i]->max_power,
++ WCN36XX_HAL_CHAN_REG1_MAX_PWR_MASK);
++ u32p_replace_bits(&param->reg_info_1, req->channels[i]->max_reg_power,
++ WCN36XX_HAL_CHAN_REG1_REG_PWR_MASK);
++ u32p_replace_bits(&param->reg_info_1, 0,
++ WCN36XX_HAL_CHAN_REG1_CLASS_ID_MASK);
++ u32p_replace_bits(&param->reg_info_2, ant_gain,
++ WCN36XX_HAL_CHAN_REG2_ANT_GAIN_MASK);
++
++ wcn36xx_dbg(WCN36XX_DBG_HAL,
++ "%s: freq=%u, channel_info=%08x, reg_info1=%08x, reg_info2=%08x\n",
++ __func__, param->mhz, param->channel_info, param->reg_info_1,
++ param->reg_info_2);
++ }
++
++ mutex_lock(&wcn->hal_mutex);
++
++ PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));
++
++ ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
++ if (ret) {
++ wcn36xx_err("Sending hal_update_channel_list failed\n");
++ goto out;
++ }
++
++ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
++ if (ret) {
++ wcn36xx_err("hal_update_channel_list response failed err=%d\n", ret);
++ goto out;
++ }
++
++out:
++ kfree(msg_body);
++ mutex_unlock(&wcn->hal_mutex);
++ return ret;
++}
++
+ static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)
+ {
+ struct wcn36xx_hal_switch_channel_rsp_msg *rsp;
+@@ -2623,30 +2704,52 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
+ 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;
+ }
+
+@@ -3060,6 +3163,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
+ case WCN36XX_HAL_GTK_OFFLOAD_RSP:
+ case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP:
+ case WCN36XX_HAL_HOST_RESUME_RSP:
++ case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP:
+ memcpy(wcn->hal_buf, buf, len);
+ wcn->hal_rsp_len = len;
+ complete(&wcn->hal_rsp_compl);
+diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
+index d8bded03945d4..d3774568d885e 100644
+--- a/drivers/net/wireless/ath/wcn36xx/smd.h
++++ b/drivers/net/wireless/ath/wcn36xx/smd.h
+@@ -70,6 +70,7 @@ int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t cha
+ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req);
+ int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn);
++int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_request *req);
+ int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
+ int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
+ int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
+diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
+index cab196bb38cd4..bbd7194c82e27 100644
+--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
++++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
+@@ -31,6 +31,13 @@ struct wcn36xx_rate {
+ enum rate_info_bw bw;
+ };
+
++/* Buffer descriptor rx_ch field is limited to 5-bit (4+1), a mapping is used
++ * for 11A Channels.
++ */
++static const u8 ab_rx_ch_map[] = { 36, 40, 44, 48, 52, 56, 60, 64, 100, 104,
++ 108, 112, 116, 120, 124, 128, 132, 136, 140,
++ 149, 153, 157, 161, 165, 144 };
++
+ static const struct wcn36xx_rate wcn36xx_rate_table[] = {
+ /* 11b rates */
+ { 10, 0, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 },
+@@ -291,6 +298,22 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
+ ieee80211_is_probe_resp(hdr->frame_control))
+ status.boottime_ns = ktime_get_boottime_ns();
+
++ if (bd->scan_learn) {
++ /* If packet originates from hardware scanning, extract the
++ * band/channel from bd descriptor.
++ */
++ u8 hwch = (bd->reserved0 << 4) + bd->rx_ch;
++
++ if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) {
++ status.band = NL80211_BAND_5GHZ;
++ status.freq = ieee80211_channel_to_frequency(ab_rx_ch_map[hwch - 1],
++ status.band);
++ } else {
++ status.band = NL80211_BAND_2GHZ;
++ status.freq = ieee80211_channel_to_frequency(hwch, status.band);
++ }
++ }
++
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+
+ if (ieee80211_is_beacon(hdr->frame_control)) {
+@@ -321,8 +344,6 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
+ bd->pdu.mpdu_header_off;
+ bd->pdu.mpdu_len = len;
+ bd->pdu.tid = tid;
+- /* Use seq number generated by mac80211 */
+- bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST;
+ }
+
+ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
+@@ -419,6 +440,9 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
+ tid = ieee80211_get_tid(hdr);
+ /* TID->QID is one-to-one mapping */
+ bd->queue_id = tid;
++ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS;
++ } else {
++ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS;
+ }
+
+ if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT ||
+@@ -429,6 +453,9 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
+ if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
+ /* Don't use a regular queue for null packet (no ampdu) */
+ bd->queue_id = WCN36XX_TX_U_WQ_ID;
++ bd->bd_rate = WCN36XX_BD_RATE_CTRL;
++ if (ieee80211_is_qos_nullfunc(hdr->frame_control))
++ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST;
+ }
+
+ if (bcast) {
+@@ -488,6 +515,8 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
+ bd->queue_id = WCN36XX_TX_U_WQ_ID;
+ *vif_priv = __vif_priv;
+
++ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS;
++
+ wcn36xx_set_tx_pdu(bd,
+ ieee80211_is_data_qos(hdr->frame_control) ?
+ sizeof(struct ieee80211_qos_hdr) :
+@@ -502,10 +531,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct wcn36xx_vif *vif_priv = NULL;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+- unsigned long flags;
+ bool is_low = ieee80211_is_data(hdr->frame_control);
+ bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
+ is_multicast_ether_addr(hdr->addr1);
++ bool ack_ind = (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) &&
++ !(info->flags & IEEE80211_TX_CTL_NO_ACK);
+ struct wcn36xx_tx_bd bd;
+ int ret;
+
+@@ -521,30 +551,16 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
+
+ bd.dpu_rf = WCN36XX_BMU_WQ_TX;
+
+- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
++ if (unlikely(ack_ind)) {
+ wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
+
+- spin_lock_irqsave(&wcn->dxe_lock, flags);
+- if (wcn->tx_ack_skb) {
+- spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+- wcn36xx_warn("tx_ack_skb already set\n");
+- return -EINVAL;
+- }
+-
+- wcn->tx_ack_skb = skb;
+- spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+-
+ /* Only one at a time is supported by fw. Stop the TX queues
+ * until the ack status gets back.
+ */
+ ieee80211_stop_queues(wcn->hw);
+
+- /* TX watchdog if no TX irq or ack indication received */
+- mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10);
+-
+ /* Request ack indication from the firmware */
+- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+- bd.tx_comp = 1;
++ bd.tx_comp = 1;
+ }
+
+ /* Data frames served first*/
+@@ -558,14 +574,8 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
+ bd.tx_bd_sign = 0xbdbdbdbd;
+
+ ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
+- if (ret && (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
+- /* If the skb has not been transmitted,
+- * don't keep a reference to it.
+- */
+- spin_lock_irqsave(&wcn->dxe_lock, flags);
+- wcn->tx_ack_skb = NULL;
+- spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+-
++ if (unlikely(ret && ack_ind)) {
++ /* If the skb has not been transmitted, resume TX queue */
+ ieee80211_wake_queues(wcn->hw);
+ }
+
+diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h
+index 032216e82b2be..b54311ffde9c5 100644
+--- a/drivers/net/wireless/ath/wcn36xx/txrx.h
++++ b/drivers/net/wireless/ath/wcn36xx/txrx.h
+@@ -110,7 +110,8 @@ struct wcn36xx_rx_bd {
+ /* 0x44 */
+ u32 exp_seq_num:12;
+ u32 cur_seq_num:12;
+- u32 fr_type_subtype:8;
++ u32 rf_band:2;
++ u32 fr_type_subtype:6;
+
+ /* 0x48 */
+ u32 msdu_size:16;
+diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+index add6e527e8330..e9560f35e9bcf 100644
+--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
++++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+@@ -128,7 +128,6 @@ struct wcn36xx_vif {
+ enum wcn36xx_hal_bss_type bss_type;
+
+ /* Power management */
+- bool allow_bmps;
+ enum wcn36xx_power_state pw_state;
+
+ u8 bss_index;
+diff --git a/drivers/net/wireless/broadcom/b43/phy_g.c b/drivers/net/wireless/broadcom/b43/phy_g.c
+index d5a1a5c582366..ac72ca39e409b 100644
+--- a/drivers/net/wireless/broadcom/b43/phy_g.c
++++ b/drivers/net/wireless/broadcom/b43/phy_g.c
+@@ -2297,7 +2297,7 @@ static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
+ 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++) {
+diff --git a/drivers/net/wireless/broadcom/b43legacy/radio.c b/drivers/net/wireless/broadcom/b43legacy/radio.c
+index 06891b4f837b9..fdf78c10a05c2 100644
+--- a/drivers/net/wireless/broadcom/b43legacy/radio.c
++++ b/drivers/net/wireless/broadcom/b43legacy/radio.c
+@@ -283,7 +283,7 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
+ & 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++) {
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+index 6d5188b78f2de..0af452dca7664 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+@@ -75,6 +75,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
+ },
+ .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.
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+index dde22bdc87039..069fcbc46d2ba 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+@@ -284,16 +284,19 @@ int iwl_pnvm_load(struct iwl_trans *trans,
+ /* First attempt to get the PNVM from BIOS */
+ package = iwl_uefi_get_pnvm(trans, &len);
+ if (!IS_ERR_OR_NULL(package)) {
+- data = kmemdup(package->data, len, GFP_KERNEL);
++ if (len >= sizeof(*package)) {
++ /* we need only the data */
++ len -= sizeof(*package);
++ data = kmemdup(package->data, len, GFP_KERNEL);
++ } else {
++ data = NULL;
++ }
+
+ /* free package regardless of whether kmemdup succeeded */
+ kfree(package);
+
+- if (data) {
+- /* we need only the data size */
+- len -= sizeof(*package);
++ if (data)
+ goto parse;
+- }
+ }
+
+ /* If it's not available, try from the filesystem */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+index c875bf35533ce..009dd4be597b0 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+@@ -86,6 +86,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ if (len < tlv_len) {
+ IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
++ kfree(reduce_power_data);
+ reduce_power_data = ERR_PTR(-EINVAL);
+ goto out;
+ }
+@@ -105,6 +106,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ IWL_DEBUG_FW(trans,
+ "Couldn't allocate (more) reduce_power_data\n");
+
++ kfree(reduce_power_data);
+ reduce_power_data = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+@@ -134,6 +136,10 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ done:
+ if (!size) {
+ IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");
++ /* Better safe than sorry, but 'reduce_power_data' should
++ * always be NULL if !size.
++ */
++ kfree(reduce_power_data);
+ reduce_power_data = ERR_PTR(-ENOENT);
+ goto out;
+ }
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+index 77124b8b235ee..94553f272d377 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+@@ -1271,23 +1271,31 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
+ const struct iwl_op_mode_ops *ops = op->ops;
+ struct dentry *dbgfs_dir = NULL;
+ struct iwl_op_mode *op_mode = NULL;
++ int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY;
++
++ for (retry = 0; retry <= max_retry; retry++) {
+
+ #ifdef CONFIG_IWLWIFI_DEBUGFS
+- drv->dbgfs_op_mode = debugfs_create_dir(op->name,
+- drv->dbgfs_drv);
+- dbgfs_dir = drv->dbgfs_op_mode;
++ drv->dbgfs_op_mode = debugfs_create_dir(op->name,
++ drv->dbgfs_drv);
++ dbgfs_dir = drv->dbgfs_op_mode;
+ #endif
+
+- op_mode = ops->start(drv->trans, drv->trans->cfg, &drv->fw, dbgfs_dir);
++ op_mode = ops->start(drv->trans, drv->trans->cfg,
++ &drv->fw, dbgfs_dir);
++
++ if (op_mode)
++ return op_mode;
++
++ IWL_ERR(drv, "retry init count %d\n", retry);
+
+ #ifdef CONFIG_IWLWIFI_DEBUGFS
+- if (!op_mode) {
+ debugfs_remove_recursive(drv->dbgfs_op_mode);
+ drv->dbgfs_op_mode = NULL;
+- }
+ #endif
++ }
+
+- return op_mode;
++ return NULL;
+ }
+
+ static void _iwl_op_mode_stop(struct iwl_drv *drv)
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+index b6442df0c6439..56f2fd3b94906 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+@@ -90,4 +90,7 @@ void iwl_drv_stop(struct iwl_drv *drv);
+ #define IWL_EXPORT_SYMBOL(sym)
+ #endif
+
++/* max retry for init flow */
++#define IWL_MAX_INIT_RETRY 2
++
+ #endif /* __iwl_drv_h__ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+index 9f706fffb5922..d3013a51a5096 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+@@ -2336,7 +2336,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
+ iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+ false, 0);
+ ret = 1;
+- mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+ goto err;
+ }
+
+@@ -2385,6 +2384,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
+ }
+ }
+
++ /* after the successful handshake, we're out of D3 */
+ mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+
+ /*
+@@ -2455,6 +2455,9 @@ out:
+ */
+ set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);
+
++ /* regardless of what happened, we're now out of D3 */
++ mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
++
+ return 1;
+ }
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+index 3a4585222d6d4..7e5ad943b20cb 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -16,6 +16,7 @@
+ #include <net/ieee80211_radiotap.h>
+ #include <net/tcp.h>
+
++#include "iwl-drv.h"
+ #include "iwl-op-mode.h"
+ #include "iwl-io.h"
+ #include "mvm.h"
+@@ -1116,9 +1117,30 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+ {
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
++ int retry, max_retry = 0;
+
+ mutex_lock(&mvm->mutex);
+- ret = __iwl_mvm_mac_start(mvm);
++
++ /* we are starting the mac not in error flow, and restart is enabled */
++ if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) &&
++ iwlwifi_mod_params.fw_restart) {
++ max_retry = IWL_MAX_INIT_RETRY;
++ /*
++ * This will prevent mac80211 recovery flows to trigger during
++ * init failures
++ */
++ set_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
++ }
++
++ for (retry = 0; retry <= max_retry; retry++) {
++ ret = __iwl_mvm_mac_start(mvm);
++ if (!ret)
++ break;
++
++ IWL_ERR(mvm, "mac start retry %d\n", retry);
++ }
++ clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
++
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+index f877d86b038e3..46af8dd2dc930 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+@@ -1121,6 +1121,8 @@ struct iwl_mvm {
+ * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running
+ * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA
+ * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it)
++ * @IWL_MVM_STATUS_STARTING: starting mac,
++ * used to disable restart flow while in STARTING state
+ */
+ enum iwl_mvm_status {
+ IWL_MVM_STATUS_HW_RFKILL,
+@@ -1132,6 +1134,7 @@ enum iwl_mvm_status {
+ IWL_MVM_STATUS_FIRMWARE_RUNNING,
+ IWL_MVM_STATUS_NEED_FLUSH_P2P,
+ IWL_MVM_STATUS_IN_D3,
++ IWL_MVM_STATUS_STARTING,
+ };
+
+ /* Keep track of completed init configuration */
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+index 77ea2d0a30916..49c32a8132a0f 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+@@ -687,6 +687,7 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm)
+ int ret;
+
+ rtnl_lock();
++ wiphy_lock(mvm->hw->wiphy);
+ mutex_lock(&mvm->mutex);
+
+ ret = iwl_run_init_mvm_ucode(mvm);
+@@ -702,6 +703,7 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm)
+ iwl_mvm_stop_device(mvm);
+
+ mutex_unlock(&mvm->mutex);
++ wiphy_unlock(mvm->hw->wiphy);
+ rtnl_unlock();
+
+ if (ret < 0)
+@@ -1424,6 +1426,9 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
+ */
+ if (!mvm->fw_restart && fw_error) {
+ iwl_fw_error_collect(&mvm->fwrt, false);
++ } else if (test_bit(IWL_MVM_STATUS_STARTING,
++ &mvm->status)) {
++ IWL_ERR(mvm, "Starting mac, retry will be triggered anyway\n");
+ } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ struct iwl_mvm_reprobe *reprobe;
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+index 0a13c2bda2eed..06fbd9ab37dfe 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+@@ -268,17 +268,18 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
+ int rate_idx = -1;
+ u8 rate_plcp;
+ u32 rate_flags = 0;
+- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ /* info->control is only relevant for non HW rate control */
+ if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) {
++ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
++
+ /* HT rate doesn't make sense for a non data frame */
+ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS &&
+ !ieee80211_is_data(fc),
+ "Got a HT rate (flags:0x%x/mcs:%d/fc:0x%x/state:%d) for a non data frame\n",
+ info->control.rates[0].flags,
+ info->control.rates[0].idx,
+- le16_to_cpu(fc), mvmsta->sta_state);
++ le16_to_cpu(fc), sta ? mvmsta->sta_state : -1);
+
+ rate_idx = info->control.rates[0].idx;
+ }
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+index 4a3d2971a98b7..ec8a223f90e85 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+@@ -405,6 +405,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,
+
+ lockdep_assert_held(&mvm->mutex);
+
++ if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
++ return false;
++
+ if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
+ return false;
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+index e3996ff99bad5..3b974388d834d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+@@ -931,9 +931,9 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
+ IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
+ iwl_qu_b0_hr1_b0, iwl_ax101_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+- IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP,
++ IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP,
+ IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY,
+- IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
++ IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB,
+ iwl_qu_b0_hr_b0, iwl_ax203_name),
+
+ /* Qu C step */
+@@ -945,7 +945,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP,
+ IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY,
+- IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
++ IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB,
+ iwl_qu_c0_hr_b0, iwl_ax203_name),
+
+ /* QuZ */
+diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
+index 20436a289d5cd..5d6dc1dd050d4 100644
+--- a/drivers/net/wireless/marvell/libertas/if_usb.c
++++ b/drivers/net/wireless/marvell/libertas/if_usb.c
+@@ -292,6 +292,7 @@ err_add_card:
+ if_usb_reset_device(cardp);
+ dealloc:
+ if_usb_free(cardp);
++ kfree(cardp);
+
+ error:
+ return r;
+@@ -316,6 +317,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
+
+ /* Unlink and free urb */
+ if_usb_free(cardp);
++ kfree(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+index fe0a69e804d8c..75b5319d033f3 100644
+--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
++++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+@@ -230,6 +230,7 @@ static int if_usb_probe(struct usb_interface *intf,
+
+ dealloc:
+ if_usb_free(cardp);
++ kfree(cardp);
+ error:
+ lbtf_deb_leave(LBTF_DEB_MAIN);
+ return -ENOMEM;
+@@ -254,6 +255,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
+
+ /* Unlink and free urb */
+ if_usb_free(cardp);
++ kfree(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
+index 6696bce561786..cf08a4af84d6d 100644
+--- a/drivers/net/wireless/marvell/mwifiex/11n.c
++++ b/drivers/net/wireless/marvell/mwifiex/11n.c
+@@ -657,14 +657,15 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
+ uint16_t del_ba_param_set;
+
+ memset(&delba, 0, sizeof(delba));
+- delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
+
+- del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
++ del_ba_param_set = tid << DELBA_TID_POS;
++
+ if (initiator)
+ del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+ else
+ del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+
++ delba.del_ba_param_set = cpu_to_le16(del_ba_param_set);
+ memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
+
+ /* We don't wait for the response of this command */
+diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+index 0961f4a5e415c..97f0f39364d67 100644
+--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+@@ -908,16 +908,20 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+- priv->bss_role = MWIFIEX_BSS_ROLE_STA;
++ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
++ priv->bss_type = MWIFIEX_BSS_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+- priv->bss_role = MWIFIEX_BSS_ROLE_STA;
++ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
++ priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+- priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
++ priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
++ priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
+ break;
+ case NL80211_IFTYPE_AP:
+ priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
++ priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
+ break;
+ default:
+ mwifiex_dbg(adapter, ERROR,
+@@ -1229,29 +1233,15 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
++ if (mwifiex_cfg80211_deinit_p2p(priv))
++ return -EFAULT;
++
+ switch (type) {
+- case NL80211_IFTYPE_STATION:
+- if (mwifiex_cfg80211_deinit_p2p(priv))
+- return -EFAULT;
+- priv->adapter->curr_iface_comb.p2p_intf--;
+- priv->adapter->curr_iface_comb.sta_intf++;
+- dev->ieee80211_ptr->iftype = type;
+- if (mwifiex_deinit_priv_params(priv))
+- return -1;
+- if (mwifiex_init_new_priv_params(priv, dev, type))
+- return -1;
+- if (mwifiex_sta_init_cmd(priv, false, false))
+- return -1;
+- break;
+ case NL80211_IFTYPE_ADHOC:
+- if (mwifiex_cfg80211_deinit_p2p(priv))
+- return -EFAULT;
++ case NL80211_IFTYPE_STATION:
+ return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
+ type, params);
+- break;
+ case NL80211_IFTYPE_AP:
+- if (mwifiex_cfg80211_deinit_p2p(priv))
+- return -EFAULT;
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ params);
+ case NL80211_IFTYPE_UNSPECIFIED:
+diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
+index c6ccce426b496..c3f5583ea70df 100644
+--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
+@@ -17,6 +17,7 @@
+ * this warranty disclaimer.
+ */
+
++#include <linux/iopoll.h>
+ #include <linux/firmware.h>
+
+ #include "decl.h"
+@@ -647,11 +648,15 @@ static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
+ "max count reached while accessing sleep cookie\n");
+ }
+
++#define N_WAKEUP_TRIES_SHORT_INTERVAL 15
++#define N_WAKEUP_TRIES_LONG_INTERVAL 35
++
+ /* This function wakes up the card by reading fw_status register. */
+ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+ {
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
++ int retval;
+
+ mwifiex_dbg(adapter, EVENT,
+ "event: Wakeup device...\n");
+@@ -659,11 +664,24 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+ if (reg->sleep_cookie)
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+
+- /* Accessing fw_status register will wakeup device */
+- if (mwifiex_write_reg(adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
+- mwifiex_dbg(adapter, ERROR,
+- "Writing fw_status register failed\n");
+- return -1;
++ /* The 88W8897 PCIe+USB firmware (latest version 15.68.19.p21) sometimes
++ * appears to ignore or miss our wakeup request, so we continue trying
++ * until we receive an interrupt from the card.
++ */
++ if (read_poll_timeout(mwifiex_write_reg, retval,
++ READ_ONCE(adapter->int_status) != 0,
++ 500, 500 * N_WAKEUP_TRIES_SHORT_INTERVAL,
++ false,
++ adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
++ if (read_poll_timeout(mwifiex_write_reg, retval,
++ READ_ONCE(adapter->int_status) != 0,
++ 10000, 10000 * N_WAKEUP_TRIES_LONG_INTERVAL,
++ false,
++ adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
++ mwifiex_dbg(adapter, ERROR,
++ "Firmware didn't wake up\n");
++ return -EIO;
++ }
+ }
+
+ if (reg->sleep_cookie) {
+@@ -1490,6 +1508,14 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+ ret = -1;
+ goto done_unmap;
+ }
++
++ /* The firmware (latest version 15.68.19.p21) of the 88W8897 PCIe+USB card
++ * seems to crash randomly after setting the TX ring write pointer when
++ * ASPM powersaving is enabled. A workaround seems to be keeping the bus
++ * busy by reading a random register afterwards.
++ */
++ mwifiex_read_reg(adapter, PCI_VENDOR_ID, &rx_val);
++
+ if ((mwifiex_pcie_txbd_not_full(card)) &&
+ tx_param->next_pkt_len) {
+ /* have more packets and TxBD still can hold more */
+diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
+index 426e39d4ccf0f..9736aa0ab7fd4 100644
+--- a/drivers/net/wireless/marvell/mwifiex/usb.c
++++ b/drivers/net/wireless/marvell/mwifiex/usb.c
+@@ -505,6 +505,22 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
+ }
+ }
+
++ switch (card->usb_boot_state) {
++ case USB8XXX_FW_DNLD:
++ /* Reject broken descriptors. */
++ if (!card->rx_cmd_ep || !card->tx_cmd_ep)
++ return -ENODEV;
++ if (card->bulk_out_maxpktsize == 0)
++ return -ENODEV;
++ break;
++ case USB8XXX_FW_READY:
++ /* Assume the driver can handle missing endpoints for now. */
++ break;
++ default:
++ WARN_ON(1);
++ return -ENODEV;
++ }
++
+ usb_set_intfdata(intf, card);
+
+ ret = mwifiex_add_card(card, &card->fw_done, &usb_ops,
+diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c
+index 3bf6571f41490..529e325498cdb 100644
+--- a/drivers/net/wireless/marvell/mwl8k.c
++++ b/drivers/net/wireless/marvell/mwl8k.c
+@@ -5800,8 +5800,8 @@ static void mwl8k_fw_state_machine(const struct firmware *fw, void *context)
+ fail:
+ priv->fw_state = FW_STATE_ERROR;
+ complete(&priv->firmware_loading_complete);
+- device_release_driver(&priv->pdev->dev);
+ mwl8k_release_firmware(priv);
++ device_release_driver(&priv->pdev->dev);
+ }
+
+ #define MAX_RESTART_ATTEMPTS 1
+diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
+index fa48cc3a7a8f7..ad97308c78534 100644
+--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
+@@ -116,8 +116,11 @@ static int mt76_read_rate_txpower(struct seq_file *s, void *data)
+ return 0;
+ }
+
+-struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
++struct dentry *
++mt76_register_debugfs_fops(struct mt76_dev *dev,
++ const struct file_operations *ops)
+ {
++ const struct file_operations *fops = ops ? ops : &fops_regval;
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("mt76", dev->hw->wiphy->debugfsdir);
+@@ -126,8 +129,7 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
+
+ debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin);
+ debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
+- debugfs_create_file_unsafe("regval", 0600, dir, dev,
+- &fops_regval);
++ debugfs_create_file_unsafe("regval", 0600, dir, dev, fops);
+ debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev,
+ &fops_napi_threaded);
+ debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
+@@ -140,4 +142,4 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
+
+ return dir;
+ }
+-EXPORT_SYMBOL_GPL(mt76_register_debugfs);
++EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
+index 25c5ceef52577..4d01fd85283df 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76.h
+@@ -869,7 +869,13 @@ struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
+ int mt76_register_phy(struct mt76_phy *phy, bool vht,
+ struct ieee80211_rate *rates, int n_rates);
+
+-struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
++struct dentry *mt76_register_debugfs_fops(struct mt76_dev *dev,
++ const struct file_operations *ops);
++static inline struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
++{
++ return mt76_register_debugfs_fops(dev, NULL);
++}
++
+ int mt76_queues_read(struct seq_file *s, void *data);
+ void mt76_seq_puts_array(struct seq_file *file, const char *str,
+ s8 *val, int len);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+index cb4659771fd97..bda22ca0bd714 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+@@ -2,6 +2,33 @@
+
+ #include "mt7615.h"
+
++static int
++mt7615_reg_set(void *data, u64 val)
++{
++ struct mt7615_dev *dev = data;
++
++ mt7615_mutex_acquire(dev);
++ mt76_wr(dev, dev->mt76.debugfs_reg, val);
++ mt7615_mutex_release(dev);
++
++ return 0;
++}
++
++static int
++mt7615_reg_get(void *data, u64 *val)
++{
++ struct mt7615_dev *dev = data;
++
++ mt7615_mutex_acquire(dev);
++ *val = mt76_rr(dev, dev->mt76.debugfs_reg);
++ mt7615_mutex_release(dev);
++
++ return 0;
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7615_reg_get, mt7615_reg_set,
++ "0x%08llx\n");
++
+ static int
+ mt7615_radar_pattern_set(void *data, u64 val)
+ {
+@@ -506,7 +533,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
+ {
+ struct dentry *dir;
+
+- dir = mt76_register_debugfs(&dev->mt76);
++ dir = mt76_register_debugfs_fops(&dev->mt76, &fops_regval);
+ if (!dir)
+ return -ENOMEM;
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+index 2f1ac644e018e..47f23ac905a3c 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+@@ -49,12 +49,14 @@ int mt7615_thermal_init(struct mt7615_dev *dev)
+ {
+ struct wiphy *wiphy = mt76_hw(dev)->wiphy;
+ struct device *hwmon;
++ const char *name;
+
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+- hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
+- wiphy_name(wiphy), dev,
++ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7615_%s",
++ wiphy_name(wiphy));
++ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, dev,
+ mt7615_hwmon_groups);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+index ff3f85e4087c9..5455231f51881 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+@@ -755,12 +755,15 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+ txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
+
+- txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
+- FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
+- FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
+- if (!is_mmio)
+- txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
+- FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
++ val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
++ FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
++ FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
++ txwi[7] = cpu_to_le32(val);
++ if (!is_mmio) {
++ val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
++ FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
++ txwi[8] = cpu_to_le32(val);
++ }
+
+ return 0;
+ }
+@@ -1494,32 +1497,41 @@ out:
+ }
+
+ static void
+-mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
++mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi)
+ {
+ struct mt76_dev *mdev = &dev->mt76;
+- struct mt76_txwi_cache *txwi;
+ __le32 *txwi_data;
+ u32 val;
+ u8 wcid;
+
+- trace_mac_tx_free(dev, token);
+- txwi = mt76_token_put(mdev, token);
+- if (!txwi)
+- return;
++ mt7615_txp_skb_unmap(mdev, txwi);
++ if (!txwi->skb)
++ goto out;
+
+ txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
+ val = le32_to_cpu(txwi_data[1]);
+ wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
++ mt76_tx_complete_skb(mdev, wcid, txwi->skb);
+
+- mt7615_txp_skb_unmap(mdev, txwi);
+- if (txwi->skb) {
+- mt76_tx_complete_skb(mdev, wcid, txwi->skb);
+- txwi->skb = NULL;
+- }
+-
++out:
++ txwi->skb = NULL;
+ mt76_put_txwi(mdev, txwi);
+ }
+
++static void
++mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
++{
++ struct mt76_dev *mdev = &dev->mt76;
++ struct mt76_txwi_cache *txwi;
++
++ trace_mac_tx_free(dev, token);
++ txwi = mt76_token_put(mdev, token);
++ if (!txwi)
++ return;
++
++ mt7615_txwi_free(dev, txwi);
++}
++
+ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
+ {
+ struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
+@@ -2026,16 +2038,8 @@ void mt7615_tx_token_put(struct mt7615_dev *dev)
+ int id;
+
+ spin_lock_bh(&dev->mt76.token_lock);
+- idr_for_each_entry(&dev->mt76.token, txwi, id) {
+- mt7615_txp_skb_unmap(&dev->mt76, txwi);
+- if (txwi->skb) {
+- struct ieee80211_hw *hw;
+-
+- hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
+- ieee80211_free_txskb(hw, txwi->skb);
+- }
+- mt76_put_txwi(&dev->mt76, txwi);
+- }
++ idr_for_each_entry(&dev->mt76.token, txwi, id)
++ mt7615_txwi_free(dev, txwi);
+ spin_unlock_bh(&dev->mt76.token_lock);
+ idr_destroy(&dev->mt76.token);
+ }
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+index dada43d6d879e..51260a669d166 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+@@ -135,8 +135,6 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
+ int i;
+
+ switch (type) {
+- case NL80211_IFTYPE_MESH_POINT:
+- case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ /* prefer hw bssid slot 1-3 */
+ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
+@@ -160,6 +158,8 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
+ return HW_BSSID_0;
+
+ break;
++ case NL80211_IFTYPE_ADHOC:
++ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP:
+ /* ap uses hw bssid 0 and ext bssid */
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+index f8a09692d3e4c..4fed3afad67cc 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+@@ -808,7 +808,8 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
+
+ static int
+ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta, bool enable)
++ struct ieee80211_sta *sta, struct mt7615_phy *phy,
++ bool enable)
+ {
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA;
+@@ -821,6 +822,7 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
++ case NL80211_IFTYPE_MONITOR:
+ break;
+ case NL80211_IFTYPE_STATION:
+ /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
+@@ -840,14 +842,19 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ }
+
+ bss = (struct bss_info_basic *)tlv;
+- memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
+- bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+ bss->network_type = cpu_to_le32(type);
+- bss->dtim_period = vif->bss_conf.dtim_period;
+ bss->bmc_tx_wlan_idx = wlan_idx;
+ bss->wmm_idx = mvif->mt76.wmm_idx;
+ bss->active = enable;
+
++ if (vif->type != NL80211_IFTYPE_MONITOR) {
++ memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
++ bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
++ bss->dtim_period = vif->bss_conf.dtim_period;
++ } else {
++ memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN);
++ }
++
+ return 0;
+ }
+
+@@ -863,6 +870,7 @@ mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac));
+
+ switch (vif->type) {
++ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ if (vif->p2p)
+@@ -929,7 +937,7 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ if (enable)
+ mt7615_mcu_bss_omac_tlv(skb, vif);
+
+- mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable);
++ mt7615_mcu_bss_basic_tlv(skb, vif, sta, phy, enable);
+
+ if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
+ mvif->mt76.omac_idx < REPEATER_BSSID_START)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+index 5c3a81e5f559d..d25b50e769328 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+@@ -689,7 +689,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
+ if (ht_cap->ht_supported)
+ mode |= PHY_TYPE_BIT_HT;
+
+- if (he_cap->has_he)
++ if (he_cap && he_cap->has_he)
+ mode |= PHY_TYPE_BIT_HE;
+ } else if (band == NL80211_BAND_5GHZ) {
+ mode |= PHY_TYPE_BIT_OFDM;
+@@ -700,7 +700,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
+ if (vht_cap->vht_supported)
+ mode |= PHY_TYPE_BIT_VHT;
+
+- if (he_cap->has_he)
++ if (he_cap && he_cap->has_he)
+ mode |= PHY_TYPE_BIT_HE;
+ }
+
+@@ -719,6 +719,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
+ struct sta_rec_state *state;
+ struct sta_rec_phy *phy;
+ struct tlv *tlv;
++ u16 supp_rates;
+
+ /* starec ht */
+ if (sta->ht_cap.ht_supported) {
+@@ -767,7 +768,15 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));
+ ra_info = (struct sta_rec_ra_info *)tlv;
+- ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]);
++
++ supp_rates = sta->supp_rates[band];
++ if (band == NL80211_BAND_2GHZ)
++ supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) |
++ FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf);
++ else
++ supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates);
++
++ ra_info->legacy = cpu_to_le16(supp_rates);
+
+ if (sta->ht_cap.ht_supported)
+ memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask,
+@@ -1929,19 +1938,22 @@ mt76_connac_mcu_key_iter(struct ieee80211_hw *hw,
+ key->cipher != WLAN_CIPHER_SUITE_TKIP)
+ return;
+
+- if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+- gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);
++ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+ cipher = BIT(3);
+- } else {
+- gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);
++ else
+ cipher = BIT(4);
+- }
+
+ /* we are assuming here to have a single pairwise key */
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
++ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
++ gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);
++ else
++ gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);
++
+ gtk_tlv->pairwise_cipher = cpu_to_le32(cipher);
+- gtk_tlv->group_cipher = cpu_to_le32(cipher);
+ gtk_tlv->keyid = key->keyidx;
++ } else {
++ gtk_tlv->group_cipher = cpu_to_le32(cipher);
+ }
+ }
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+index 1c73beb226771..77d4435e4581e 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+@@ -124,6 +124,8 @@ struct sta_rec_state {
+ u8 rsv[1];
+ } __packed;
+
++#define RA_LEGACY_OFDM GENMASK(13, 6)
++#define RA_LEGACY_CCK GENMASK(3, 0)
+ #define HT_MCS_MASK_NUM 10
+ struct sta_rec_ra_info {
+ __le16 tag;
+@@ -844,14 +846,14 @@ struct mt76_connac_gtk_rekey_tlv {
+ * 2: rekey update
+ */
+ u8 keyid;
+- u8 pad[2];
++ u8 option; /* 1: rekey data update without enabling offload */
++ u8 pad[1];
+ __le32 proto; /* WPA-RSN-WAPI-OPSN */
+ __le32 pairwise_cipher;
+ __le32 group_cipher;
+ __le32 key_mgmt; /* NONE-PSK-IEEE802.1X */
+ __le32 mgmt_group_cipher;
+- u8 option; /* 1: rekey data update without enabling offload */
+- u8 reserverd[3];
++ u8 reserverd[4];
+ } __packed;
+
+ #define MT76_CONNAC_WOW_MASK_MAX_LEN 16
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+index c32e6dc687739..07b21b2085823 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+@@ -176,7 +176,7 @@ void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
+ mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
+ }
+
+-static __le16
++static u16
+ mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val)
+ {
+@@ -222,14 +222,14 @@ mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
+ rateval |= MT_RXWI_RATE_SGI;
+
+ *nss_val = nss;
+- return cpu_to_le16(rateval);
++ return rateval;
+ }
+
+ void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate)
+ {
+ s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
+- __le16 rateval;
++ u16 rateval;
+ u32 tx_info;
+ s8 nss;
+
+@@ -342,7 +342,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
+ struct ieee80211_key_conf *key = info->control.hw_key;
+ u32 wcid_tx_info;
+ u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
+- u16 txwi_flags = 0;
++ u16 txwi_flags = 0, rateval;
+ u8 nss;
+ s8 txpwr_adj, max_txpwr_adj;
+ u8 ccmp_pn[8], nstreams = dev->mphy.chainmask & 0xf;
+@@ -380,14 +380,15 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
+
+ if (wcid && (rate->idx < 0 || !rate->count)) {
+ wcid_tx_info = wcid->tx_info;
+- txwi->rate = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
++ rateval = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
+ max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ,
+ wcid_tx_info);
+ nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info);
+ } else {
+- txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss);
++ rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
+ max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
+ }
++ txwi->rate = cpu_to_le16(rateval);
+
+ txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf,
+ max_txpwr_adj);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+index 4798d6344305d..b171027e0cfa8 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+@@ -130,9 +130,12 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
+ struct device *hwmon;
++ const char *name;
+
+- cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy,
+- &mt7915_thermal_ops);
++ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s",
++ wiphy_name(wiphy));
++
++ cdev = thermal_cooling_device_register(name, phy, &mt7915_thermal_ops);
+ if (!IS_ERR(cdev)) {
+ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
+ "cooling_device") < 0)
+@@ -144,8 +147,7 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+- hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
+- wiphy_name(wiphy), phy,
++ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
+ mt7915_hwmon_groups);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+index 2462704094b0a..bbc996f86b5c3 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+@@ -1232,7 +1232,7 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
+ goto out;
+
+ info = IEEE80211_SKB_CB(skb);
+- if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK)))
++ if (!(txs_data[0] & cpu_to_le32(MT_TXS0_ACK_ERROR_MASK)))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ info->status.ampdu_len = 1;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+index eb1885f4bd8eb..fee7741b5d421 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+@@ -272,7 +272,8 @@ enum tx_mcu_port_q_idx {
+ #define MT_TX_RATE_MODE GENMASK(9, 6)
+ #define MT_TX_RATE_SU_EXT_TONE BIT(5)
+ #define MT_TX_RATE_DCM BIT(4)
+-#define MT_TX_RATE_IDX GENMASK(3, 0)
++/* VHT/HE only use bits 0-3 */
++#define MT_TX_RATE_IDX GENMASK(5, 0)
+
+ #define MT_TXP_MAX_BUF_NUM 6
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+index 43960770a9af2..7440f2b443eca 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+@@ -176,7 +176,7 @@ mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+ if (ht_cap->ht_supported)
+ mode |= PHY_MODE_GN;
+
+- if (he_cap->has_he)
++ if (he_cap && he_cap->has_he)
+ mode |= PHY_MODE_AX_24G;
+ } else if (band == NL80211_BAND_5GHZ) {
+ mode |= PHY_MODE_A;
+@@ -187,7 +187,7 @@ mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+ if (vht_cap->vht_supported)
+ mode |= PHY_MODE_AC;
+
+- if (he_cap->has_he)
++ if (he_cap && he_cap->has_he)
+ mode |= PHY_MODE_AX_5G;
+ }
+
+@@ -721,7 +721,7 @@ mt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif,
+ .bss_idx = mvif->idx,
+ .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0,
+ .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0,
+- .muar_idx = msta ? mvif->omac_idx : 0,
++ .muar_idx = msta && msta->wcid.sta ? mvif->omac_idx : 0xe,
+ .is_tlv_append = 1,
+ };
+ struct sk_buff *skb;
+@@ -757,7 +757,7 @@ mt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta,
+ }
+
+ if (sta_hdr)
+- sta_hdr->len = cpu_to_le16(sizeof(hdr));
++ le16_add_cpu(&sta_hdr->len, sizeof(hdr));
+
+ return skb_put_data(nskb, &hdr, sizeof(hdr));
+ }
+@@ -925,7 +925,7 @@ static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
+
+ elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
+
+- if (!elem || elem->datalen < 10 ||
++ if (!elem || elem->datalen <= 10 ||
+ !(elem->data[10] &
+ WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
+ data->tolerated = false;
+@@ -1201,7 +1201,7 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb,
+ u8 cipher;
+
+ cipher = mt7915_mcu_get_cipher(key->cipher);
+- if (cipher == MT_CIPHER_NONE)
++ if (cipher == MCU_CIPHER_NONE)
+ return -EOPNOTSUPP;
+
+ sec_key = &sec->key[0];
+@@ -2790,7 +2790,7 @@ out:
+ default:
+ ret = -EAGAIN;
+ dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
+- goto out;
++ break;
+ }
+ release_firmware(fw);
+
+@@ -3391,20 +3391,20 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
+
+ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
+ {
+-#define TOTAL_PAGE_MASK GENMASK(7, 5)
++#define MAX_PAGE_IDX_MASK GENMASK(7, 5)
+ #define PAGE_IDX_MASK GENMASK(4, 2)
+ #define PER_PAGE_SIZE 0x400
+ struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
+- u8 total = MT7915_EEPROM_SIZE / PER_PAGE_SIZE;
++ u8 total = DIV_ROUND_UP(MT7915_EEPROM_SIZE, PER_PAGE_SIZE);
+ u8 *eep = (u8 *)dev->mt76.eeprom.data;
+ int eep_len;
+ int i;
+
+- for (i = 0; i <= total; i++, eep += eep_len) {
++ for (i = 0; i < total; i++, eep += eep_len) {
+ struct sk_buff *skb;
+ int ret;
+
+- if (i == total)
++ if (i == total - 1 && !!(MT7915_EEPROM_SIZE % PER_PAGE_SIZE))
+ eep_len = MT7915_EEPROM_SIZE % PER_PAGE_SIZE;
+ else
+ eep_len = PER_PAGE_SIZE;
+@@ -3414,7 +3414,7 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
+ if (!skb)
+ return -ENOMEM;
+
+- req.format = FIELD_PREP(TOTAL_PAGE_MASK, total) |
++ req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
+ FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
+ req.len = cpu_to_le16(eep_len);
+
+@@ -3481,7 +3481,7 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
+ u8 idx;
+ u8 rsv[4];
+ __le32 len;
+- } req;
++ } req = {};
+ struct sk_buff *skb;
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+index 77468bdae460b..30f3b3085c786 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+@@ -4,6 +4,32 @@
+ #include "mt7921.h"
+ #include "eeprom.h"
+
++static int
++mt7921_reg_set(void *data, u64 val)
++{
++ struct mt7921_dev *dev = data;
++
++ mt7921_mutex_acquire(dev);
++ mt76_wr(dev, dev->mt76.debugfs_reg, val);
++ mt7921_mutex_release(dev);
++
++ return 0;
++}
++
++static int
++mt7921_reg_get(void *data, u64 *val)
++{
++ struct mt7921_dev *dev = data;
++
++ mt7921_mutex_acquire(dev);
++ *val = mt76_rr(dev, dev->mt76.debugfs_reg);
++ mt7921_mutex_release(dev);
++
++ return 0;
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7921_reg_get, mt7921_reg_set,
++ "0x%08llx\n");
+ static int
+ mt7921_fw_debug_set(void *data, u64 val)
+ {
+@@ -69,6 +95,8 @@ mt7921_tx_stats_show(struct seq_file *file, void *data)
+ struct mt7921_dev *dev = file->private;
+ int stat[8], i, n;
+
++ mt7921_mutex_acquire(dev);
++
+ mt7921_ampdu_stat_read_phy(&dev->phy, file);
+
+ /* Tx amsdu info */
+@@ -78,6 +106,8 @@ mt7921_tx_stats_show(struct seq_file *file, void *data)
+ n += stat[i];
+ }
+
++ mt7921_mutex_release(dev);
++
+ for (i = 0; i < ARRAY_SIZE(stat); i++) {
+ seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
+ i + 1, stat[i]);
+@@ -98,6 +128,8 @@ mt7921_queues_acq(struct seq_file *s, void *data)
+ struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ int i;
+
++ mt7921_mutex_acquire(dev);
++
+ for (i = 0; i < 16; i++) {
+ int j, acs = i / 4, index = i % 4;
+ u32 ctrl, val, qlen = 0;
+@@ -117,6 +149,8 @@ mt7921_queues_acq(struct seq_file *s, void *data)
+ seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
+ }
+
++ mt7921_mutex_release(dev);
++
+ return 0;
+ }
+
+@@ -373,7 +407,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
+ {
+ struct dentry *dir;
+
+- dir = mt76_register_debugfs(&dev->mt76);
++ dir = mt76_register_debugfs_fops(&dev->mt76, &fops_regval);
+ if (!dir)
+ return -ENOMEM;
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+index a9ce10b988273..78a00028137bd 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+@@ -106,6 +106,10 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
+ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
+ mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
+
++ /* enable MIB tx-rx time reporting */
++ mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN);
++ mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN);
++
+ mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
+ /* disable rx rate report by default due to hw issues */
+ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
+@@ -247,8 +251,17 @@ int mt7921_register_device(struct mt7921_dev *dev)
+
+ void mt7921_unregister_device(struct mt7921_dev *dev)
+ {
++ int i;
++ struct mt76_connac_pm *pm = &dev->pm;
++
+ mt76_unregister_device(&dev->mt76);
++ mt76_for_each_q_rx(&dev->mt76, i)
++ napi_disable(&dev->mt76.napi[i]);
++ cancel_delayed_work_sync(&pm->ps_work);
++ cancel_work_sync(&pm->wake_work);
++
+ mt7921_tx_token_put(dev);
++ mt7921_mcu_drv_pmctrl(dev);
+ mt7921_dma_cleanup(dev);
+ mt7921_mcu_exit(dev);
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+index 7fe2e3a50428f..8a16f3f4d5253 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+@@ -180,12 +180,56 @@ mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
+ }
+
++static void
++mt7921_mac_decode_he_mu_radiotap(struct sk_buff *skb,
++ struct mt76_rx_status *status,
++ __le32 *rxv)
++{
++ static const struct ieee80211_radiotap_he_mu mu_known = {
++ .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
++ HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
++ HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
++ HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN) |
++ HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN),
++ .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN) |
++ HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN),
++ };
++ struct ieee80211_radiotap_he_mu *he_mu = NULL;
++
++ he_mu = skb_push(skb, sizeof(mu_known));
++ memcpy(he_mu, &mu_known, sizeof(mu_known));
++
++#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
++
++ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
++ if (status->he_dcm)
++ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
++
++ he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
++ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
++ le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
++
++ he_mu->ru_ch1[0] = FIELD_GET(MT_CRXV_HE_RU0, cpu_to_le32(rxv[3]));
++
++ if (status->bw >= RATE_INFO_BW_40) {
++ he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
++ he_mu->ru_ch2[0] =
++ FIELD_GET(MT_CRXV_HE_RU1, cpu_to_le32(rxv[3]));
++ }
++
++ if (status->bw >= RATE_INFO_BW_80) {
++ he_mu->ru_ch1[1] =
++ FIELD_GET(MT_CRXV_HE_RU2, cpu_to_le32(rxv[3]));
++ he_mu->ru_ch2[1] =
++ FIELD_GET(MT_CRXV_HE_RU3, cpu_to_le32(rxv[3]));
++ }
++}
++
+ static void
+ mt7921_mac_decode_he_radiotap(struct sk_buff *skb,
+ struct mt76_rx_status *status,
+ __le32 *rxv, u32 phy)
+ {
+- /* TODO: struct ieee80211_radiotap_he_mu */
+ static const struct ieee80211_radiotap_he known = {
+ .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
+@@ -193,6 +237,7 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb,
+ HE_BITS(DATA1_CODING_KNOWN) |
+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+ HE_BITS(DATA1_DOPPLER_KNOWN) |
++ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
+ .data2 = HE_BITS(DATA2_GI_KNOWN) |
+ HE_BITS(DATA2_TXBF_KNOWN) |
+@@ -207,9 +252,12 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb,
+
+ he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
+ HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
++ he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
+ he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
+ le16_encode_bits(ltf_size,
+ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
++ if (cpu_to_le32(rxv[0]) & MT_PRXV_TXBF)
++ he->data5 |= HE_BITS(DATA5_TXBF);
+ he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
+ HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
+
+@@ -217,8 +265,7 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb,
+ case MT_PHY_TYPE_HE_SU:
+ he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+ HE_BITS(DATA1_UL_DL_KNOWN) |
+- HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+- HE_BITS(DATA1_SPTL_REUSE_KNOWN);
++ HE_BITS(DATA1_BEAM_CHANGE_KNOWN);
+
+ he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
+ HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
+@@ -232,17 +279,15 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb,
+ break;
+ case MT_PHY_TYPE_HE_MU:
+ he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+- HE_BITS(DATA1_UL_DL_KNOWN) |
+- HE_BITS(DATA1_SPTL_REUSE_KNOWN);
++ HE_BITS(DATA1_UL_DL_KNOWN);
+
+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
+- he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
++ he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
+
+ mt7921_mac_decode_he_radiotap_ru(status, he, rxv);
+ break;
+ case MT_PHY_TYPE_HE_TB:
+ he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+- HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+@@ -606,9 +651,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
+
+ mt7921_mac_assoc_rssi(dev, skb);
+
+- if (rxv && status->flag & RX_FLAG_RADIOTAP_HE)
++ if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) {
+ mt7921_mac_decode_he_radiotap(skb, status, rxv, mode);
+
++ if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
++ mt7921_mac_decode_he_mu_radiotap(skb, status, rxv);
++ }
++
+ if (!status->wcid || !ieee80211_is_data_qos(fc))
+ return 0;
+
+@@ -735,8 +784,9 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
+ static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi)
+ {
+ struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid);
+- u32 pid, frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]);
++ u32 pid, frame_type;
+
++ frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, le32_to_cpu(txwi[2]));
+ if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2)))
+ return;
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
+index 3af67fac213df..f0194c8780372 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
+@@ -116,6 +116,7 @@ enum rx_pkt_type {
+ #define MT_PRXV_TX_DCM BIT(4)
+ #define MT_PRXV_TX_ER_SU_106T BIT(5)
+ #define MT_PRXV_NSTS GENMASK(9, 7)
++#define MT_PRXV_TXBF BIT(10)
+ #define MT_PRXV_HT_AD_CODE BIT(11)
+ #define MT_PRXV_FRAME_MODE GENMASK(14, 12)
+ #define MT_PRXV_SGI GENMASK(16, 15)
+@@ -138,8 +139,15 @@ enum rx_pkt_type {
+ #define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17)
+ #define MT_CRXV_HE_LDPC_EXT_SYM BIT(20)
+ #define MT_CRXV_HE_PE_DISAMBIG BIT(23)
++#define MT_CRXV_HE_NUM_USER GENMASK(30, 24)
+ #define MT_CRXV_HE_UPLINK BIT(31)
+
++#define MT_CRXV_HE_RU0 GENMASK(7, 0)
++#define MT_CRXV_HE_RU1 GENMASK(15, 8)
++#define MT_CRXV_HE_RU2 GENMASK(23, 16)
++#define MT_CRXV_HE_RU3 GENMASK(31, 24)
++#define MT_CRXV_HE_MU_AID GENMASK(30, 20)
++
+ #define MT_CRXV_HE_SR_MASK GENMASK(11, 8)
+ #define MT_CRXV_HE_SR1_MASK GENMASK(16, 12)
+ #define MT_CRXV_HE_SR2_MASK GENMASK(20, 17)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+index 9fbaacc67cfad..506a1909ce6d5 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+@@ -157,6 +157,7 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
+ {
+ struct mt7921_mcu_rxd *rxd;
++ int mcu_cmd = cmd & MCU_CMD_MASK;
+ int ret = 0;
+
+ if (!skb) {
+@@ -194,6 +195,9 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ skb_pull(skb, sizeof(*rxd));
+ event = (struct mt7921_mcu_uni_event *)skb->data;
+ ret = le32_to_cpu(event->status);
++ /* skip invalid event */
++ if (mcu_cmd != event->cid)
++ ret = -EAGAIN;
+ break;
+ }
+ case MCU_CMD_REG_READ: {
+@@ -316,11 +320,13 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy,
+ struct rate_info *rate, u16 r)
+ {
+ struct ieee80211_supported_band *sband;
+- u16 flags = 0;
++ u16 flags = 0, rate_idx;
+ u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r);
+ u8 gi = 0;
+ u8 bw = 0;
++ bool cck = false;
+
++ memset(rate, 0, sizeof(*rate));
+ rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r);
+ rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1;
+
+@@ -345,13 +351,18 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy,
+
+ switch (txmode) {
+ case MT_PHY_TYPE_CCK:
++ cck = true;
++ fallthrough;
+ case MT_PHY_TYPE_OFDM:
+ if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &mphy->sband_5g.sband;
+ else
+ sband = &mphy->sband_2g.sband;
+
+- rate->legacy = sband->bitrates[rate->mcs].bitrate;
++ rate_idx = FIELD_GET(MT_TX_RATE_IDX, r);
++ rate_idx = mt76_get_rate(mphy->dev, sband, rate_idx,
++ cck);
++ rate->legacy = sband->bitrates[rate_idx].bitrate;
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+@@ -532,7 +543,8 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
+ peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
+ peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
+ mt7921_mcu_tx_rate_parse(mphy->mt76, &peer,
+- &msta->stats.tx_rate, event->tx_rate);
++ &msta->stats.tx_rate,
++ le16_to_cpu(event->tx_rate));
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ break;
+@@ -619,7 +631,7 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb,
+ u8 cipher;
+
+ cipher = mt7921_mcu_get_cipher(key->cipher);
+- if (cipher == MT_CIPHER_NONE)
++ if (cipher == MCU_CIPHER_NONE)
+ return -EOPNOTSUPP;
+
+ sec_key = &sec->key[0];
+@@ -815,7 +827,7 @@ out:
+ default:
+ ret = -EAGAIN;
+ dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
+- goto out;
++ break;
+ }
+ release_firmware(fw);
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
+index de3c091f67368..42e7271848956 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
+@@ -296,11 +296,11 @@ struct mt7921_txpwr_event {
+ struct mt7921_mcu_tx_done_event {
+ u8 pid;
+ u8 status;
+- u16 seq;
++ __le16 seq;
+
+ u8 wlan_idx;
+ u8 tx_cnt;
+- u16 tx_rate;
++ __le16 tx_rate;
+
+ u8 flag;
+ u8 tid;
+@@ -312,9 +312,9 @@ struct mt7921_mcu_tx_done_event {
+ u8 reason;
+ u8 rsv0[1];
+
+- u32 delay;
+- u32 timestamp;
+- u32 applied_flag;
++ __le32 delay;
++ __le32 timestamp;
++ __le32 applied_flag;
+
+ u8 txs[28];
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+index b6944c867a573..26fb118237626 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+@@ -96,6 +96,10 @@
+ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
+ #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
+
++#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
++#define MT_MIB_TXDUR_EN BIT(8)
++#define MT_MIB_RXDUR_EN BIT(9)
++
+ #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x698)
+ #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(31, 16)
+
+@@ -108,9 +112,9 @@
+ #define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090)
+ #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0)
+
+-#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
++#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x054)
+ #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
+-#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
++#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x058)
+ #define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
+
+ #define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
+diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+index 96973ec7bd9ac..87c14969c75fa 100644
+--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
++++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+@@ -129,8 +129,7 @@ static void cfg_scan_result(enum scan_event scan_event,
+ info->frame_len,
+ (s32)info->rssi * 100,
+ GFP_KERNEL);
+- if (!bss)
+- cfg80211_put_bss(wiphy, bss);
++ cfg80211_put_bss(wiphy, bss);
+ } else if (scan_event == SCAN_EVENT_DONE) {
+ mutex_lock(&priv->scan_req_lock);
+
+diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+index e4473a5512415..74c3d8cb31002 100644
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+@@ -25,6 +25,9 @@ static bool rt2x00usb_check_usb_error(struct rt2x00_dev *rt2x00dev, int status)
+ if (status == -ENODEV || status == -ENOENT)
+ return true;
+
++ if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
++ return false;
++
+ if (status == -EPROTO || status == -ETIMEDOUT)
+ rt2x00dev->num_proto_errs++;
+ else
+diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
+index 585784258c665..4efab907a3ac6 100644
+--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
++++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
+@@ -28,7 +28,7 @@ u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits8, sizeof(val), 500);
+
+ val = priv->io_dmabuf->bits8;
+ mutex_unlock(&priv->io_mutex);
+@@ -45,7 +45,7 @@ u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits16, sizeof(val), 500);
+
+ val = priv->io_dmabuf->bits16;
+ mutex_unlock(&priv->io_mutex);
+@@ -62,7 +62,7 @@ u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits32, sizeof(val), 500);
+
+ val = priv->io_dmabuf->bits32;
+ mutex_unlock(&priv->io_mutex);
+@@ -79,7 +79,7 @@ void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits8, sizeof(val), 500);
+
+ mutex_unlock(&priv->io_mutex);
+ }
+@@ -93,7 +93,7 @@ void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits16, sizeof(val), 500);
+
+ mutex_unlock(&priv->io_mutex);
+ }
+@@ -107,7 +107,7 @@ void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, idx & 0x03,
+- &priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
++ &priv->io_dmabuf->bits32, sizeof(val), 500);
+
+ mutex_unlock(&priv->io_mutex);
+ }
+@@ -183,7 +183,7 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ addr, 0x8225, &priv->io_dmabuf->bits16, sizeof(data),
+- HZ / 2);
++ 500);
+
+ mutex_unlock(&priv->io_mutex);
+
+diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
+index e6399519584bd..a384fc3a4f2b0 100644
+--- a/drivers/net/wireless/realtek/rtw88/fw.c
++++ b/drivers/net/wireless/realtek/rtw88/fw.c
+@@ -1556,12 +1556,10 @@ static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size,
+ u32 i;
+ u16 idx = 0;
+ u16 ctl;
+- u8 rcr;
+
+- rcr = rtw_read8(rtwdev, REG_RCR + 2);
+ ctl = rtw_read16(rtwdev, REG_PKTBUF_DBG_CTRL) & 0xf000;
+ /* disable rx clock gate */
+- rtw_write8(rtwdev, REG_RCR, rcr | BIT(3));
++ rtw_write32_set(rtwdev, REG_RCR, BIT_DISGCLK);
+
+ do {
+ rtw_write16(rtwdev, REG_PKTBUF_DBG_CTRL, start_pg | ctl);
+@@ -1580,7 +1578,8 @@ static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size,
+
+ out:
+ rtw_write16(rtwdev, REG_PKTBUF_DBG_CTRL, ctl);
+- rtw_write8(rtwdev, REG_RCR + 2, rcr);
++ /* restore rx clock gate */
++ rtw_write32_clr(rtwdev, REG_RCR, BIT_DISGCLK);
+ }
+
+ static void rtw_fw_read_fifo(struct rtw_dev *rtwdev, enum rtw_fw_fifo_sel sel,
+diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
+index f5ce75095e904..c0fb1e446245f 100644
+--- a/drivers/net/wireless/realtek/rtw88/reg.h
++++ b/drivers/net/wireless/realtek/rtw88/reg.h
+@@ -406,6 +406,7 @@
+ #define BIT_MFBEN BIT(22)
+ #define BIT_DISCHKPPDLLEN BIT(21)
+ #define BIT_PKTCTL_DLEN BIT(20)
++#define BIT_DISGCLK BIT(19)
+ #define BIT_TIM_PARSER_EN BIT(18)
+ #define BIT_BC_MD_EN BIT(17)
+ #define BIT_UC_MD_EN BIT(16)
+diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
+index a48e616e0fb91..6bfaab48b507d 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_core.c
++++ b/drivers/net/wireless/rsi/rsi_91x_core.c
+@@ -399,6 +399,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
+
+ info = IEEE80211_SKB_CB(skb);
+ tx_params = (struct skb_info *)info->driver_data;
++ /* info->driver_data and info->control part of union so make copy */
++ tx_params->have_key = !!info->control.hw_key;
+ wh = (struct ieee80211_hdr *)&skb->data[0];
+ tx_params->sta_id = 0;
+
+diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
+index f4a26f16f00f4..dca81a4bbdd7f 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
++++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
+@@ -203,7 +203,7 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
+ wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
+
+ if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
+- info->control.hw_key) {
++ tx_params->have_key) {
+ if (rsi_is_cipher_wep(common))
+ ieee80211_size += 4;
+ else
+@@ -214,15 +214,17 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
+ RSI_WIFI_DATA_Q);
+ data_desc->header_len = ieee80211_size;
+
+- if (common->min_rate != RSI_RATE_AUTO) {
++ if (common->rate_config[common->band].fixed_enabled) {
+ /* Send fixed rate */
++ u16 fixed_rate = common->rate_config[common->band].fixed_hw_rate;
++
+ data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
+- data_desc->rate_info = cpu_to_le16(common->min_rate);
++ data_desc->rate_info = cpu_to_le16(fixed_rate);
+
+ if (conf_is_ht40(&common->priv->hw->conf))
+ data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
+
+- if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) {
++ if (common->vif_info[0].sgi && (fixed_rate & 0x100)) {
+ /* Only MCS rates */
+ data_desc->rate_info |=
+ cpu_to_le16(ENABLE_SHORTGI_RATE);
+diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+index b66975f545675..e70c1c7fdf595 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+@@ -510,7 +510,6 @@ static int rsi_mac80211_add_interface(struct ieee80211_hw *hw,
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_P2P_GO)) {
+ rsi_send_rx_filter_frame(common, DISALLOW_BEACONS);
+- common->min_rate = RSI_RATE_AUTO;
+ for (i = 0; i < common->max_stations; i++)
+ common->stations[i].sta = NULL;
+ }
+@@ -1228,20 +1227,32 @@ static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+ {
++ const unsigned int mcs_offset = ARRAY_SIZE(rsi_rates);
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+- enum nl80211_band band = hw->conf.chandef.chan->band;
++ int i;
+
+ mutex_lock(&common->mutex);
+- common->fixedrate_mask[band] = 0;
+
+- if (mask->control[band].legacy == 0xfff) {
+- common->fixedrate_mask[band] =
+- (mask->control[band].ht_mcs[0] << 12);
+- } else {
+- common->fixedrate_mask[band] =
+- mask->control[band].legacy;
++ for (i = 0; i < ARRAY_SIZE(common->rate_config); i++) {
++ struct rsi_rate_config *cfg = &common->rate_config[i];
++ u32 bm;
++
++ bm = mask->control[i].legacy | (mask->control[i].ht_mcs[0] << mcs_offset);
++ if (hweight32(bm) == 1) { /* single rate */
++ int rate_index = ffs(bm) - 1;
++
++ if (rate_index < mcs_offset)
++ cfg->fixed_hw_rate = rsi_rates[rate_index].hw_value;
++ else
++ cfg->fixed_hw_rate = rsi_mcsrates[rate_index - mcs_offset];
++ cfg->fixed_enabled = true;
++ } else {
++ cfg->configured_mask = bm;
++ cfg->fixed_enabled = false;
++ }
+ }
++
+ mutex_unlock(&common->mutex);
+
+ return 0;
+@@ -1378,46 +1389,6 @@ void rsi_indicate_pkt_to_os(struct rsi_common *common,
+ ieee80211_rx_irqsafe(hw, skb);
+ }
+
+-static void rsi_set_min_rate(struct ieee80211_hw *hw,
+- struct ieee80211_sta *sta,
+- struct rsi_common *common)
+-{
+- u8 band = hw->conf.chandef.chan->band;
+- u8 ii;
+- u32 rate_bitmap;
+- bool matched = false;
+-
+- common->bitrate_mask[band] = sta->supp_rates[band];
+-
+- rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]);
+-
+- if (rate_bitmap & 0xfff) {
+- /* Find out the min rate */
+- for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) {
+- if (rate_bitmap & BIT(ii)) {
+- common->min_rate = rsi_rates[ii].hw_value;
+- matched = true;
+- break;
+- }
+- }
+- }
+-
+- common->vif_info[0].is_ht = sta->ht_cap.ht_supported;
+-
+- if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) {
+- for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) {
+- if ((rate_bitmap >> 12) & BIT(ii)) {
+- common->min_rate = rsi_mcsrates[ii];
+- matched = true;
+- break;
+- }
+- }
+- }
+-
+- if (!matched)
+- common->min_rate = 0xffff;
+-}
+-
+ /**
+ * rsi_mac80211_sta_add() - This function notifies driver about a peer getting
+ * connected.
+@@ -1516,9 +1487,9 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw,
+
+ if ((vif->type == NL80211_IFTYPE_STATION) ||
+ (vif->type == NL80211_IFTYPE_P2P_CLIENT)) {
+- rsi_set_min_rate(hw, sta, common);
++ common->bitrate_mask[common->band] = sta->supp_rates[common->band];
++ common->vif_info[0].is_ht = sta->ht_cap.ht_supported;
+ if (sta->ht_cap.ht_supported) {
+- common->vif_info[0].is_ht = true;
+ common->bitrate_mask[NL80211_BAND_2GHZ] =
+ sta->supp_rates[NL80211_BAND_2GHZ];
+ if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ||
+@@ -1592,7 +1563,6 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw,
+ bss->qos = sta->wme;
+ common->bitrate_mask[NL80211_BAND_2GHZ] = 0;
+ common->bitrate_mask[NL80211_BAND_5GHZ] = 0;
+- common->min_rate = 0xffff;
+ common->vif_info[0].is_ht = false;
+ common->vif_info[0].sgi = false;
+ common->vif_info[0].seq_start = 0;
+diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
+index d98483298555c..f1bf71e6c6081 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_main.c
++++ b/drivers/net/wireless/rsi/rsi_91x_main.c
+@@ -211,9 +211,10 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
+ bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
+ if (bt_pkt_type == BT_CARD_READY_IND) {
+ rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
+- if (rsi_bt_ops.attach(common, &g_proto_ops))
+- rsi_dbg(ERR_ZONE,
+- "Failed to attach BT module\n");
++ if (common->fsm_state == FSM_MAC_INIT_DONE)
++ rsi_attach_bt(common);
++ else
++ common->bt_defer_attach = true;
+ } else {
+ if (common->bt_adapter)
+ rsi_bt_ops.recv_pkt(common->bt_adapter,
+@@ -278,6 +279,15 @@ void rsi_set_bt_context(void *priv, void *bt_context)
+ }
+ #endif
+
++void rsi_attach_bt(struct rsi_common *common)
++{
++#ifdef CONFIG_RSI_COEX
++ if (rsi_bt_ops.attach(common, &g_proto_ops))
++ rsi_dbg(ERR_ZONE,
++ "Failed to attach BT module\n");
++#endif
++}
++
+ /**
+ * rsi_91x_init() - This function initializes os interface operations.
+ * @oper_mode: One of DEV_OPMODE_*.
+@@ -359,6 +369,7 @@ struct rsi_hw *rsi_91x_init(u16 oper_mode)
+ if (common->coex_mode > 1) {
+ if (rsi_coex_attach(common)) {
+ rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
++ rsi_kill_thread(&common->tx_thread);
+ goto err;
+ }
+ }
+diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+index 891fd5f0fa765..0848f7a7e76c6 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
++++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+@@ -276,7 +276,7 @@ static void rsi_set_default_parameters(struct rsi_common *common)
+ common->channel_width = BW_20MHZ;
+ common->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+ common->channel = 1;
+- common->min_rate = 0xffff;
++ memset(&common->rate_config, 0, sizeof(common->rate_config));
+ common->fsm_state = FSM_CARD_NOT_READY;
+ common->iface_down = true;
+ common->endpoint = EP_2GHZ_20MHZ;
+@@ -1314,7 +1314,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common,
+ u8 band = hw->conf.chandef.chan->band;
+ u8 num_supported_rates = 0;
+ u8 rate_table_offset, rate_offset = 0;
+- u32 rate_bitmap;
++ u32 rate_bitmap, configured_rates;
+ u16 *selected_rates, min_rate;
+ bool is_ht = false, is_sgi = false;
+ u16 frame_len = sizeof(struct rsi_auto_rate);
+@@ -1364,6 +1364,10 @@ static int rsi_send_auto_rate_request(struct rsi_common *common,
+ is_sgi = true;
+ }
+
++ /* Limit to any rates administratively configured by cfg80211 */
++ configured_rates = common->rate_config[band].configured_mask ?: 0xffffffff;
++ rate_bitmap &= configured_rates;
++
+ if (band == NL80211_BAND_2GHZ) {
+ if ((rate_bitmap == 0) && (is_ht))
+ min_rate = RSI_RATE_MCS0;
+@@ -1389,10 +1393,13 @@ static int rsi_send_auto_rate_request(struct rsi_common *common,
+ num_supported_rates = jj;
+
+ if (is_ht) {
+- for (ii = 0; ii < ARRAY_SIZE(mcs); ii++)
+- selected_rates[jj++] = mcs[ii];
+- num_supported_rates += ARRAY_SIZE(mcs);
+- rate_offset += ARRAY_SIZE(mcs);
++ for (ii = 0; ii < ARRAY_SIZE(mcs); ii++) {
++ if (configured_rates & BIT(ii + ARRAY_SIZE(rsi_rates))) {
++ selected_rates[jj++] = mcs[ii];
++ num_supported_rates++;
++ rate_offset++;
++ }
++ }
+ }
+
+ sort(selected_rates, jj, sizeof(u16), &rsi_compare, NULL);
+@@ -1482,7 +1489,7 @@ void rsi_inform_bss_status(struct rsi_common *common,
+ qos_enable,
+ aid, sta_id,
+ vif);
+- if (common->min_rate == 0xffff)
++ if (!common->rate_config[common->band].fixed_enabled)
+ rsi_send_auto_rate_request(common, sta, sta_id, vif);
+ if (opmode == RSI_OPMODE_STA &&
+ !(assoc_cap & WLAN_CAPABILITY_PRIVACY) &&
+@@ -2071,6 +2078,9 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
+ if (common->reinit_hw) {
+ complete(&common->wlan_init_completion);
+ } else {
++ if (common->bt_defer_attach)
++ rsi_attach_bt(common);
++
+ return rsi_mac80211_attach(common);
+ }
+ }
+diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
+index e0c502bc42707..9f16128e4ffab 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
++++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
+@@ -24,10 +24,7 @@
+ /* Default operating mode is wlan STA + BT */
+ static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+ module_param(dev_oper_mode, ushort, 0444);
+-MODULE_PARM_DESC(dev_oper_mode,
+- "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+- "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+- "6[AP + BT classic], 14[AP + BT classic + BT LE]");
++MODULE_PARM_DESC(dev_oper_mode, DEV_OPMODE_PARAM_DESC);
+
+ /**
+ * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
+diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
+index 416976f098882..6821ea9918956 100644
+--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
+@@ -25,10 +25,7 @@
+ /* Default operating mode is wlan STA + BT */
+ static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+ module_param(dev_oper_mode, ushort, 0444);
+-MODULE_PARM_DESC(dev_oper_mode,
+- "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+- "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+- "6[AP + BT classic], 14[AP + BT classic + BT LE]");
++MODULE_PARM_DESC(dev_oper_mode, DEV_OPMODE_PARAM_DESC);
+
+ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num, gfp_t flags);
+
+@@ -61,7 +58,7 @@ static int rsi_usb_card_write(struct rsi_hw *adapter,
+ (void *)seg,
+ (int)len,
+ &transfer,
+- HZ * 5);
++ USB_CTRL_SET_TIMEOUT);
+
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
+index d044a440fa080..5b07262a97408 100644
+--- a/drivers/net/wireless/rsi/rsi_hal.h
++++ b/drivers/net/wireless/rsi/rsi_hal.h
+@@ -28,6 +28,17 @@
+ #define DEV_OPMODE_AP_BT 6
+ #define DEV_OPMODE_AP_BT_DUAL 14
+
++#define DEV_OPMODE_PARAM_DESC \
++ __stringify(DEV_OPMODE_WIFI_ALONE) "[Wi-Fi alone], " \
++ __stringify(DEV_OPMODE_BT_ALONE) "[BT classic alone], " \
++ __stringify(DEV_OPMODE_BT_LE_ALONE) "[BT LE alone], " \
++ __stringify(DEV_OPMODE_BT_DUAL) "[BT classic + BT LE alone], " \
++ __stringify(DEV_OPMODE_STA_BT) "[Wi-Fi STA + BT classic], " \
++ __stringify(DEV_OPMODE_STA_BT_LE) "[Wi-Fi STA + BT LE], " \
++ __stringify(DEV_OPMODE_STA_BT_DUAL) "[Wi-Fi STA + BT classic + BT LE], " \
++ __stringify(DEV_OPMODE_AP_BT) "[Wi-Fi AP + BT classic], " \
++ __stringify(DEV_OPMODE_AP_BT_DUAL) "[Wi-Fi AP + BT classic + BT LE]"
++
+ #define FLASH_WRITE_CHUNK_SIZE (4 * 1024)
+ #define FLASH_SECTOR_SIZE (4 * 1024)
+
+diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
+index 0f535850a3836..dcf8fb40698b7 100644
+--- a/drivers/net/wireless/rsi/rsi_main.h
++++ b/drivers/net/wireless/rsi/rsi_main.h
+@@ -61,6 +61,7 @@ enum RSI_FSM_STATES {
+ extern u32 rsi_zone_enabled;
+ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
+
++#define RSI_MAX_BANDS 2
+ #define RSI_MAX_VIFS 3
+ #define NUM_EDCA_QUEUES 4
+ #define IEEE80211_ADDR_LEN 6
+@@ -139,6 +140,7 @@ struct skb_info {
+ u8 internal_hdr_size;
+ struct ieee80211_vif *vif;
+ u8 vap_id;
++ bool have_key;
+ };
+
+ enum edca_queue {
+@@ -229,6 +231,12 @@ struct rsi_9116_features {
+ u32 ps_options;
+ };
+
++struct rsi_rate_config {
++ u32 configured_mask; /* configured by mac80211 bits 0-11=legacy 12+ mcs */
++ u16 fixed_hw_rate;
++ bool fixed_enabled;
++};
++
+ struct rsi_common {
+ struct rsi_hw *priv;
+ struct vif_priv vif_info[RSI_MAX_VIFS];
+@@ -254,8 +262,8 @@ struct rsi_common {
+ u8 channel_width;
+
+ u16 rts_threshold;
+- u16 bitrate_mask[2];
+- u32 fixedrate_mask[2];
++ u32 bitrate_mask[RSI_MAX_BANDS];
++ struct rsi_rate_config rate_config[RSI_MAX_BANDS];
+
+ u8 rf_reset;
+ struct transmit_q_stats tx_stats;
+@@ -276,7 +284,6 @@ struct rsi_common {
+ u8 mac_id;
+ u8 radio_id;
+ u16 rate_pwr[20];
+- u16 min_rate;
+
+ /* WMM algo related */
+ u8 selected_qnum;
+@@ -320,6 +327,7 @@ struct rsi_common {
+ struct ieee80211_vif *roc_vif;
+
+ bool eapol4_confirm;
++ bool bt_defer_attach;
+ void *bt_adapter;
+
+ struct cfg80211_scan_request *hwscan;
+@@ -401,5 +409,6 @@ struct rsi_host_intf_ops {
+
+ enum rsi_host_intf rsi_get_host_intf(void *priv);
+ void rsi_set_bt_context(void *priv, void *bt_context);
++void rsi_attach_bt(struct rsi_common *common);
+
+ #endif
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index 4a16d6e33c093..d9dea4829c86e 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -203,6 +203,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */
+ unsigned int rx_queue_max;
+ unsigned int rx_queue_len;
+ unsigned long last_rx_time;
++ unsigned int rx_slots_needed;
+ bool stalled;
+
+ struct xenvif_copy_state rx_copy;
+diff --git a/drivers/net/xen-netback/rx.c b/drivers/net/xen-netback/rx.c
+index accc991d153f7..dbac4c03d21a1 100644
+--- a/drivers/net/xen-netback/rx.c
++++ b/drivers/net/xen-netback/rx.c
+@@ -33,28 +33,36 @@
+ #include <xen/xen.h>
+ #include <xen/events.h>
+
+-static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
++/*
++ * Update the needed ring page slots for the first SKB queued.
++ * Note that any call sequence outside the RX thread calling this function
++ * needs to wake up the RX thread via a call of xenvif_kick_thread()
++ * afterwards in order to avoid a race with putting the thread to sleep.
++ */
++static void xenvif_update_needed_slots(struct xenvif_queue *queue,
++ const struct sk_buff *skb)
+ {
+- RING_IDX prod, cons;
+- struct sk_buff *skb;
+- int needed;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&queue->rx_queue.lock, flags);
++ unsigned int needed = 0;
+
+- skb = skb_peek(&queue->rx_queue);
+- if (!skb) {
+- spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
+- return false;
++ if (skb) {
++ needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE);
++ if (skb_is_gso(skb))
++ needed++;
++ if (skb->sw_hash)
++ needed++;
+ }
+
+- needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE);
+- if (skb_is_gso(skb))
+- needed++;
+- if (skb->sw_hash)
+- needed++;
++ WRITE_ONCE(queue->rx_slots_needed, needed);
++}
+
+- spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
++static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
++{
++ RING_IDX prod, cons;
++ unsigned int needed;
++
++ needed = READ_ONCE(queue->rx_slots_needed);
++ if (!needed)
++ return false;
+
+ do {
+ prod = queue->rx.sring->req_prod;
+@@ -80,13 +88,19 @@ void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
+
+ spin_lock_irqsave(&queue->rx_queue.lock, flags);
+
+- __skb_queue_tail(&queue->rx_queue, skb);
+-
+- queue->rx_queue_len += skb->len;
+- if (queue->rx_queue_len > queue->rx_queue_max) {
++ if (queue->rx_queue_len >= queue->rx_queue_max) {
+ struct net_device *dev = queue->vif->dev;
+
+ netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id));
++ kfree_skb(skb);
++ queue->vif->dev->stats.rx_dropped++;
++ } else {
++ if (skb_queue_empty(&queue->rx_queue))
++ xenvif_update_needed_slots(queue, skb);
++
++ __skb_queue_tail(&queue->rx_queue, skb);
++
++ queue->rx_queue_len += skb->len;
+ }
+
+ spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
+@@ -100,6 +114,8 @@ static struct sk_buff *xenvif_rx_dequeue(struct xenvif_queue *queue)
+
+ skb = __skb_dequeue(&queue->rx_queue);
+ if (skb) {
++ xenvif_update_needed_slots(queue, skb_peek(&queue->rx_queue));
++
+ queue->rx_queue_len -= skb->len;
+ if (queue->rx_queue_len < queue->rx_queue_max) {
+ struct netdev_queue *txq;
+@@ -134,6 +150,7 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue)
+ break;
+ xenvif_rx_dequeue(queue);
+ kfree_skb(skb);
++ queue->vif->dev->stats.rx_dropped++;
+ }
+ }
+
+@@ -487,27 +504,31 @@ void xenvif_rx_action(struct xenvif_queue *queue)
+ xenvif_rx_copy_flush(queue);
+ }
+
+-static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue)
++static RING_IDX xenvif_rx_queue_slots(const struct xenvif_queue *queue)
+ {
+ RING_IDX prod, cons;
+
+ prod = queue->rx.sring->req_prod;
+ cons = queue->rx.req_cons;
+
++ return prod - cons;
++}
++
++static bool xenvif_rx_queue_stalled(const struct xenvif_queue *queue)
++{
++ unsigned int needed = READ_ONCE(queue->rx_slots_needed);
++
+ return !queue->stalled &&
+- prod - cons < 1 &&
++ xenvif_rx_queue_slots(queue) < needed &&
+ time_after(jiffies,
+ queue->last_rx_time + queue->vif->stall_timeout);
+ }
+
+ static bool xenvif_rx_queue_ready(struct xenvif_queue *queue)
+ {
+- RING_IDX prod, cons;
+-
+- prod = queue->rx.sring->req_prod;
+- cons = queue->rx.req_cons;
++ unsigned int needed = READ_ONCE(queue->rx_slots_needed);
+
+- return queue->stalled && prod - cons >= 1;
++ return queue->stalled && xenvif_rx_queue_slots(queue) >= needed;
+ }
+
+ bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread)
+diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
+index fc41ba95f81d0..8126e08f11a99 100644
+--- a/drivers/net/xen-netfront.c
++++ b/drivers/net/xen-netfront.c
+@@ -148,6 +148,9 @@ struct netfront_queue {
+ grant_ref_t gref_rx_head;
+ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
++ unsigned int rx_rsp_unconsumed;
++ spinlock_t rx_cons_lock;
++
+ struct page_pool *page_pool;
+ struct xdp_rxq_info xdp_rxq;
+ };
+@@ -376,12 +379,13 @@ static int xennet_open(struct net_device *dev)
+ return 0;
+ }
+
+-static void xennet_tx_buf_gc(struct netfront_queue *queue)
++static bool xennet_tx_buf_gc(struct netfront_queue *queue)
+ {
+ RING_IDX cons, prod;
+ unsigned short id;
+ struct sk_buff *skb;
+ bool more_to_do;
++ bool work_done = false;
+ const struct device *dev = &queue->info->netdev->dev;
+
+ BUG_ON(!netif_carrier_ok(queue->info->netdev));
+@@ -398,6 +402,8 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
+ for (cons = queue->tx.rsp_cons; cons != prod; cons++) {
+ struct xen_netif_tx_response txrsp;
+
++ work_done = true;
++
+ RING_COPY_RESPONSE(&queue->tx, cons, &txrsp);
+ if (txrsp.status == XEN_NETIF_RSP_NULL)
+ continue;
+@@ -441,11 +447,13 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
+
+ xennet_maybe_wake_tx(queue);
+
+- return;
++ return work_done;
+
+ err:
+ queue->info->broken = true;
+ dev_alert(dev, "Disabled for further use\n");
++
++ return work_done;
+ }
+
+ struct xennet_gnttab_make_txreq {
+@@ -834,6 +842,16 @@ static int xennet_close(struct net_device *dev)
+ return 0;
+ }
+
++static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&queue->rx_cons_lock, flags);
++ queue->rx.rsp_cons = val;
++ queue->rx_rsp_unconsumed = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
++ spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
++}
++
+ static void xennet_move_rx_slot(struct netfront_queue *queue, struct sk_buff *skb,
+ grant_ref_t ref)
+ {
+@@ -885,7 +903,7 @@ static int xennet_get_extras(struct netfront_queue *queue,
+ xennet_move_rx_slot(queue, skb, ref);
+ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+- queue->rx.rsp_cons = cons;
++ xennet_set_rx_rsp_cons(queue, cons);
+ return err;
+ }
+
+@@ -1039,7 +1057,7 @@ next:
+ }
+
+ if (unlikely(err))
+- queue->rx.rsp_cons = cons + slots;
++ xennet_set_rx_rsp_cons(queue, cons + slots);
+
+ return err;
+ }
+@@ -1093,7 +1111,8 @@ static int xennet_fill_frags(struct netfront_queue *queue,
+ __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
+ }
+ if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
+- queue->rx.rsp_cons = ++cons + skb_queue_len(list);
++ xennet_set_rx_rsp_cons(queue,
++ ++cons + skb_queue_len(list));
+ kfree_skb(nskb);
+ return -ENOENT;
+ }
+@@ -1106,7 +1125,7 @@ static int xennet_fill_frags(struct netfront_queue *queue,
+ kfree_skb(nskb);
+ }
+
+- queue->rx.rsp_cons = cons;
++ xennet_set_rx_rsp_cons(queue, cons);
+
+ return 0;
+ }
+@@ -1229,7 +1248,9 @@ err:
+
+ if (unlikely(xennet_set_skb_gso(skb, gso))) {
+ __skb_queue_head(&tmpq, skb);
+- queue->rx.rsp_cons += skb_queue_len(&tmpq);
++ xennet_set_rx_rsp_cons(queue,
++ queue->rx.rsp_cons +
++ skb_queue_len(&tmpq));
+ goto err;
+ }
+ }
+@@ -1253,7 +1274,8 @@ err:
+
+ __skb_queue_tail(&rxq, skb);
+
+- i = ++queue->rx.rsp_cons;
++ i = queue->rx.rsp_cons + 1;
++ xennet_set_rx_rsp_cons(queue, i);
+ work_done++;
+ }
+ if (need_xdp_flush)
+@@ -1417,40 +1439,79 @@ static int xennet_set_features(struct net_device *dev,
+ return 0;
+ }
+
+-static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
++static bool xennet_handle_tx(struct netfront_queue *queue, unsigned int *eoi)
+ {
+- struct netfront_queue *queue = dev_id;
+ unsigned long flags;
+
+- if (queue->info->broken)
+- return IRQ_HANDLED;
++ if (unlikely(queue->info->broken))
++ return false;
+
+ spin_lock_irqsave(&queue->tx_lock, flags);
+- xennet_tx_buf_gc(queue);
++ if (xennet_tx_buf_gc(queue))
++ *eoi = 0;
+ spin_unlock_irqrestore(&queue->tx_lock, flags);
+
++ return true;
++}
++
++static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
++{
++ unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
++
++ if (likely(xennet_handle_tx(dev_id, &eoiflag)))
++ xen_irq_lateeoi(irq, eoiflag);
++
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
++static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
+ {
+- struct netfront_queue *queue = dev_id;
+- struct net_device *dev = queue->info->netdev;
++ unsigned int work_queued;
++ unsigned long flags;
+
+- if (queue->info->broken)
+- return IRQ_HANDLED;
++ if (unlikely(queue->info->broken))
++ return false;
++
++ spin_lock_irqsave(&queue->rx_cons_lock, flags);
++ work_queued = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx);
++ if (work_queued > queue->rx_rsp_unconsumed) {
++ queue->rx_rsp_unconsumed = work_queued;
++ *eoi = 0;
++ } else if (unlikely(work_queued < queue->rx_rsp_unconsumed)) {
++ const struct device *dev = &queue->info->netdev->dev;
++
++ spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
++ dev_alert(dev, "RX producer index going backwards\n");
++ dev_alert(dev, "Disabled for further use\n");
++ queue->info->broken = true;
++ return false;
++ }
++ spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
+
+- if (likely(netif_carrier_ok(dev) &&
+- RING_HAS_UNCONSUMED_RESPONSES(&queue->rx)))
++ if (likely(netif_carrier_ok(queue->info->netdev) && work_queued))
+ napi_schedule(&queue->napi);
+
++ return true;
++}
++
++static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
++{
++ unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
++
++ if (likely(xennet_handle_rx(dev_id, &eoiflag)))
++ xen_irq_lateeoi(irq, eoiflag);
++
+ return IRQ_HANDLED;
+ }
+
+ static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+ {
+- xennet_tx_interrupt(irq, dev_id);
+- xennet_rx_interrupt(irq, dev_id);
++ unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
++
++ if (xennet_handle_tx(dev_id, &eoiflag) &&
++ xennet_handle_rx(dev_id, &eoiflag))
++ xen_irq_lateeoi(irq, eoiflag);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -1768,9 +1829,10 @@ static int setup_netfront_single(struct netfront_queue *queue)
+ if (err < 0)
+ goto fail;
+
+- err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
+- xennet_interrupt,
+- 0, queue->info->netdev->name, queue);
++ err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
++ xennet_interrupt, 0,
++ queue->info->netdev->name,
++ queue);
+ if (err < 0)
+ goto bind_fail;
+ queue->rx_evtchn = queue->tx_evtchn;
+@@ -1798,18 +1860,18 @@ static int setup_netfront_split(struct netfront_queue *queue)
+
+ snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
+ "%s-tx", queue->name);
+- err = bind_evtchn_to_irqhandler(queue->tx_evtchn,
+- xennet_tx_interrupt,
+- 0, queue->tx_irq_name, queue);
++ err = bind_evtchn_to_irqhandler_lateeoi(queue->tx_evtchn,
++ xennet_tx_interrupt, 0,
++ queue->tx_irq_name, queue);
+ if (err < 0)
+ goto bind_tx_fail;
+ queue->tx_irq = err;
+
+ snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
+ "%s-rx", queue->name);
+- err = bind_evtchn_to_irqhandler(queue->rx_evtchn,
+- xennet_rx_interrupt,
+- 0, queue->rx_irq_name, queue);
++ err = bind_evtchn_to_irqhandler_lateeoi(queue->rx_evtchn,
++ xennet_rx_interrupt, 0,
++ queue->rx_irq_name, queue);
+ if (err < 0)
+ goto bind_rx_fail;
+ queue->rx_irq = err;
+@@ -1911,6 +1973,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
+
+ spin_lock_init(&queue->tx_lock);
+ spin_lock_init(&queue->rx_lock);
++ spin_lock_init(&queue->rx_cons_lock);
+
+ timer_setup(&queue->rx_refill_timer, rx_refill_timeout, 0);
+
+diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c
+index 2f3f3fe9a0baa..d32aec0c334fe 100644
+--- a/drivers/nfc/pn533/pn533.c
++++ b/drivers/nfc/pn533/pn533.c
+@@ -2218,7 +2218,7 @@ static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb)
+ frag = pn533_alloc_skb(dev, frag_size);
+ if (!frag) {
+ skb_queue_purge(&dev->fragment_skb);
+- break;
++ return -ENOMEM;
+ }
+
+ if (!dev->tgt_mode) {
+@@ -2287,7 +2287,7 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
+ /* jumbo frame ? */
+ if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+ rc = pn533_fill_fragment_skbs(dev, skb);
+- if (rc <= 0)
++ if (rc < 0)
+ goto error;
+
+ skb = skb_dequeue(&dev->fragment_skb);
+@@ -2355,7 +2355,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+ /* let's split in multiple chunks if size's too big */
+ if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+ rc = pn533_fill_fragment_skbs(dev, skb);
+- if (rc <= 0)
++ if (rc < 0)
+ goto error;
+
+ /* get the first skb */
+diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
+index 92dec49522972..3fd1bdb9fc05b 100644
+--- a/drivers/nvdimm/btt.c
++++ b/drivers/nvdimm/btt.c
+@@ -1538,7 +1538,6 @@ static int btt_blk_init(struct btt *btt)
+ int rc = nd_integrity_init(btt->btt_disk, btt_meta_size(btt));
+
+ if (rc) {
+- del_gendisk(btt->btt_disk);
+ blk_cleanup_disk(btt->btt_disk);
+ return rc;
+ }
+diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
+index 054154c22899a..2721dd2ead0a7 100644
+--- a/drivers/nvdimm/pmem.c
++++ b/drivers/nvdimm/pmem.c
+@@ -429,8 +429,10 @@ static int pmem_attach_disk(struct device *dev,
+ bb_range.end = res->end;
+ }
+
+- if (IS_ERR(addr))
+- return PTR_ERR(addr);
++ if (IS_ERR(addr)) {
++ rc = PTR_ERR(addr);
++ goto out;
++ }
+ pmem->virt_addr = addr;
+
+ blk_queue_write_cache(q, true, fua);
+@@ -455,7 +457,8 @@ static int pmem_attach_disk(struct device *dev,
+ flags = DAXDEV_F_SYNC;
+ dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
+ if (IS_ERR(dax_dev)) {
+- return PTR_ERR(dax_dev);
++ rc = PTR_ERR(dax_dev);
++ goto out;
+ }
+ dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
+ pmem->dax_dev = dax_dev;
+@@ -470,8 +473,10 @@ static int pmem_attach_disk(struct device *dev,
+ "badblocks");
+ if (!pmem->bb_state)
+ dev_warn(dev, "'badblocks' notification disabled\n");
+-
+ return 0;
++out:
++ blk_cleanup_disk(pmem->disk);
++ return rc;
+ }
+
+ static int nd_pmem_probe(struct device *dev)
+diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
+index fba06618c6c23..2f76969408b27 100644
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -138,13 +138,12 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
+ {
+ struct nvme_ns *ns;
+
+- mutex_lock(&ctrl->scan_lock);
+ down_read(&ctrl->namespaces_rwsem);
+- list_for_each_entry(ns, &ctrl->namespaces, list)
+- if (nvme_mpath_clear_current_path(ns))
+- kblockd_schedule_work(&ns->head->requeue_work);
++ list_for_each_entry(ns, &ctrl->namespaces, list) {
++ nvme_mpath_clear_current_path(ns);
++ kblockd_schedule_work(&ns->head->requeue_work);
++ }
+ up_read(&ctrl->namespaces_rwsem);
+- mutex_unlock(&ctrl->scan_lock);
+ }
+
+ void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
+diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
+index 042c594bc57e2..0498801542eb6 100644
+--- a/drivers/nvme/host/rdma.c
++++ b/drivers/nvme/host/rdma.c
+@@ -1095,11 +1095,13 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
+ return ret;
+
+ if (ctrl->ctrl.icdoff) {
++ ret = -EOPNOTSUPP;
+ dev_err(ctrl->ctrl.device, "icdoff is not supported!\n");
+ goto destroy_admin;
+ }
+
+ if (!(ctrl->ctrl.sgls & (1 << 2))) {
++ ret = -EOPNOTSUPP;
+ dev_err(ctrl->ctrl.device,
+ "Mandatory keyed sgls are not supported!\n");
+ goto destroy_admin;
+diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
+index be5d82421e3a4..496d775c67707 100644
+--- a/drivers/nvme/target/configfs.c
++++ b/drivers/nvme/target/configfs.c
+@@ -1553,6 +1553,8 @@ static void nvmet_port_release(struct config_item *item)
+ {
+ struct nvmet_port *port = to_nvmet_port(item);
+
++ /* Let inflight controllers teardown complete */
++ flush_scheduled_work();
+ list_del(&port->global_entry);
+
+ kfree(port->ana_state);
+diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
+index 1dd1a0fe2e819..df7e033dd2732 100644
+--- a/drivers/nvme/target/io-cmd-file.c
++++ b/drivers/nvme/target/io-cmd-file.c
+@@ -8,6 +8,7 @@
+ #include <linux/uio.h>
+ #include <linux/falloc.h>
+ #include <linux/file.h>
++#include <linux/fs.h>
+ #include "nvmet.h"
+
+ #define NVMET_MAX_MPOOL_BVEC 16
+@@ -266,7 +267,8 @@ static void nvmet_file_execute_rw(struct nvmet_req *req)
+
+ if (req->ns->buffered_io) {
+ if (likely(!req->f.mpool_alloc) &&
+- nvmet_file_execute_io(req, IOCB_NOWAIT))
++ (req->ns->file->f_mode & FMODE_NOWAIT) &&
++ nvmet_file_execute_io(req, IOCB_NOWAIT))
+ return;
+ nvmet_file_submit_buffered_io(req);
+ } else
+diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
+index 891174ccd44bb..f1eedbf493d5b 100644
+--- a/drivers/nvme/target/rdma.c
++++ b/drivers/nvme/target/rdma.c
+@@ -1818,12 +1818,36 @@ restart:
+ mutex_unlock(&nvmet_rdma_queue_mutex);
+ }
+
++static void nvmet_rdma_destroy_port_queues(struct nvmet_rdma_port *port)
++{
++ struct nvmet_rdma_queue *queue, *tmp;
++ struct nvmet_port *nport = port->nport;
++
++ mutex_lock(&nvmet_rdma_queue_mutex);
++ list_for_each_entry_safe(queue, tmp, &nvmet_rdma_queue_list,
++ queue_list) {
++ if (queue->port != nport)
++ continue;
++
++ list_del_init(&queue->queue_list);
++ __nvmet_rdma_queue_disconnect(queue);
++ }
++ mutex_unlock(&nvmet_rdma_queue_mutex);
++}
++
+ static void nvmet_rdma_disable_port(struct nvmet_rdma_port *port)
+ {
+ struct rdma_cm_id *cm_id = xchg(&port->cm_id, NULL);
+
+ if (cm_id)
+ rdma_destroy_id(cm_id);
++
++ /*
++ * Destroy the remaining queues, which are not belong to any
++ * controller yet. Do it here after the RDMA-CM was destroyed
++ * guarantees that no new queue will be created.
++ */
++ nvmet_rdma_destroy_port_queues(port);
+ }
+
+ static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port)
+diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
+index 46c3b3be7e033..2b8bab28417b8 100644
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -700,10 +700,11 @@ static int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
+ static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
+ {
+ struct nvmet_tcp_queue *queue = cmd->queue;
++ int left = NVME_TCP_DIGEST_LENGTH - cmd->offset;
+ struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
+ struct kvec iov = {
+ .iov_base = (u8 *)&cmd->exp_ddgst + cmd->offset,
+- .iov_len = NVME_TCP_DIGEST_LENGTH - cmd->offset
++ .iov_len = left
+ };
+ int ret;
+
+@@ -717,6 +718,10 @@ static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
+ return ret;
+
+ cmd->offset += ret;
++ left -= ret;
++
++ if (left)
++ return -EAGAIN;
+
+ if (queue->nvme_sq.sqhd_disabled) {
+ cmd->queue->snd_cmd = NULL;
+@@ -1740,6 +1745,17 @@ err_port:
+ return ret;
+ }
+
++static void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port)
++{
++ struct nvmet_tcp_queue *queue;
++
++ mutex_lock(&nvmet_tcp_queue_mutex);
++ list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list)
++ if (queue->port == port)
++ kernel_sock_shutdown(queue->sock, SHUT_RDWR);
++ mutex_unlock(&nvmet_tcp_queue_mutex);
++}
++
+ static void nvmet_tcp_remove_port(struct nvmet_port *nport)
+ {
+ struct nvmet_tcp_port *port = nport->priv;
+@@ -1749,6 +1765,11 @@ static void nvmet_tcp_remove_port(struct nvmet_port *nport)
+ port->sock->sk->sk_user_data = NULL;
+ write_unlock_bh(&port->sock->sk->sk_callback_lock);
+ cancel_work_sync(&port->accept_work);
++ /*
++ * Destroy the remaining queues, which are not belong to any
++ * controller yet.
++ */
++ nvmet_tcp_destroy_port_queues(port);
+
+ sock_release(port->sock);
+ kfree(port);
+diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
+index 8c056972a6ddc..5b85a2a3792ae 100644
+--- a/drivers/of/unittest.c
++++ b/drivers/of/unittest.c
+@@ -1688,19 +1688,19 @@ static void __init of_unittest_overlay_gpio(void)
+ */
+
+ EXPECT_BEGIN(KERN_INFO,
+- "GPIO line <<int>> (line-B-input) hogged as input\n");
++ "gpio-<<int>> (line-B-input): hogged as input\n");
+
+ EXPECT_BEGIN(KERN_INFO,
+- "GPIO line <<int>> (line-A-input) hogged as input\n");
++ "gpio-<<int>> (line-A-input): hogged as input\n");
+
+ ret = platform_driver_register(&unittest_gpio_driver);
+ if (unittest(ret == 0, "could not register unittest gpio driver\n"))
+ return;
+
+ EXPECT_END(KERN_INFO,
+- "GPIO line <<int>> (line-A-input) hogged as input\n");
++ "gpio-<<int>> (line-A-input): hogged as input\n");
+ EXPECT_END(KERN_INFO,
+- "GPIO line <<int>> (line-B-input) hogged as input\n");
++ "gpio-<<int>> (line-B-input): hogged as input\n");
+
+ unittest(probe_pass_count + 2 == unittest_gpio_probe_pass_count,
+ "unittest_gpio_probe() failed or not called\n");
+@@ -1727,7 +1727,7 @@ static void __init of_unittest_overlay_gpio(void)
+ chip_request_count = unittest_gpio_chip_request_count;
+
+ EXPECT_BEGIN(KERN_INFO,
+- "GPIO line <<int>> (line-D-input) hogged as input\n");
++ "gpio-<<int>> (line-D-input): hogged as input\n");
+
+ /* overlay_gpio_03 contains gpio node and child gpio hog node */
+
+@@ -1735,7 +1735,7 @@ static void __init of_unittest_overlay_gpio(void)
+ "Adding overlay 'overlay_gpio_03' failed\n");
+
+ EXPECT_END(KERN_INFO,
+- "GPIO line <<int>> (line-D-input) hogged as input\n");
++ "gpio-<<int>> (line-D-input): hogged as input\n");
+
+ unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count,
+ "unittest_gpio_probe() failed or not called\n");
+@@ -1774,7 +1774,7 @@ static void __init of_unittest_overlay_gpio(void)
+ */
+
+ EXPECT_BEGIN(KERN_INFO,
+- "GPIO line <<int>> (line-C-input) hogged as input\n");
++ "gpio-<<int>> (line-C-input): hogged as input\n");
+
+ /* overlay_gpio_04b contains child gpio hog node */
+
+@@ -1782,7 +1782,7 @@ static void __init of_unittest_overlay_gpio(void)
+ "Adding overlay 'overlay_gpio_04b' failed\n");
+
+ EXPECT_END(KERN_INFO,
+- "GPIO line <<int>> (line-C-input) hogged as input\n");
++ "gpio-<<int>> (line-C-input): hogged as input\n");
+
+ unittest(chip_request_count + 1 == unittest_gpio_chip_request_count,
+ "unittest_gpio_chip_request() called %d times (expected 1 time)\n",
+diff --git a/drivers/opp/of.c b/drivers/opp/of.c
+index 2a97c6535c4c6..c32ae7497392b 100644
+--- a/drivers/opp/of.c
++++ b/drivers/opp/of.c
+@@ -921,7 +921,7 @@ free_required_opps:
+ free_opp:
+ _opp_free(new_opp);
+
+- return ERR_PTR(ret);
++ return ret ? ERR_PTR(ret) : NULL;
+ }
+
+ /* Initializes OPP tables based on new bindings */
+diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
+index ffb176d288cd9..918e11082e6a7 100644
+--- a/drivers/pci/controller/cadence/pci-j721e.c
++++ b/drivers/pci/controller/cadence/pci-j721e.c
+@@ -474,7 +474,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(dev, "failed to enable pcie_refclk\n");
+- goto err_get_sync;
++ goto err_pcie_setup;
+ }
+ pcie->refclk = clk;
+
+diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
+index 5fee0f89ab594..a224afadbcc00 100644
+--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
++++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
+@@ -127,6 +127,8 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
+ goto err_init;
+ }
+
++ return 0;
++
+ err_init:
+ err_get_sync:
+ pm_runtime_put_sync(dev);
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index d842fd0181299..d05be942956e2 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -168,30 +168,21 @@ static void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv)
+ writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX);
+ }
+
+-static void uniphier_pcie_irq_ack(struct irq_data *d)
+-{
+- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+- u32 val;
+-
+- val = readl(priv->base + PCL_RCV_INTX);
+- val &= ~PCL_RCV_INTX_ALL_STATUS;
+- val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_STATUS_SHIFT);
+- writel(val, priv->base + PCL_RCV_INTX);
+-}
+-
+ static void uniphier_pcie_irq_mask(struct irq_data *d)
+ {
+ struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
++ unsigned long flags;
+ u32 val;
+
++ raw_spin_lock_irqsave(&pp->lock, flags);
++
+ val = readl(priv->base + PCL_RCV_INTX);
+- val &= ~PCL_RCV_INTX_ALL_MASK;
+ val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
+ writel(val, priv->base + PCL_RCV_INTX);
++
++ raw_spin_unlock_irqrestore(&pp->lock, flags);
+ }
+
+ static void uniphier_pcie_irq_unmask(struct irq_data *d)
+@@ -199,17 +190,20 @@ static void uniphier_pcie_irq_unmask(struct irq_data *d)
+ struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
++ unsigned long flags;
+ u32 val;
+
++ raw_spin_lock_irqsave(&pp->lock, flags);
++
+ val = readl(priv->base + PCL_RCV_INTX);
+- val &= ~PCL_RCV_INTX_ALL_MASK;
+ val &= ~BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
+ writel(val, priv->base + PCL_RCV_INTX);
++
++ raw_spin_unlock_irqrestore(&pp->lock, flags);
+ }
+
+ static struct irq_chip uniphier_pcie_irq_chip = {
+ .name = "PCI",
+- .irq_ack = uniphier_pcie_irq_ack,
+ .irq_mask = uniphier_pcie_irq_mask,
+ .irq_unmask = uniphier_pcie_irq_unmask,
+ };
+diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
+index 596ebcfcc82dc..c3b725afa11fd 100644
+--- a/drivers/pci/controller/pci-aardvark.c
++++ b/drivers/pci/controller/pci-aardvark.c
+@@ -31,9 +31,6 @@
+ /* PCIe core registers */
+ #define PCIE_CORE_DEV_ID_REG 0x0
+ #define PCIE_CORE_CMD_STATUS_REG 0x4
+-#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0)
+-#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1)
+-#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
+ #define PCIE_CORE_DEV_REV_REG 0x8
+ #define PCIE_CORE_PCIEXP_CAP 0xc0
+ #define PCIE_CORE_ERR_CAPCTL_REG 0x118
+@@ -99,6 +96,7 @@
+ #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10)
+ #define PCIE_CORE_REF_CLK_REG (CONTROL_BASE_ADDR + 0x14)
+ #define PCIE_CORE_REF_CLK_TX_ENABLE BIT(1)
++#define PCIE_CORE_REF_CLK_RX_ENABLE BIT(2)
+ #define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30)
+ #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40)
+ #define PCIE_MSG_PM_PME_MASK BIT(7)
+@@ -106,18 +104,19 @@
+ #define PCIE_ISR0_MSI_INT_PENDING BIT(24)
+ #define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
+ #define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val))
+-#define PCIE_ISR0_ALL_MASK GENMASK(26, 0)
++#define PCIE_ISR0_ALL_MASK GENMASK(31, 0)
+ #define PCIE_ISR1_REG (CONTROL_BASE_ADDR + 0x48)
+ #define PCIE_ISR1_MASK_REG (CONTROL_BASE_ADDR + 0x4C)
+ #define PCIE_ISR1_POWER_STATE_CHANGE BIT(4)
+ #define PCIE_ISR1_FLUSH BIT(5)
+ #define PCIE_ISR1_INTX_ASSERT(val) BIT(8 + (val))
+-#define PCIE_ISR1_ALL_MASK GENMASK(11, 4)
++#define PCIE_ISR1_ALL_MASK GENMASK(31, 0)
+ #define PCIE_MSI_ADDR_LOW_REG (CONTROL_BASE_ADDR + 0x50)
+ #define PCIE_MSI_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54)
+ #define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58)
+ #define PCIE_MSI_MASK_REG (CONTROL_BASE_ADDR + 0x5C)
+ #define PCIE_MSI_PAYLOAD_REG (CONTROL_BASE_ADDR + 0x9C)
++#define PCIE_MSI_DATA_MASK GENMASK(15, 0)
+
+ /* PCIe window configuration */
+ #define OB_WIN_BASE_ADDR 0x4c00
+@@ -164,8 +163,50 @@
+ #define CFG_REG (LMI_BASE_ADDR + 0x0)
+ #define LTSSM_SHIFT 24
+ #define LTSSM_MASK 0x3f
+-#define LTSSM_L0 0x10
+ #define RC_BAR_CONFIG 0x300
++
++/* LTSSM values in CFG_REG */
++enum {
++ LTSSM_DETECT_QUIET = 0x0,
++ LTSSM_DETECT_ACTIVE = 0x1,
++ LTSSM_POLLING_ACTIVE = 0x2,
++ LTSSM_POLLING_COMPLIANCE = 0x3,
++ LTSSM_POLLING_CONFIGURATION = 0x4,
++ LTSSM_CONFIG_LINKWIDTH_START = 0x5,
++ LTSSM_CONFIG_LINKWIDTH_ACCEPT = 0x6,
++ LTSSM_CONFIG_LANENUM_ACCEPT = 0x7,
++ LTSSM_CONFIG_LANENUM_WAIT = 0x8,
++ LTSSM_CONFIG_COMPLETE = 0x9,
++ LTSSM_CONFIG_IDLE = 0xa,
++ LTSSM_RECOVERY_RCVR_LOCK = 0xb,
++ LTSSM_RECOVERY_SPEED = 0xc,
++ LTSSM_RECOVERY_RCVR_CFG = 0xd,
++ LTSSM_RECOVERY_IDLE = 0xe,
++ LTSSM_L0 = 0x10,
++ LTSSM_RX_L0S_ENTRY = 0x11,
++ LTSSM_RX_L0S_IDLE = 0x12,
++ LTSSM_RX_L0S_FTS = 0x13,
++ LTSSM_TX_L0S_ENTRY = 0x14,
++ LTSSM_TX_L0S_IDLE = 0x15,
++ LTSSM_TX_L0S_FTS = 0x16,
++ LTSSM_L1_ENTRY = 0x17,
++ LTSSM_L1_IDLE = 0x18,
++ LTSSM_L2_IDLE = 0x19,
++ LTSSM_L2_TRANSMIT_WAKE = 0x1a,
++ LTSSM_DISABLED = 0x20,
++ LTSSM_LOOPBACK_ENTRY_MASTER = 0x21,
++ LTSSM_LOOPBACK_ACTIVE_MASTER = 0x22,
++ LTSSM_LOOPBACK_EXIT_MASTER = 0x23,
++ LTSSM_LOOPBACK_ENTRY_SLAVE = 0x24,
++ LTSSM_LOOPBACK_ACTIVE_SLAVE = 0x25,
++ LTSSM_LOOPBACK_EXIT_SLAVE = 0x26,
++ LTSSM_HOT_RESET = 0x27,
++ LTSSM_RECOVERY_EQUALIZATION_PHASE0 = 0x28,
++ LTSSM_RECOVERY_EQUALIZATION_PHASE1 = 0x29,
++ LTSSM_RECOVERY_EQUALIZATION_PHASE2 = 0x2a,
++ LTSSM_RECOVERY_EQUALIZATION_PHASE3 = 0x2b,
++};
++
+ #define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
+
+ /* PCIe core controller registers */
+@@ -198,7 +239,7 @@
+ #define PCIE_IRQ_MSI_INT2_DET BIT(21)
+ #define PCIE_IRQ_RC_DBELL_DET BIT(22)
+ #define PCIE_IRQ_EP_STATUS BIT(23)
+-#define PCIE_IRQ_ALL_MASK 0xfff0fb
++#define PCIE_IRQ_ALL_MASK GENMASK(31, 0)
+ #define PCIE_IRQ_ENABLE_INTS_MASK PCIE_IRQ_CORE_INT
+
+ /* Transaction types */
+@@ -257,18 +298,49 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg)
+ return readl(pcie->base + reg);
+ }
+
+-static inline u16 advk_read16(struct advk_pcie *pcie, u64 reg)
++static u8 advk_pcie_ltssm_state(struct advk_pcie *pcie)
+ {
+- return advk_readl(pcie, (reg & ~0x3)) >> ((reg & 0x3) * 8);
++ u32 val;
++ u8 ltssm_state;
++
++ val = advk_readl(pcie, CFG_REG);
++ ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
++ return ltssm_state;
+ }
+
+-static int advk_pcie_link_up(struct advk_pcie *pcie)
++static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
+ {
+- u32 val, ltssm_state;
++ /* check if LTSSM is in normal operation - some L* state */
++ u8 ltssm_state = advk_pcie_ltssm_state(pcie);
++ return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED;
++}
+
+- val = advk_readl(pcie, CFG_REG);
+- ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
+- return ltssm_state >= LTSSM_L0;
++static inline bool advk_pcie_link_active(struct advk_pcie *pcie)
++{
++ /*
++ * According to PCIe Base specification 3.0, Table 4-14: Link
++ * Status Mapped to the LTSSM, and 4.2.6.3.6 Configuration.Idle
++ * is Link Up mapped to LTSSM Configuration.Idle, Recovery, L0,
++ * L0s, L1 and L2 states. And according to 3.2.1. Data Link
++ * Control and Management State Machine Rules is DL Up status
++ * reported in DL Active state.
++ */
++ u8 ltssm_state = advk_pcie_ltssm_state(pcie);
++ return ltssm_state >= LTSSM_CONFIG_IDLE && ltssm_state < LTSSM_DISABLED;
++}
++
++static inline bool advk_pcie_link_training(struct advk_pcie *pcie)
++{
++ /*
++ * According to PCIe Base specification 3.0, Table 4-14: Link
++ * Status Mapped to the LTSSM is Link Training mapped to LTSSM
++ * Configuration and Recovery states.
++ */
++ u8 ltssm_state = advk_pcie_ltssm_state(pcie);
++ return ((ltssm_state >= LTSSM_CONFIG_LINKWIDTH_START &&
++ ltssm_state < LTSSM_L0) ||
++ (ltssm_state >= LTSSM_RECOVERY_EQUALIZATION_PHASE0 &&
++ ltssm_state <= LTSSM_RECOVERY_EQUALIZATION_PHASE3));
+ }
+
+ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
+@@ -291,7 +363,7 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
+ size_t retries;
+
+ for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
+- if (!advk_pcie_link_up(pcie))
++ if (advk_pcie_link_training(pcie))
+ break;
+ udelay(RETRAIN_WAIT_USLEEP_US);
+ }
+@@ -299,23 +371,9 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
+
+ static void advk_pcie_issue_perst(struct advk_pcie *pcie)
+ {
+- u32 reg;
+-
+ if (!pcie->reset_gpio)
+ return;
+
+- /*
+- * As required by PCI Express spec (PCI Express Base Specification, REV.
+- * 4.0 PCI Express, February 19 2014, 6.6.1 Conventional Reset) a delay
+- * for at least 100ms after de-asserting PERST# signal is needed before
+- * link training is enabled. So ensure that link training is disabled
+- * prior de-asserting PERST# signal to fulfill that PCI Express spec
+- * requirement.
+- */
+- reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+- reg &= ~LINK_TRAINING_EN;
+- advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+-
+ /* 10ms delay is needed for some cards */
+ dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
+ gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+@@ -323,53 +381,46 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie)
+ gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+ }
+
+-static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen)
++static void advk_pcie_train_link(struct advk_pcie *pcie)
+ {
+- int ret, neg_gen;
++ struct device *dev = &pcie->pdev->dev;
+ u32 reg;
++ int ret;
+
+- /* Setup link speed */
++ /*
++ * Setup PCIe rev / gen compliance based on device tree property
++ * 'max-link-speed' which also forces maximal link speed.
++ */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg &= ~PCIE_GEN_SEL_MSK;
+- if (gen == 3)
++ if (pcie->link_gen == 3)
+ reg |= SPEED_GEN_3;
+- else if (gen == 2)
++ else if (pcie->link_gen == 2)
+ reg |= SPEED_GEN_2;
+ else
+ reg |= SPEED_GEN_1;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+ /*
+- * Enable link training. This is not needed in every call to this
+- * function, just once suffices, but it does not break anything either.
++ * Set maximal link speed value also into PCIe Link Control 2 register.
++ * Armada 3700 Functional Specification says that default value is based
++ * on SPEED_GEN but tests showed that default value is always 8.0 GT/s.
+ */
++ reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL2);
++ reg &= ~PCI_EXP_LNKCTL2_TLS;
++ if (pcie->link_gen == 3)
++ reg |= PCI_EXP_LNKCTL2_TLS_8_0GT;
++ else if (pcie->link_gen == 2)
++ reg |= PCI_EXP_LNKCTL2_TLS_5_0GT;
++ else
++ reg |= PCI_EXP_LNKCTL2_TLS_2_5GT;
++ advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL2);
++
++ /* Enable link training after selecting PCIe generation */
+ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+ reg |= LINK_TRAINING_EN;
+ advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+- /*
+- * Start link training immediately after enabling it.
+- * This solves problems for some buggy cards.
+- */
+- reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL);
+- reg |= PCI_EXP_LNKCTL_RL;
+- advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL);
+-
+- ret = advk_pcie_wait_for_link(pcie);
+- if (ret)
+- return ret;
+-
+- reg = advk_read16(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKSTA);
+- neg_gen = reg & PCI_EXP_LNKSTA_CLS;
+-
+- return neg_gen;
+-}
+-
+-static void advk_pcie_train_link(struct advk_pcie *pcie)
+-{
+- struct device *dev = &pcie->pdev->dev;
+- int neg_gen = -1, gen;
+-
+ /*
+ * Reset PCIe card via PERST# signal. Some cards are not detected
+ * during link training when they are in some non-initial state.
+@@ -380,41 +431,18 @@ static void advk_pcie_train_link(struct advk_pcie *pcie)
+ * PERST# signal could have been asserted by pinctrl subsystem before
+ * probe() callback has been called or issued explicitly by reset gpio
+ * function advk_pcie_issue_perst(), making the endpoint going into
+- * fundamental reset. As required by PCI Express spec a delay for at
+- * least 100ms after such a reset before link training is needed.
+- */
+- msleep(PCI_PM_D3COLD_WAIT);
+-
+- /*
+- * Try link training at link gen specified by device tree property
+- * 'max-link-speed'. If this fails, iteratively train at lower gen.
++ * fundamental reset. As required by PCI Express spec (PCI Express
++ * Base Specification, REV. 4.0 PCI Express, February 19 2014, 6.6.1
++ * Conventional Reset) a delay for at least 100ms after such a reset
++ * before sending a Configuration Request to the device is needed.
++ * So wait until PCIe link is up. Function advk_pcie_wait_for_link()
++ * waits for link at least 900ms.
+ */
+- for (gen = pcie->link_gen; gen > 0; --gen) {
+- neg_gen = advk_pcie_train_at_gen(pcie, gen);
+- if (neg_gen > 0)
+- break;
+- }
+-
+- if (neg_gen < 0)
+- goto err;
+-
+- /*
+- * After successful training if negotiated gen is lower than requested,
+- * train again on negotiated gen. This solves some stability issues for
+- * some buggy gen1 cards.
+- */
+- if (neg_gen < gen) {
+- gen = neg_gen;
+- neg_gen = advk_pcie_train_at_gen(pcie, gen);
+- }
+-
+- if (neg_gen == gen) {
+- dev_info(dev, "link up at gen %i\n", gen);
+- return;
+- }
+-
+-err:
+- dev_err(dev, "link never came up\n");
++ ret = advk_pcie_wait_for_link(pcie);
++ if (ret < 0)
++ dev_err(dev, "link never came up\n");
++ else
++ dev_info(dev, "link up\n");
+ }
+
+ /*
+@@ -451,9 +479,15 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+ u32 reg;
+ int i;
+
+- /* Enable TX */
++ /*
++ * Configure PCIe Reference clock. Direction is from the PCIe
++ * controller to the endpoint card, so enable transmitting of
++ * Reference clock differential signal off-chip and disable
++ * receiving off-chip differential signal.
++ */
+ reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG);
+ reg |= PCIE_CORE_REF_CLK_TX_ENABLE;
++ reg &= ~PCIE_CORE_REF_CLK_RX_ENABLE;
+ advk_writel(pcie, reg, PCIE_CORE_REF_CLK_REG);
+
+ /* Set to Direct mode */
+@@ -477,6 +511,31 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+ reg = (PCI_VENDOR_ID_MARVELL << 16) | PCI_VENDOR_ID_MARVELL;
+ advk_writel(pcie, reg, VENDOR_ID_REG);
+
++ /*
++ * Change Class Code of PCI Bridge device to PCI Bridge (0x600400),
++ * because the default value is Mass storage controller (0x010400).
++ *
++ * Note that this Aardvark PCI Bridge does not have compliant Type 1
++ * Configuration Space and it even cannot be accessed via Aardvark's
++ * PCI config space access method. Something like config space is
++ * available in internal Aardvark registers starting at offset 0x0
++ * and is reported as Type 0. In range 0x10 - 0x34 it has totally
++ * different registers.
++ *
++ * Therefore driver uses emulation of PCI Bridge which emulates
++ * access to configuration space via internal Aardvark registers or
++ * emulated configuration buffer.
++ */
++ reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG);
++ reg &= ~0xffffff00;
++ reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8;
++ advk_writel(pcie, reg, PCIE_CORE_DEV_REV_REG);
++
++ /* Disable Root Bridge I/O space, memory space and bus mastering */
++ reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
++ reg &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
++ advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
++
+ /* Set Advanced Error Capabilities and Control PF0 register */
+ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
+ PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
+@@ -488,8 +547,9 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+ reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL);
+ reg &= ~PCI_EXP_DEVCTL_RELAX_EN;
+ reg &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
++ reg &= ~PCI_EXP_DEVCTL_PAYLOAD;
+ reg &= ~PCI_EXP_DEVCTL_READRQ;
+- reg |= PCI_EXP_DEVCTL_PAYLOAD; /* Set max payload size */
++ reg |= PCI_EXP_DEVCTL_PAYLOAD_512B;
+ reg |= PCI_EXP_DEVCTL_READRQ_512B;
+ advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL);
+
+@@ -574,19 +634,6 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+ advk_pcie_disable_ob_win(pcie, i);
+
+ advk_pcie_train_link(pcie);
+-
+- /*
+- * FIXME: The following register update is suspicious. This register is
+- * applicable only when the PCI controller is configured for Endpoint
+- * mode, not as a Root Complex. But apparently when this code is
+- * removed, some cards stop working. This should be investigated and
+- * a comment explaining this should be put here.
+- */
+- reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
+- reg |= PCIE_CORE_CMD_MEM_ACCESS_EN |
+- PCIE_CORE_CMD_IO_ACCESS_EN |
+- PCIE_CORE_CMD_MEM_IO_REQ_EN;
+- advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
+ }
+
+ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u32 *val)
+@@ -595,6 +642,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3
+ u32 reg;
+ unsigned int status;
+ char *strcomp_status, *str_posted;
++ int ret;
+
+ reg = advk_readl(pcie, PIO_STAT);
+ status = (reg & PIO_COMPLETION_STATUS_MASK) >>
+@@ -619,6 +667,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3
+ case PIO_COMPLETION_STATUS_OK:
+ if (reg & PIO_ERR_STATUS) {
+ strcomp_status = "COMP_ERR";
++ ret = -EFAULT;
+ break;
+ }
+ /* Get the read result */
+@@ -626,9 +675,11 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3
+ *val = advk_readl(pcie, PIO_RD_DATA);
+ /* No error */
+ strcomp_status = NULL;
++ ret = 0;
+ break;
+ case PIO_COMPLETION_STATUS_UR:
+ strcomp_status = "UR";
++ ret = -EOPNOTSUPP;
+ break;
+ case PIO_COMPLETION_STATUS_CRS:
+ if (allow_crs && val) {
+@@ -646,6 +697,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3
+ */
+ *val = CFG_RD_CRS_VAL;
+ strcomp_status = NULL;
++ ret = 0;
+ break;
+ }
+ /* PCIe r4.0, sec 2.3.2, says:
+@@ -661,31 +713,34 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3
+ * Request and taking appropriate action, e.g., complete the
+ * Request to the host as a failed transaction.
+ *
+- * To simplify implementation do not re-issue the Configuration
+- * Request and complete the Request as a failed transaction.
++ * So return -EAGAIN and caller (pci-aardvark.c driver) will
++ * re-issue request again up to the PIO_RETRY_CNT retries.
+ */
+ strcomp_status = "CRS";
++ ret = -EAGAIN;
+ break;
+ case PIO_COMPLETION_STATUS_CA:
+ strcomp_status = "CA";
++ ret = -ECANCELED;
+ break;
+ default:
+ strcomp_status = "Unknown";
++ ret = -EINVAL;
+ break;
+ }
+
+ if (!strcomp_status)
+- return 0;
++ return ret;
+
+ if (reg & PIO_NON_POSTED_REQ)
+ str_posted = "Non-posted";
+ else
+ str_posted = "Posted";
+
+- dev_err(dev, "%s PIO Response Status: %s, %#x @ %#x\n",
++ dev_dbg(dev, "%s PIO Response Status: %s, %#x @ %#x\n",
+ str_posted, strcomp_status, reg, advk_readl(pcie, PIO_ADDR_LS));
+
+- return -EFAULT;
++ return ret;
+ }
+
+ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
+@@ -693,13 +748,13 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
+ struct device *dev = &pcie->pdev->dev;
+ int i;
+
+- for (i = 0; i < PIO_RETRY_CNT; i++) {
++ for (i = 1; i <= PIO_RETRY_CNT; i++) {
+ u32 start, isr;
+
+ start = advk_readl(pcie, PIO_START);
+ isr = advk_readl(pcie, PIO_ISR);
+ if (!start && isr)
+- return 0;
++ return i;
+ udelay(PIO_RETRY_DELAY);
+ }
+
+@@ -707,6 +762,64 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
+ return -ETIMEDOUT;
+ }
+
++static pci_bridge_emul_read_status_t
++advk_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
++ int reg, u32 *value)
++{
++ struct advk_pcie *pcie = bridge->data;
++
++ switch (reg) {
++ case PCI_COMMAND:
++ *value = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
++ return PCI_BRIDGE_EMUL_HANDLED;
++
++ case PCI_INTERRUPT_LINE: {
++ /*
++ * From the whole 32bit register we support reading from HW only
++ * one bit: PCI_BRIDGE_CTL_BUS_RESET.
++ * Other bits are retrieved only from emulated config buffer.
++ */
++ __le32 *cfgspace = (__le32 *)&bridge->conf;
++ u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
++ if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
++ val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
++ else
++ val &= ~(PCI_BRIDGE_CTL_BUS_RESET << 16);
++ *value = val;
++ return PCI_BRIDGE_EMUL_HANDLED;
++ }
++
++ default:
++ return PCI_BRIDGE_EMUL_NOT_HANDLED;
++ }
++}
++
++static void
++advk_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
++ int reg, u32 old, u32 new, u32 mask)
++{
++ struct advk_pcie *pcie = bridge->data;
++
++ switch (reg) {
++ case PCI_COMMAND:
++ advk_writel(pcie, new, PCIE_CORE_CMD_STATUS_REG);
++ break;
++
++ case PCI_INTERRUPT_LINE:
++ if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
++ u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
++ if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
++ val |= HOT_RESET_GEN;
++ else
++ val &= ~HOT_RESET_GEN;
++ advk_writel(pcie, val, PCIE_CORE_CTRL1_REG);
++ }
++ break;
++
++ default:
++ break;
++ }
++}
+
+ static pci_bridge_emul_read_status_t
+ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+@@ -723,6 +836,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+ case PCI_EXP_RTCTL: {
+ u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
+ *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
++ *value |= le16_to_cpu(bridge->pcie_conf.rootctl) & PCI_EXP_RTCTL_CRSSVE;
+ *value |= PCI_EXP_RTCAP_CRSVIS << 16;
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+@@ -734,12 +848,26 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+
++ case PCI_EXP_LNKCAP: {
++ u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
++ /*
++ * PCI_EXP_LNKCAP_DLLLARC bit is hardwired in aardvark HW to 0.
++ * But support for PCI_EXP_LNKSTA_DLLLA is emulated via ltssm
++ * state so explicitly enable PCI_EXP_LNKCAP_DLLLARC flag.
++ */
++ val |= PCI_EXP_LNKCAP_DLLLARC;
++ *value = val;
++ return PCI_BRIDGE_EMUL_HANDLED;
++ }
++
+ case PCI_EXP_LNKCTL: {
+ /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
+ u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
+ ~(PCI_EXP_LNKSTA_LT << 16);
+- if (!advk_pcie_link_up(pcie))
++ if (advk_pcie_link_training(pcie))
+ val |= (PCI_EXP_LNKSTA_LT << 16);
++ if (advk_pcie_link_active(pcie))
++ val |= (PCI_EXP_LNKSTA_DLLLA << 16);
+ *value = val;
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+@@ -747,7 +875,6 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+ case PCI_CAP_LIST_ID:
+ case PCI_EXP_DEVCAP:
+ case PCI_EXP_DEVCTL:
+- case PCI_EXP_LNKCAP:
+ *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
+ return PCI_BRIDGE_EMUL_HANDLED;
+ default:
+@@ -794,6 +921,8 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
+ }
+
+ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
++ .read_base = advk_pci_bridge_emul_base_conf_read,
++ .write_base = advk_pci_bridge_emul_base_conf_write,
+ .read_pcie = advk_pci_bridge_emul_pcie_conf_read,
+ .write_pcie = advk_pci_bridge_emul_pcie_conf_write,
+ };
+@@ -805,7 +934,6 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
+ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
+ {
+ struct pci_bridge_emul *bridge = &pcie->bridge;
+- int ret;
+
+ bridge->conf.vendor =
+ cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff);
+@@ -825,19 +953,14 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
+ /* Support interrupt A for MSI feature */
+ bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE;
+
++ /* Indicates supports for Completion Retry Status */
++ bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS);
++
+ bridge->has_pcie = true;
+ bridge->data = pcie;
+ bridge->ops = &advk_pci_bridge_emul_ops;
+
+- /* PCIe config space can be initialized after pci_bridge_emul_init() */
+- ret = pci_bridge_emul_init(bridge, 0);
+- if (ret < 0)
+- return ret;
+-
+- /* Indicates supports for Completion Retry Status */
+- bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS);
+-
+- return 0;
++ return pci_bridge_emul_init(bridge, 0);
+ }
+
+ static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
+@@ -889,6 +1012,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 *val)
+ {
+ struct advk_pcie *pcie = bus->sysdata;
++ int retry_count;
+ bool allow_crs;
+ u32 reg;
+ int ret;
+@@ -911,18 +1035,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
+ (le16_to_cpu(pcie->bridge.pcie_conf.rootctl) &
+ PCI_EXP_RTCTL_CRSSVE);
+
+- if (advk_pcie_pio_is_running(pcie)) {
+- /*
+- * If it is possible return Completion Retry Status so caller
+- * tries to issue the request again instead of failing.
+- */
+- if (allow_crs) {
+- *val = CFG_RD_CRS_VAL;
+- return PCIBIOS_SUCCESSFUL;
+- }
+- *val = 0xffffffff;
+- return PCIBIOS_SET_FAILED;
+- }
++ if (advk_pcie_pio_is_running(pcie))
++ goto try_crs;
+
+ /* Program the control register */
+ reg = advk_readl(pcie, PIO_CTRL);
+@@ -941,30 +1055,24 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
+ /* Program the data strobe */
+ advk_writel(pcie, 0xf, PIO_WR_DATA_STRB);
+
+- /* Clear PIO DONE ISR and start the transfer */
+- advk_writel(pcie, 1, PIO_ISR);
+- advk_writel(pcie, 1, PIO_START);
++ retry_count = 0;
++ do {
++ /* Clear PIO DONE ISR and start the transfer */
++ advk_writel(pcie, 1, PIO_ISR);
++ advk_writel(pcie, 1, PIO_START);
+
+- ret = advk_pcie_wait_pio(pcie);
+- if (ret < 0) {
+- /*
+- * If it is possible return Completion Retry Status so caller
+- * tries to issue the request again instead of failing.
+- */
+- if (allow_crs) {
+- *val = CFG_RD_CRS_VAL;
+- return PCIBIOS_SUCCESSFUL;
+- }
+- *val = 0xffffffff;
+- return PCIBIOS_SET_FAILED;
+- }
++ ret = advk_pcie_wait_pio(pcie);
++ if (ret < 0)
++ goto try_crs;
+
+- /* Check PIO status and get the read result */
+- ret = advk_pcie_check_pio_status(pcie, allow_crs, val);
+- if (ret < 0) {
+- *val = 0xffffffff;
+- return PCIBIOS_SET_FAILED;
+- }
++ retry_count += ret;
++
++ /* Check PIO status and get the read result */
++ ret = advk_pcie_check_pio_status(pcie, allow_crs, val);
++ } while (ret == -EAGAIN && retry_count < PIO_RETRY_CNT);
++
++ if (ret < 0)
++ goto fail;
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+@@ -972,6 +1080,20 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
+ *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
++
++try_crs:
++ /*
++ * If it is possible, return Completion Retry Status so that caller
++ * tries to issue the request again instead of failing.
++ */
++ if (allow_crs) {
++ *val = CFG_RD_CRS_VAL;
++ return PCIBIOS_SUCCESSFUL;
++ }
++
++fail:
++ *val = 0xffffffff;
++ return PCIBIOS_SET_FAILED;
+ }
+
+ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+@@ -980,6 +1102,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ struct advk_pcie *pcie = bus->sysdata;
+ u32 reg;
+ u32 data_strobe = 0x0;
++ int retry_count;
+ int offset;
+ int ret;
+
+@@ -1021,19 +1144,22 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ /* Program the data strobe */
+ advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB);
+
+- /* Clear PIO DONE ISR and start the transfer */
+- advk_writel(pcie, 1, PIO_ISR);
+- advk_writel(pcie, 1, PIO_START);
++ retry_count = 0;
++ do {
++ /* Clear PIO DONE ISR and start the transfer */
++ advk_writel(pcie, 1, PIO_ISR);
++ advk_writel(pcie, 1, PIO_START);
+
+- ret = advk_pcie_wait_pio(pcie);
+- if (ret < 0)
+- return PCIBIOS_SET_FAILED;
++ ret = advk_pcie_wait_pio(pcie);
++ if (ret < 0)
++ return PCIBIOS_SET_FAILED;
+
+- ret = advk_pcie_check_pio_status(pcie, false, NULL);
+- if (ret < 0)
+- return PCIBIOS_SET_FAILED;
++ retry_count += ret;
+
+- return PCIBIOS_SUCCESSFUL;
++ ret = advk_pcie_check_pio_status(pcie, false, NULL);
++ } while (ret == -EAGAIN && retry_count < PIO_RETRY_CNT);
++
++ return ret < 0 ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
+ }
+
+ static struct pci_ops advk_pcie_ops = {
+@@ -1082,7 +1208,7 @@ static int advk_msi_irq_domain_alloc(struct irq_domain *domain,
+ domain->host_data, handle_simple_irq,
+ NULL, NULL);
+
+- return hwirq;
++ return 0;
+ }
+
+ static void advk_msi_irq_domain_free(struct irq_domain *domain,
+@@ -1263,8 +1389,12 @@ static void advk_pcie_handle_msi(struct advk_pcie *pcie)
+ if (!(BIT(msi_idx) & msi_status))
+ continue;
+
++ /*
++ * msi_idx contains bits [4:0] of the msi_data and msi_data
++ * contains 16bit MSI interrupt number
++ */
+ advk_writel(pcie, BIT(msi_idx), PCIE_MSI_STATUS_REG);
+- msi_data = advk_readl(pcie, PCIE_MSI_PAYLOAD_REG) & 0xFF;
++ msi_data = advk_readl(pcie, PCIE_MSI_PAYLOAD_REG) & PCIE_MSI_DATA_MASK;
+ generic_handle_irq(msi_data);
+ }
+
+@@ -1286,12 +1416,6 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
+ isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
+ isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
+
+- if (!isr0_status && !isr1_status) {
+- advk_writel(pcie, isr0_val, PCIE_ISR0_REG);
+- advk_writel(pcie, isr1_val, PCIE_ISR1_REG);
+- return;
+- }
+-
+ /* Process MSI interrupts */
+ if (isr0_status & PCIE_ISR0_MSI_INT_PENDING)
+ advk_pcie_handle_msi(pcie);
+diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
+index 4b4792940e869..e11530cb05699 100644
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -148,6 +148,9 @@ static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 s
+ raw_spinlock_t *lock = &desc->dev->msi_lock;
+ unsigned long flags;
+
++ if (!desc->msi_attrib.can_mask)
++ return;
++
+ raw_spin_lock_irqsave(lock, flags);
+ desc->msi_mask &= ~clear;
+ desc->msi_mask |= set;
+@@ -181,7 +184,8 @@ static void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
+ {
+ void __iomem *desc_addr = pci_msix_desc_addr(desc);
+
+- writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
++ if (desc->msi_attrib.can_mask)
++ writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
+ }
+
+ static inline void pci_msix_mask(struct msi_desc *desc)
+@@ -200,23 +204,17 @@ static inline void pci_msix_unmask(struct msi_desc *desc)
+
+ static void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
+ {
+- if (pci_msi_ignore_mask || desc->msi_attrib.is_virtual)
+- return;
+-
+ if (desc->msi_attrib.is_msix)
+ pci_msix_mask(desc);
+- else if (desc->msi_attrib.maskbit)
++ else
+ pci_msi_mask(desc, mask);
+ }
+
+ static void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
+ {
+- if (pci_msi_ignore_mask || desc->msi_attrib.is_virtual)
+- return;
+-
+ if (desc->msi_attrib.is_msix)
+ pci_msix_unmask(desc);
+- else if (desc->msi_attrib.maskbit)
++ else
+ pci_msi_unmask(desc, mask);
+ }
+
+@@ -370,6 +368,11 @@ static void free_msi_irqs(struct pci_dev *dev)
+ for (i = 0; i < entry->nvec_used; i++)
+ BUG_ON(irq_has_action(entry->irq + i));
+
++ if (dev->msi_irq_groups) {
++ msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
++ dev->msi_irq_groups = NULL;
++ }
++
+ pci_msi_teardown_msi_irqs(dev);
+
+ list_for_each_entry_safe(entry, tmp, msi_list, list) {
+@@ -381,11 +384,6 @@ static void free_msi_irqs(struct pci_dev *dev)
+ list_del(&entry->list);
+ free_msi_entry(entry);
+ }
+-
+- if (dev->msi_irq_groups) {
+- msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
+- dev->msi_irq_groups = NULL;
+- }
+ }
+
+ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
+@@ -479,12 +477,16 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
+ goto out;
+
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
++ /* Lies, damned lies, and MSIs */
++ if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
++ control |= PCI_MSI_FLAGS_MASKBIT;
+
+ entry->msi_attrib.is_msix = 0;
+ entry->msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
+ entry->msi_attrib.is_virtual = 0;
+ entry->msi_attrib.entry_nr = 0;
+- entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT);
++ entry->msi_attrib.can_mask = !pci_msi_ignore_mask &&
++ !!(control & PCI_MSI_FLAGS_MASKBIT);
+ entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
+ entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
+ entry->msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
+@@ -495,7 +497,7 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
+ entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+
+ /* Save the initial mask status */
+- if (entry->msi_attrib.maskbit)
++ if (entry->msi_attrib.can_mask)
+ pci_read_config_dword(dev, entry->mask_pos, &entry->msi_mask);
+
+ out:
+@@ -638,10 +640,13 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
+ entry->msi_attrib.is_virtual =
+ entry->msi_attrib.entry_nr >= vec_count;
+
++ entry->msi_attrib.can_mask = !pci_msi_ignore_mask &&
++ !entry->msi_attrib.is_virtual;
++
+ entry->msi_attrib.default_irq = dev->irq;
+ entry->mask_base = base;
+
+- if (!entry->msi_attrib.is_virtual) {
++ if (entry->msi_attrib.can_mask) {
+ addr = pci_msix_desc_addr(entry);
+ entry->msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
+ }
+@@ -716,9 +721,6 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
+ goto out_disable;
+ }
+
+- /* Ensure that all table entries are masked. */
+- msix_mask_all(base, tsize);
+-
+ ret = msix_setup_entries(dev, base, entries, nvec, affd);
+ if (ret)
+ goto out_disable;
+@@ -745,6 +747,16 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
+ /* Set MSI-X enabled bits and unmask the function */
+ pci_intx_for_msi(dev, 0);
+ dev->msix_enabled = 1;
++
++ /*
++ * Ensure that all table entries are masked to prevent
++ * stale entries from firing in a crash kernel.
++ *
++ * Done late to deal with a broken Marvell NVME device
++ * which takes the MSI-X mask bits into account even
++ * when MSI-X is disabled, which prevents MSI delivery.
++ */
++ msix_mask_all(base, tsize);
+ pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
+
+ pcibios_free_irq(dev);
+@@ -771,7 +783,7 @@ out_free:
+ free_msi_irqs(dev);
+
+ out_disable:
+- pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
++ pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE, 0);
+
+ return ret;
+ }
+diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
+index fdaf86a888b73..db97cddfc85e1 100644
+--- a/drivers/pci/pci-bridge-emul.c
++++ b/drivers/pci/pci-bridge-emul.c
+@@ -431,8 +431,21 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
+ /* Clear the W1C bits */
+ new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
+
++ /* Save the new value with the cleared W1C bits into the cfgspace */
+ cfgspace[reg / 4] = cpu_to_le32(new);
+
++ /*
++ * Clear the W1C bits not specified by the write mask, so that the
++ * write_op() does not clear them.
++ */
++ new &= ~(behavior[reg / 4].w1c & ~mask);
++
++ /*
++ * Set the W1C bits specified by the write mask, so that write_op()
++ * knows about that they are to be cleared.
++ */
++ new |= (value << shift) & (behavior[reg / 4].w1c & mask);
++
+ if (write_op)
+ write_op(bridge, reg, old, new, mask);
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index ce2ab62b64cfa..a101faf3e88a9 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -3719,6 +3719,14 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
+ struct pci_dev *bridge;
+ u32 cap, ctl2;
+
++ /*
++ * Per PCIe r5.0, sec 9.3.5.10, the AtomicOp Requester Enable bit
++ * in Device Control 2 is reserved in VFs and the PF value applies
++ * to all associated VFs.
++ */
++ if (dev->is_virtfn)
++ return -EINVAL;
++
+ if (!pci_is_pcie(dev))
+ return -EINVAL;
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 4537d1ea14fdc..208fa03acdda0 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -3612,6 +3612,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset);
+
+ /*
+ * Root port on some Cavium CN8xxx chips do not successfully complete a bus
+@@ -5795,3 +5796,9 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
+ }
+ DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
+ PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
++
++static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
++{
++ pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING;
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0ab8, nvidia_ion_ahci_fixup);
+diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c
+index 4076580fc2cd9..ab1b0986aa671 100644
+--- a/drivers/phy/microchip/sparx5_serdes.c
++++ b/drivers/phy/microchip/sparx5_serdes.c
+@@ -2475,10 +2475,10 @@ static int sparx5_serdes_probe(struct platform_device *pdev)
+ return -EINVAL;
+ }
+ iomem = devm_ioremap(priv->dev, iores->start, resource_size(iores));
+- if (IS_ERR(iomem)) {
++ if (!iomem) {
+ dev_err(priv->dev, "Unable to get serdes registers: %s\n",
+ iores->name);
+- return PTR_ERR(iomem);
++ return -ENOMEM;
+ }
+ for (idx = 0; idx < ARRAY_SIZE(sparx5_serdes_iomap); idx++) {
+ struct sparx5_serdes_io_resource *iomap = &sparx5_serdes_iomap[idx];
+diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
+index f14032170b1c1..06b04606dd7ea 100644
+--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
++++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
+@@ -3632,7 +3632,7 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
+ .nlanes = 1,
+
+ .serdes_tbl = sc8180x_qmp_pcie_serdes_tbl,
+- .serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
++ .serdes_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_serdes_tbl),
+ .tx_tbl = sc8180x_qmp_pcie_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl),
+ .rx_tbl = sc8180x_qmp_pcie_rx_tbl,
+diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
+index 3c1d3b71c825b..f1d97fbd13318 100644
+--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
++++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
+@@ -561,7 +561,7 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
+ {
+ struct device *dev = &qphy->phy->dev;
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
+- u8 *val;
++ u8 *val, hstx_trim;
+
+ /* efuse register is optional */
+ if (!qphy->cell)
+@@ -575,7 +575,13 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
+ * set while configuring the phy.
+ */
+ val = nvmem_cell_read(qphy->cell, NULL);
+- if (IS_ERR(val) || !val[0]) {
++ if (IS_ERR(val)) {
++ dev_dbg(dev, "failed to read a valid hs-tx trim value\n");
++ return;
++ }
++ hstx_trim = val[0];
++ kfree(val);
++ if (!hstx_trim) {
+ dev_dbg(dev, "failed to read a valid hs-tx trim value\n");
+ return;
+ }
+@@ -583,12 +589,10 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
+ /* Fused TUNE1/2 value is the higher nibble only */
+ if (cfg->update_tune1_with_efuse)
+ qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
+- val[0] << HSTX_TRIM_SHIFT,
+- HSTX_TRIM_MASK);
++ hstx_trim << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK);
+ else
+ qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],
+- val[0] << HSTX_TRIM_SHIFT,
+- HSTX_TRIM_MASK);
++ hstx_trim << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK);
+ }
+
+ static int qusb2_phy_set_mode(struct phy *phy,
+diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
+index ae4bac024c7b1..7e61202aa234e 100644
+--- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
++++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
+@@ -33,7 +33,7 @@
+
+ #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
+ #define RETENABLEN BIT(3)
+-#define FSEL_MASK GENMASK(7, 5)
++#define FSEL_MASK GENMASK(6, 4)
+ #define FSEL_DEFAULT (0x3 << 4)
+
+ #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1 (0x58)
+diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
+index 5fd2e8a08bfcf..d0ab69750c6b4 100644
+--- a/drivers/phy/ti/phy-gmii-sel.c
++++ b/drivers/phy/ti/phy-gmii-sel.c
+@@ -320,6 +320,8 @@ static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
+ u64 size;
+
+ offset = of_get_address(dev->of_node, 0, &size, NULL);
++ if (!offset)
++ return -EINVAL;
+ priv->num_ports = size / sizeof(u32);
+ if (!priv->num_ports)
+ return -EINVAL;
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 5082102d7d0d9..ffe39336fcaca 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -2100,6 +2100,8 @@ int pinctrl_enable(struct pinctrl_dev *pctldev)
+ if (error) {
+ dev_err(pctldev->dev, "could not claim hogs: %i\n",
+ error);
++ pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
++ pctldev->desc->npins);
+ mutex_destroy(&pctldev->mutex);
+ kfree(pctldev);
+
+diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
+index bae9d429b813e..ecab9064a8458 100644
+--- a/drivers/pinctrl/pinctrl-amd.c
++++ b/drivers/pinctrl/pinctrl-amd.c
+@@ -598,14 +598,14 @@ static struct irq_chip amd_gpio_irqchip = {
+
+ #define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
+
+-static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
++static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
+ {
+ struct amd_gpio *gpio_dev = dev_id;
+ struct gpio_chip *gc = &gpio_dev->gc;
+- irqreturn_t ret = IRQ_NONE;
+ unsigned int i, irqnr;
+ unsigned long flags;
+ u32 __iomem *regs;
++ bool ret = false;
+ u32 regval;
+ u64 status, mask;
+
+@@ -627,6 +627,14 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
+ /* Each status bit covers four pins */
+ for (i = 0; i < 4; i++) {
+ regval = readl(regs + i);
++ /* caused wake on resume context for shared IRQ */
++ if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) {
++ dev_dbg(&gpio_dev->pdev->dev,
++ "Waking due to GPIO %d: 0x%x",
++ irqnr + i, regval);
++ return true;
++ }
++
+ if (!(regval & PIN_IRQ_PENDING) ||
+ !(regval & BIT(INTERRUPT_MASK_OFF)))
+ continue;
+@@ -650,9 +658,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
+ }
+ writel(regval, regs + i);
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+- ret = IRQ_HANDLED;
++ ret = true;
+ }
+ }
++ /* did not cause wake on resume context for shared IRQ */
++ if (irq < 0)
++ return false;
+
+ /* Signal EOI to the GPIO unit */
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+@@ -664,6 +675,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
+ return ret;
+ }
+
++static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
++{
++ return IRQ_RETVAL(do_amd_gpio_irq_handler(irq, dev_id));
++}
++
++static bool __maybe_unused amd_gpio_check_wake(void *dev_id)
++{
++ return do_amd_gpio_irq_handler(-1, dev_id);
++}
++
+ static int amd_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+ struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev);
+@@ -1033,6 +1054,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
+ goto out2;
+
+ platform_set_drvdata(pdev, gpio_dev);
++ acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev);
+
+ dev_dbg(&pdev->dev, "amd gpio driver loaded\n");
+ return ret;
+@@ -1050,6 +1072,7 @@ static int amd_gpio_remove(struct platform_device *pdev)
+ gpio_dev = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&gpio_dev->gc);
++ acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev);
+
+ return 0;
+ }
+diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
+index fb713f9c53d0e..3f0143087cc77 100644
+--- a/drivers/pinctrl/pinctrl-equilibrium.c
++++ b/drivers/pinctrl/pinctrl-equilibrium.c
+@@ -675,6 +675,11 @@ static int eqbr_build_functions(struct eqbr_pinctrl_drv_data *drvdata)
+ return ret;
+
+ for (i = 0; i < nr_funcs; i++) {
++
++ /* Ignore the same function with multiple groups */
++ if (funcs[i].name == NULL)
++ continue;
++
+ ret = pinmux_generic_add_function(drvdata->pctl_dev,
+ funcs[i].name,
+ funcs[i].groups,
+@@ -815,7 +820,7 @@ static int pinctrl_reg(struct eqbr_pinctrl_drv_data *drvdata)
+
+ ret = eqbr_build_functions(drvdata);
+ if (ret) {
+- dev_err(dev, "Failed to build groups\n");
++ dev_err(dev, "Failed to build functions\n");
+ return ret;
+ }
+
+diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
+index 5ff4207df66e1..f1b5176a5085b 100644
+--- a/drivers/pinctrl/qcom/Kconfig
++++ b/drivers/pinctrl/qcom/Kconfig
+@@ -189,6 +189,7 @@ config PINCTRL_QCOM_SPMI_PMIC
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
++ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select IRQ_DOMAIN_HIERARCHY
+ help
+@@ -203,6 +204,7 @@ config PINCTRL_QCOM_SSBI_PMIC
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
++ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select IRQ_DOMAIN_HIERARCHY
+ help
+diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
+index c51793f6546f1..fdfd7b8f3a76d 100644
+--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
++++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
+@@ -1310,6 +1310,7 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
+ .ngpios = 151,
+ .wakeirq_map = sdm845_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(sdm845_pdc_map),
++ .wakeirq_dual_edge_errata = true,
+ };
+
+ static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
+diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350.c b/drivers/pinctrl/qcom/pinctrl-sm8350.c
+index 4d8f8636c2b39..1c042d39380c6 100644
+--- a/drivers/pinctrl/qcom/pinctrl-sm8350.c
++++ b/drivers/pinctrl/qcom/pinctrl-sm8350.c
+@@ -1597,10 +1597,10 @@ static const struct msm_pingroup sm8350_groups[] = {
+ [200] = PINGROUP(200, qdss_gpio, _, _, _, _, _, _, _, _),
+ [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _),
+ [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _),
+- [203] = UFS_RESET(ufs_reset, 0x1d8000),
+- [204] = SDC_PINGROUP(sdc2_clk, 0x1cf000, 14, 6),
+- [205] = SDC_PINGROUP(sdc2_cmd, 0x1cf000, 11, 3),
+- [206] = SDC_PINGROUP(sdc2_data, 0x1cf000, 9, 0),
++ [203] = UFS_RESET(ufs_reset, 0xd8000),
++ [204] = SDC_PINGROUP(sdc2_clk, 0xcf000, 14, 6),
++ [205] = SDC_PINGROUP(sdc2_cmd, 0xcf000, 11, 3),
++ [206] = SDC_PINGROUP(sdc2_data, 0xcf000, 9, 0),
+ };
+
+ static const struct msm_gpio_wakeirq_map sm8350_pdc_map[] = {
+diff --git a/drivers/pinctrl/ralink/pinctrl-mt7620.c b/drivers/pinctrl/ralink/pinctrl-mt7620.c
+index 425d55a2ee19f..6853b5b8b0fe7 100644
+--- a/drivers/pinctrl/ralink/pinctrl-mt7620.c
++++ b/drivers/pinctrl/ralink/pinctrl-mt7620.c
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+
++#include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7620.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c
+index f2ab02225837e..f29130957e49a 100644
+--- a/drivers/pinctrl/renesas/core.c
++++ b/drivers/pinctrl/renesas/core.c
+@@ -890,7 +890,7 @@ static void __init sh_pfc_check_drive_reg(const struct sh_pfc_soc_info *info,
+ if (!field->pin && !field->offset && !field->size)
+ continue;
+
+- mask = GENMASK(field->offset + field->size, field->offset);
++ mask = GENMASK(field->offset + field->size - 1, field->offset);
+ if (mask & seen)
+ sh_pfc_err("drive_reg 0x%x: field %u overlap\n",
+ drive->reg, i);
+diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+index dbf2f521bb272..20b2af889ca96 100644
+--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+@@ -852,7 +852,7 @@ static const u32 rzg2l_gpio_configs[] = {
+ RZG2L_GPIO_PORT_PACK(2, 0x1e, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1f, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x20, RZG2L_MPXED_PIN_FUNCS),
+- RZG2L_GPIO_PORT_PACK(3, 0x22, RZG2L_MPXED_PIN_FUNCS),
++ RZG2L_GPIO_PORT_PACK(3, 0x21, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x22, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x23, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_ETH0)),
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
+index 4428c4330229a..1679811eff502 100644
+--- a/drivers/platform/surface/surface_aggregator_registry.c
++++ b/drivers/platform/surface/surface_aggregator_registry.c
+@@ -77,6 +77,42 @@ static const struct software_node ssam_node_bas_dtx = {
+ .parent = &ssam_node_root,
+ };
+
++/* HID keyboard (TID1). */
++static const struct software_node ssam_node_hid_tid1_keyboard = {
++ .name = "ssam:01:15:01:01:00",
++ .parent = &ssam_node_root,
++};
++
++/* HID pen stash (TID1; pen taken / stashed away evens). */
++static const struct software_node ssam_node_hid_tid1_penstash = {
++ .name = "ssam:01:15:01:02:00",
++ .parent = &ssam_node_root,
++};
++
++/* HID touchpad (TID1). */
++static const struct software_node ssam_node_hid_tid1_touchpad = {
++ .name = "ssam:01:15:01:03:00",
++ .parent = &ssam_node_root,
++};
++
++/* HID device instance 6 (TID1, unknown HID device). */
++static const struct software_node ssam_node_hid_tid1_iid6 = {
++ .name = "ssam:01:15:01:06:00",
++ .parent = &ssam_node_root,
++};
++
++/* HID device instance 7 (TID1, unknown HID device). */
++static const struct software_node ssam_node_hid_tid1_iid7 = {
++ .name = "ssam:01:15:01:07:00",
++ .parent = &ssam_node_root,
++};
++
++/* HID system controls (TID1). */
++static const struct software_node ssam_node_hid_tid1_sysctrl = {
++ .name = "ssam:01:15:01:08:00",
++ .parent = &ssam_node_root,
++};
++
+ /* HID keyboard. */
+ static const struct software_node ssam_node_hid_main_keyboard = {
+ .name = "ssam:01:15:02:01:00",
+@@ -159,6 +195,21 @@ static const struct software_node *ssam_node_group_sl3[] = {
+ NULL,
+ };
+
++/* Devices for Surface Laptop Studio. */
++static const struct software_node *ssam_node_group_sls[] = {
++ &ssam_node_root,
++ &ssam_node_bat_ac,
++ &ssam_node_bat_main,
++ &ssam_node_tmp_pprof,
++ &ssam_node_hid_tid1_keyboard,
++ &ssam_node_hid_tid1_penstash,
++ &ssam_node_hid_tid1_touchpad,
++ &ssam_node_hid_tid1_iid6,
++ &ssam_node_hid_tid1_iid7,
++ &ssam_node_hid_tid1_sysctrl,
++ NULL,
++};
++
+ /* Devices for Surface Laptop Go. */
+ static const struct software_node *ssam_node_group_slg1[] = {
+ &ssam_node_root,
+@@ -507,6 +558,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
+ /* Surface Laptop Go 1 */
+ { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
+
++ /* Surface Laptop Studio */
++ { "MSHW0123", (unsigned long)ssam_node_group_sls },
++
+ { },
+ };
+ MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
+diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c
+index fc95620101e85..54b88bedecdf1 100644
+--- a/drivers/platform/x86/amd-pmc.c
++++ b/drivers/platform/x86/amd-pmc.c
+@@ -70,7 +70,7 @@
+ #define AMD_CPU_ID_CZN AMD_CPU_ID_RN
+ #define AMD_CPU_ID_YC 0x14B5
+
+-#define PMC_MSG_DELAY_MIN_US 100
++#define PMC_MSG_DELAY_MIN_US 50
+ #define RESPONSE_REGISTER_LOOP_MAX 20000
+
+ #define SOC_SUBSYSTEM_IP_MAX 12
+diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
+index 2fffa57e596e4..fe224a54f24c0 100644
+--- a/drivers/platform/x86/dell/Kconfig
++++ b/drivers/platform/x86/dell/Kconfig
+@@ -187,7 +187,7 @@ config DELL_WMI_AIO
+
+ config DELL_WMI_DESCRIPTOR
+ tristate
+- default m
++ default n
+ depends on ACPI_WMI
+
+ config DELL_WMI_LED
+diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
+index cc53f725c0419..ef24f53753c6e 100644
+--- a/drivers/platform/x86/hp_accel.c
++++ b/drivers/platform/x86/hp_accel.c
+@@ -331,9 +331,11 @@ static int lis3lv02d_probe(struct platform_device *device)
+ INIT_WORK(&hpled_led.work, delayed_set_status_worker);
+ ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+ if (ret) {
++ i8042_remove_filter(hp_accel_i8042_filter);
+ lis3lv02d_joystick_disable(&lis3_dev);
+ lis3lv02d_poweroff(&lis3_dev);
+ flush_work(&hpled_led.work);
++ lis3lv02d_remove_fs(&lis3_dev);
+ return ret;
+ }
+
+diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
+index 08598942a6d78..13f8cf70b9aee 100644
+--- a/drivers/platform/x86/intel/hid.c
++++ b/drivers/platform/x86/intel/hid.c
+@@ -99,6 +99,13 @@ static const struct dmi_system_id button_array_table[] = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Tablet Gen 2"),
+ },
+ },
++ {
++ .ident = "Microsoft Surface Go 3",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
++ },
++ },
+ { }
+ };
+
+diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
+index 9472aae72df29..c4d9c45350f7c 100644
+--- a/drivers/platform/x86/think-lmi.c
++++ b/drivers/platform/x86/think-lmi.c
+@@ -888,8 +888,10 @@ static int tlmi_analyze(void)
+ break;
+ if (!item)
+ break;
+- if (!*item)
++ if (!*item) {
++ kfree(item);
+ continue;
++ }
+
+ /* It is not allowed to have '/' for file name. Convert it into '\'. */
+ strreplace(item, '/', '\\');
+@@ -902,6 +904,7 @@ static int tlmi_analyze(void)
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (!setting) {
+ ret = -ENOMEM;
++ kfree(item);
+ goto fail_clear_attr;
+ }
+ setting->index = i;
+@@ -916,7 +919,6 @@ static int tlmi_analyze(void)
+ }
+ kobject_init(&setting->kobj, &tlmi_attr_setting_ktype);
+ tlmi_priv.setting[i] = setting;
+- tlmi_priv.settings_count++;
+ kfree(item);
+ }
+
+@@ -983,7 +985,12 @@ static void tlmi_remove(struct wmi_device *wdev)
+
+ static int tlmi_probe(struct wmi_device *wdev, const void *context)
+ {
+- tlmi_analyze();
++ int ret;
++
++ ret = tlmi_analyze();
++ if (ret)
++ return ret;
++
+ return tlmi_sysfs_init();
+ }
+
+diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
+index f8e26823075fd..2ce5086a5af27 100644
+--- a/drivers/platform/x86/think-lmi.h
++++ b/drivers/platform/x86/think-lmi.h
+@@ -55,7 +55,6 @@ struct tlmi_attr_setting {
+ struct think_lmi {
+ struct wmi_device *wmi_device;
+
+- int settings_count;
+ bool can_set_bios_settings;
+ bool can_get_bios_selections;
+ bool can_set_bios_password;
+diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
+index 50ff04c84650c..3dc055ce6e61b 100644
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -1178,15 +1178,6 @@ static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk)
+ return status;
+ }
+
+-/* Query FW and update rfkill sw state for all rfkill switches */
+-static void tpacpi_rfk_update_swstate_all(void)
+-{
+- unsigned int i;
+-
+- for (i = 0; i < TPACPI_RFK_SW_MAX; i++)
+- tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]);
+-}
+-
+ /*
+ * Sync the HW-blocking state of all rfkill switches,
+ * do notice it causes the rfkill core to schedule uevents
+@@ -3129,9 +3120,6 @@ static void tpacpi_send_radiosw_update(void)
+ if (wlsw == TPACPI_RFK_RADIO_OFF)
+ tpacpi_rfk_update_hwblock_state(true);
+
+- /* Sync sw blocking state */
+- tpacpi_rfk_update_swstate_all();
+-
+ /* Sync hw blocking state last if it is hw-unblocked */
+ if (wlsw == TPACPI_RFK_RADIO_ON)
+ tpacpi_rfk_update_hwblock_state(false);
+@@ -8853,6 +8841,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
+ TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (1st gen) */
+ TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */
+ TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (3nd gen) */
++ TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (4nd gen) */
+ TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */
+ TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL), /* X1 Carbon (9th gen) */
+ };
+@@ -9145,7 +9134,7 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
+
+ if (strlencmp(cmd, "level auto") == 0)
+ level = TP_EC_FAN_AUTO;
+- else if ((strlencmp(cmd, "level disengaged") == 0) |
++ else if ((strlencmp(cmd, "level disengaged") == 0) ||
+ (strlencmp(cmd, "level full-speed") == 0))
+ level = TP_EC_FAN_FULLSPEED;
+ else if (sscanf(cmd, "level %d", &level) != 1)
+diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
+index a76313006bdc4..1b65bb61ce888 100644
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -353,7 +353,14 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
+ * the WQxx method failed - we should disable collection anyway.
+ */
+ if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
+- status = acpi_execute_simple_method(handle, wc_method, 0);
++ /*
++ * Ignore whether this WCxx call succeeds or not since
++ * the previously executed WQxx method call might have
++ * succeeded, and returning the failing status code
++ * of this call would throw away the result of the WQxx
++ * call, potentially leaking memory.
++ */
++ acpi_execute_simple_method(handle, wc_method, 0);
+ }
+
+ return status;
+diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
+index 026649409135c..64def79d557a8 100644
+--- a/drivers/power/reset/at91-reset.c
++++ b/drivers/power/reset/at91-reset.c
+@@ -193,7 +193,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ reset->rstc_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
+- if (!reset->rstc_base) {
++ if (IS_ERR(reset->rstc_base)) {
+ dev_err(&pdev->dev, "Could not map reset controller address\n");
+ return -ENODEV;
+ }
+@@ -203,7 +203,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
+ for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
+ reset->ramc_lpr = (u32)match->data;
+ reset->ramc_base[idx] = devm_of_iomap(&pdev->dev, np, 0, NULL);
+- if (!reset->ramc_base[idx]) {
++ if (IS_ERR(reset->ramc_base[idx])) {
+ dev_err(&pdev->dev, "Could not map ram controller address\n");
+ of_node_put(np);
+ return -ENODEV;
+diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
+index 46f078350fd3f..cf38cbfe13e9d 100644
+--- a/drivers/power/supply/bq27xxx_battery_i2c.c
++++ b/drivers/power/supply/bq27xxx_battery_i2c.c
+@@ -187,7 +187,8 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
+ dev_err(&client->dev,
+ "Unable to register IRQ %d error %d\n",
+ client->irq, ret);
+- return ret;
++ bq27xxx_battery_teardown(di);
++ goto err_failed;
+ }
+ }
+
+diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
+index 3cea92e28dc3e..a9aef1e8b186e 100644
+--- a/drivers/power/supply/max17040_battery.c
++++ b/drivers/power/supply/max17040_battery.c
+@@ -449,6 +449,8 @@ static int max17040_probe(struct i2c_client *client,
+
+ chip->client = client;
+ chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
++ if (IS_ERR(chip->regmap))
++ return PTR_ERR(chip->regmap);
+ chip_id = (enum chip_id) id->driver_data;
+ if (client->dev.of_node) {
+ ret = max17040_get_of_data(chip);
+diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
+index 8dffae76b6a31..aaf6f1bd3d298 100644
+--- a/drivers/power/supply/max17042_battery.c
++++ b/drivers/power/supply/max17042_battery.c
+@@ -313,7 +313,10 @@ static int max17042_get_property(struct power_supply *psy,
+ val->intval = data * 625 / 8;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+- ret = regmap_read(map, MAX17042_RepSOC, &data);
++ if (chip->pdata->enable_current_sense)
++ ret = regmap_read(map, MAX17042_RepSOC, &data);
++ else
++ ret = regmap_read(map, MAX17042_VFSOC, &data);
+ if (ret < 0)
+ return ret;
+
+@@ -857,7 +860,8 @@ static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
+ regmap_read(map, MAX17042_RepSOC, &soc);
+ soc >>= 8;
+ soc_tr = (soc + off) << 8;
+- soc_tr |= (soc - off);
++ if (off < soc)
++ soc_tr |= soc - off;
+ regmap_write(map, MAX17042_SALRT_Th, soc_tr);
+ }
+
+@@ -876,6 +880,10 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
+ max17042_set_soc_threshold(chip, 1);
+ }
+
++ /* we implicitly handle all alerts via power_supply_changed */
++ regmap_clear_bits(chip->regmap, MAX17042_STATUS,
++ 0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT));
++
+ power_supply_changed(chip->battery);
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
+index 9ad0afe83d1b7..7a23c70f48791 100644
+--- a/drivers/power/supply/rt5033_battery.c
++++ b/drivers/power/supply/rt5033_battery.c
+@@ -60,7 +60,7 @@ static int rt5033_battery_get_watt_prop(struct i2c_client *client,
+ regmap_read(battery->regmap, regh, &msb);
+ regmap_read(battery->regmap, regl, &lsb);
+
+- ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000;
++ ret = ((msb << 4) + (lsb >> 4)) * 1250;
+
+ return ret;
+ }
+diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
+index caf9b37c5eb1e..e238ae8e94709 100644
+--- a/drivers/ptp/ptp_ocp.c
++++ b/drivers/ptp/ptp_ocp.c
+@@ -1049,10 +1049,11 @@ ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r)
+ if (!ext)
+ return -ENOMEM;
+
+- err = -EINVAL;
+ ext->mem = ptp_ocp_get_mem(bp, r);
+- if (!ext->mem)
++ if (IS_ERR(ext->mem)) {
++ err = PTR_ERR(ext->mem);
+ goto out;
++ }
+
+ ext->bp = bp;
+ ext->info = r->extra;
+@@ -1122,8 +1123,8 @@ ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r)
+ void __iomem *mem;
+
+ mem = ptp_ocp_get_mem(bp, r);
+- if (!mem)
+- return -EINVAL;
++ if (IS_ERR(mem))
++ return PTR_ERR(mem);
+
+ bp_assign_entry(bp, r, mem);
+
+diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
+index 7c111bbdc2afa..35269f9982105 100644
+--- a/drivers/regulator/s5m8767.c
++++ b/drivers/regulator/s5m8767.c
+@@ -850,18 +850,15 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
+ /* DS4 GPIO */
+ gpio_direction_output(pdata->buck_ds[2], 0x0);
+
+- if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+- pdata->buck4_gpiodvs) {
+- regmap_update_bits(s5m8767->iodev->regmap_pmic,
+- S5M8767_REG_BUCK2CTRL, 1 << 1,
+- (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1));
+- regmap_update_bits(s5m8767->iodev->regmap_pmic,
+- S5M8767_REG_BUCK3CTRL, 1 << 1,
+- (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1));
+- regmap_update_bits(s5m8767->iodev->regmap_pmic,
+- S5M8767_REG_BUCK4CTRL, 1 << 1,
+- (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1));
+- }
++ regmap_update_bits(s5m8767->iodev->regmap_pmic,
++ S5M8767_REG_BUCK2CTRL, 1 << 1,
++ (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1));
++ regmap_update_bits(s5m8767->iodev->regmap_pmic,
++ S5M8767_REG_BUCK3CTRL, 1 << 1,
++ (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1));
++ regmap_update_bits(s5m8767->iodev->regmap_pmic,
++ S5M8767_REG_BUCK4CTRL, 1 << 1,
++ (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1));
+
+ /* Initialize GPIO DVS registers */
+ for (i = 0; i < 8; i++) {
+diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
+index d88f76f5305eb..ff620688fad94 100644
+--- a/drivers/remoteproc/imx_rproc.c
++++ b/drivers/remoteproc/imx_rproc.c
+@@ -71,6 +71,7 @@ struct imx_rproc_mem {
+ /* att flags */
+ /* M4 own area. Can be mapped at probe */
+ #define ATT_OWN BIT(1)
++#define ATT_IOMEM BIT(2)
+
+ /* address translation table */
+ struct imx_rproc_att {
+@@ -117,7 +118,7 @@ struct imx_rproc {
+ static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ /* dev addr , sys addr , size , flags */
+ /* ITCM */
+- { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN },
++ { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00009000, 0 },
+ /* OCRAM */
+@@ -131,7 +132,7 @@ static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* DTCM */
+- { 0x20000000, 0x00800000, 0x00020000, ATT_OWN },
++ { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S - alias */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+@@ -147,7 +148,7 @@ static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCML - alias */
+- { 0x00000000, 0x007e0000, 0x00020000, 0 },
++ { 0x00000000, 0x007e0000, 0x00020000, ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00008000, 0 },
+ /* OCRAM */
+@@ -159,9 +160,9 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x80000000, 0x0FFE0000, 0 },
+ /* TCML */
+- { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN },
++ { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM},
+ /* TCMU */
+- { 0x20000000, 0x00800000, 0x00020000, ATT_OWN },
++ { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+@@ -199,12 +200,12 @@ static const struct imx_rproc_att imx_rproc_att_imx7d[] = {
+ /* OCRAM_PXP (Code) - alias */
+ { 0x00940000, 0x00940000, 0x00008000, 0 },
+ /* TCML (Code) */
+- { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
++ { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN | ATT_IOMEM },
+ /* DDR (Code) - alias, first part of DDR (Data) */
+ { 0x10000000, 0x80000000, 0x0FFF0000, 0 },
+
+ /* TCMU (Data) */
+- { 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
++ { 0x20000000, 0x00800000, 0x00008000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM (Data) */
+ { 0x20200000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM_EPDC (Data) */
+@@ -218,18 +219,18 @@ static const struct imx_rproc_att imx_rproc_att_imx7d[] = {
+ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCML (M4 Boot Code) - alias */
+- { 0x00000000, 0x007F8000, 0x00008000, 0 },
++ { 0x00000000, 0x007F8000, 0x00008000, ATT_IOMEM },
+ /* OCRAM_S (Code) */
+ { 0x00180000, 0x008F8000, 0x00004000, 0 },
+ /* OCRAM_S (Code) - alias */
+ { 0x00180000, 0x008FC000, 0x00004000, 0 },
+ /* TCML (Code) */
+- { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN },
++ { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN | ATT_IOMEM },
+ /* DDR (Code) - alias, first part of DDR (Data) */
+ { 0x10000000, 0x80000000, 0x0FFF8000, 0 },
+
+ /* TCMU (Data) */
+- { 0x20000000, 0x00800000, 0x00008000, ATT_OWN },
++ { 0x20000000, 0x00800000, 0x00008000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S (Data) - alias? */
+ { 0x208F8000, 0x008F8000, 0x00004000, 0 },
+ /* DDR (Data) */
+@@ -341,7 +342,7 @@ static int imx_rproc_stop(struct rproc *rproc)
+ }
+
+ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
+- size_t len, u64 *sys)
++ size_t len, u64 *sys, bool *is_iomem)
+ {
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int i;
+@@ -354,6 +355,8 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
+ unsigned int offset = da - att->da;
+
+ *sys = att->sa + offset;
++ if (is_iomem)
++ *is_iomem = att->flags & ATT_IOMEM;
+ return 0;
+ }
+ }
+@@ -377,7 +380,7 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i
+ * On device side we have many aliases, so we need to convert device
+ * address (M4) to system bus address first.
+ */
+- if (imx_rproc_da_to_sys(priv, da, len, &sys))
++ if (imx_rproc_da_to_sys(priv, da, len, &sys, is_iomem))
+ return NULL;
+
+ for (i = 0; i < IMX_RPROC_MEM_MAX; i++) {
+@@ -553,8 +556,12 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
+ if (b >= IMX_RPROC_MEM_MAX)
+ break;
+
+- priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev,
+- att->sa, att->size);
++ if (att->flags & ATT_IOMEM)
++ priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev,
++ att->sa, att->size);
++ else
++ priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev,
++ att->sa, att->size);
+ if (!priv->mem[b].cpu_addr) {
+ dev_err(dev, "failed to remap %#x bytes from %#x\n", att->size, att->sa);
+ return -ENOMEM;
+@@ -575,8 +582,8 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
+ struct resource res;
+
+ node = of_parse_phandle(np, "memory-region", a);
+- /* Not map vdev region */
+- if (!strcmp(node->name, "vdev"))
++ /* Not map vdevbuffer, vdevring region */
++ if (!strncmp(node->name, "vdev", strlen("vdev")))
+ continue;
+ err = of_address_to_resource(node, 0, &res);
+ if (err) {
+@@ -597,7 +604,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
+ }
+ priv->mem[b].sys_addr = res.start;
+ priv->mem[b].size = resource_size(&res);
+- if (!strcmp(node->name, "rsc_table"))
++ if (!strcmp(node->name, "rsc-table"))
+ priv->rsc_table = priv->mem[b].cpu_addr;
+ b++;
+ }
+diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
+index 502b6604b757b..775df165eb450 100644
+--- a/drivers/remoteproc/remoteproc_core.c
++++ b/drivers/remoteproc/remoteproc_core.c
+@@ -556,9 +556,6 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
+ /* Initialise vdev subdevice */
+ snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);
+ rvdev->dev.parent = &rproc->dev;
+- ret = copy_dma_range_map(&rvdev->dev, rproc->dev.parent);
+- if (ret)
+- return ret;
+ rvdev->dev.release = rproc_rvdev_release;
+ dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);
+ dev_set_drvdata(&rvdev->dev, rvdev);
+@@ -568,6 +565,11 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
+ put_device(&rvdev->dev);
+ return ret;
+ }
++
++ ret = copy_dma_range_map(&rvdev->dev, rproc->dev.parent);
++ if (ret)
++ goto free_rvdev;
++
+ /* Make device dma capable by inheriting from parent's capabilities */
+ set_dma_ops(&rvdev->dev, get_dma_ops(rproc->dev.parent));
+
+diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c
+index aee657cc08c6a..c892f433a323e 100644
+--- a/drivers/remoteproc/remoteproc_coredump.c
++++ b/drivers/remoteproc/remoteproc_coredump.c
+@@ -152,8 +152,8 @@ static void rproc_copy_segment(struct rproc *rproc, void *dest,
+ struct rproc_dump_segment *segment,
+ size_t offset, size_t size)
+ {
++ bool is_iomem = false;
+ void *ptr;
+- bool is_iomem;
+
+ if (segment->dump) {
+ segment->dump(rproc, segment, dest, offset, size);
+diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
+index 469c52e62faff..d635d19a5aa8a 100644
+--- a/drivers/remoteproc/remoteproc_elf_loader.c
++++ b/drivers/remoteproc/remoteproc_elf_loader.c
+@@ -178,8 +178,8 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
+ u64 filesz = elf_phdr_get_p_filesz(class, phdr);
+ u64 offset = elf_phdr_get_p_offset(class, phdr);
+ u32 type = elf_phdr_get_p_type(class, phdr);
++ bool is_iomem = false;
+ void *ptr;
+- bool is_iomem;
+
+ if (type != PT_LOAD)
+ continue;
+@@ -220,7 +220,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
+ /* put the segment where the remote processor expects it */
+ if (filesz) {
+ if (is_iomem)
+- memcpy_fromio(ptr, (void __iomem *)(elf_data + offset), filesz);
++ memcpy_toio((void __iomem *)ptr, elf_data + offset, filesz);
+ else
+ memcpy(ptr, elf_data + offset, filesz);
+ }
+diff --git a/drivers/reset/tegra/reset-bpmp.c b/drivers/reset/tegra/reset-bpmp.c
+index 4c5bba52b1059..24d3395964cc4 100644
+--- a/drivers/reset/tegra/reset-bpmp.c
++++ b/drivers/reset/tegra/reset-bpmp.c
+@@ -20,7 +20,6 @@ static int tegra_bpmp_reset_common(struct reset_controller_dev *rstc,
+ struct tegra_bpmp *bpmp = to_tegra_bpmp(rstc);
+ struct mrq_reset_request request;
+ struct tegra_bpmp_message msg;
+- int err;
+
+ memset(&request, 0, sizeof(request));
+ request.cmd = command;
+@@ -31,13 +30,7 @@ static int tegra_bpmp_reset_common(struct reset_controller_dev *rstc,
+ msg.tx.data = &request;
+ msg.tx.size = sizeof(request);
+
+- err = tegra_bpmp_transfer(bpmp, &msg);
+- if (err)
+- return err;
+- if (msg.rx.ret)
+- return -EINVAL;
+-
+- return 0;
++ return tegra_bpmp_transfer(bpmp, &msg);
+ }
+
+ static int tegra_bpmp_reset_module(struct reset_controller_dev *rstc,
+diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
+index b3de6d2e680a4..2f83adef966eb 100644
+--- a/drivers/rtc/rtc-ds1302.c
++++ b/drivers/rtc/rtc-ds1302.c
+@@ -199,11 +199,18 @@ static const struct of_device_id ds1302_dt_ids[] = {
+ MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
+ #endif
+
++static const struct spi_device_id ds1302_spi_ids[] = {
++ { .name = "ds1302", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(spi, ds1302_spi_ids);
++
+ static struct spi_driver ds1302_driver = {
+ .driver.name = "rtc-ds1302",
+ .driver.of_match_table = of_match_ptr(ds1302_dt_ids),
+ .probe = ds1302_probe,
+ .remove = ds1302_remove,
++ .id_table = ds1302_spi_ids,
+ };
+
+ module_spi_driver(ds1302_driver);
+diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
+index 66fc8617d07ee..93ce72b9ae59e 100644
+--- a/drivers/rtc/rtc-ds1390.c
++++ b/drivers/rtc/rtc-ds1390.c
+@@ -219,12 +219,19 @@ static const struct of_device_id ds1390_of_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, ds1390_of_match);
+
++static const struct spi_device_id ds1390_spi_ids[] = {
++ { .name = "ds1390" },
++ {}
++};
++MODULE_DEVICE_TABLE(spi, ds1390_spi_ids);
++
+ static struct spi_driver ds1390_driver = {
+ .driver = {
+ .name = "rtc-ds1390",
+ .of_match_table = of_match_ptr(ds1390_of_match),
+ },
+ .probe = ds1390_probe,
++ .id_table = ds1390_spi_ids,
+ };
+
+ module_spi_driver(ds1390_driver);
+diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c
+index bad7792b6ca58..0d515b3df5710 100644
+--- a/drivers/rtc/rtc-mcp795.c
++++ b/drivers/rtc/rtc-mcp795.c
+@@ -430,12 +430,19 @@ static const struct of_device_id mcp795_of_match[] = {
+ MODULE_DEVICE_TABLE(of, mcp795_of_match);
+ #endif
+
++static const struct spi_device_id mcp795_spi_ids[] = {
++ { .name = "mcp795" },
++ { }
++};
++MODULE_DEVICE_TABLE(spi, mcp795_spi_ids);
++
+ static struct spi_driver mcp795_driver = {
+ .driver = {
+ .name = "rtc-mcp795",
+ .of_match_table = of_match_ptr(mcp795_of_match),
+ },
+ .probe = mcp795_probe,
++ .id_table = mcp795_spi_ids,
+ };
+
+ module_spi_driver(mcp795_driver);
+diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
+index 0f58cac81d8c0..7473e6c8a183b 100644
+--- a/drivers/rtc/rtc-pcf2123.c
++++ b/drivers/rtc/rtc-pcf2123.c
+@@ -451,12 +451,21 @@ static const struct of_device_id pcf2123_dt_ids[] = {
+ MODULE_DEVICE_TABLE(of, pcf2123_dt_ids);
+ #endif
+
++static const struct spi_device_id pcf2123_spi_ids[] = {
++ { .name = "pcf2123", },
++ { .name = "rv2123", },
++ { .name = "rtc-pcf2123", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(spi, pcf2123_spi_ids);
++
+ static struct spi_driver pcf2123_driver = {
+ .driver = {
+ .name = "rtc-pcf2123",
+ .of_match_table = of_match_ptr(pcf2123_dt_ids),
+ },
+ .probe = pcf2123_probe,
++ .id_table = pcf2123_spi_ids,
+ };
+
+ module_spi_driver(pcf2123_driver);
+diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
+index d63102d5cb1e4..1b62ed2f14594 100644
+--- a/drivers/rtc/rtc-rv3032.c
++++ b/drivers/rtc/rtc-rv3032.c
+@@ -617,11 +617,11 @@ static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+
+ ret = rv3032_enter_eerd(rv3032, &eerd);
+ if (ret)
+- goto exit_eerd;
++ return ret;
+
+ ret = regmap_write(rv3032->regmap, RV3032_CLKOUT1, hfd & 0xff);
+ if (ret)
+- return ret;
++ goto exit_eerd;
+
+ ret = regmap_write(rv3032->regmap, RV3032_CLKOUT2, RV3032_CLKOUT2_OS |
+ FIELD_PREP(RV3032_CLKOUT2_HFD_MSK, hfd >> 8));
+diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
+index 1f5fab617b679..f7e75d9fedf61 100644
+--- a/drivers/s390/char/tape_std.c
++++ b/drivers/s390/char/tape_std.c
+@@ -53,7 +53,6 @@ int
+ tape_std_assign(struct tape_device *device)
+ {
+ int rc;
+- struct timer_list timeout;
+ struct tape_request *request;
+
+ request = tape_alloc_request(2, 11);
+@@ -70,7 +69,7 @@ tape_std_assign(struct tape_device *device)
+ * So we set up a timeout for this call.
+ */
+ timer_setup(&request->timer, tape_std_assign_timeout, 0);
+- mod_timer(&timeout, jiffies + 2 * HZ);
++ mod_timer(&request->timer, jiffies + msecs_to_jiffies(2000));
+
+ rc = tape_do_io_interruptible(device, request);
+
+diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
+index 44461928aab8a..c278097926093 100644
+--- a/drivers/s390/cio/css.c
++++ b/drivers/s390/cio/css.c
+@@ -437,8 +437,8 @@ static ssize_t dev_busid_show(struct device *dev,
+ struct subchannel *sch = to_subchannel(dev);
+ struct pmcw *pmcw = &sch->schib.pmcw;
+
+- if ((pmcw->st == SUBCHANNEL_TYPE_IO ||
+- pmcw->st == SUBCHANNEL_TYPE_MSG) && pmcw->dnv)
++ if ((pmcw->st == SUBCHANNEL_TYPE_IO && pmcw->dnv) ||
++ (pmcw->st == SUBCHANNEL_TYPE_MSG && pmcw->w))
+ return sysfs_emit(buf, "0.%x.%04x\n", sch->schid.ssid,
+ pmcw->dev);
+ else
+diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
+index 0fe7b2f2e7f52..c533d1dadc6bb 100644
+--- a/drivers/s390/cio/device_ops.c
++++ b/drivers/s390/cio/device_ops.c
+@@ -825,13 +825,23 @@ EXPORT_SYMBOL_GPL(ccw_device_get_chid);
+ */
+ void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size)
+ {
+- return cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
++ void *addr;
++
++ if (!get_device(&cdev->dev))
++ return NULL;
++ addr = cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
++ if (IS_ERR_OR_NULL(addr))
++ put_device(&cdev->dev);
++ return addr;
+ }
+ EXPORT_SYMBOL(ccw_device_dma_zalloc);
+
+ void ccw_device_dma_free(struct ccw_device *cdev, void *cpu_addr, size_t size)
+ {
++ if (!cpu_addr)
++ return;
+ cio_gp_dma_free(cdev->private->dma_pool, cpu_addr, size);
++ put_device(&cdev->dev);
+ }
+ EXPORT_SYMBOL(ccw_device_dma_free);
+
+diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
+index 9ea48bf0ee40d..032bf7b282bab 100644
+--- a/drivers/s390/crypto/ap_queue.c
++++ b/drivers/s390/crypto/ap_queue.c
+@@ -157,6 +157,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ aq->queue_count = max_t(int, 0, aq->queue_count - 1);
++ if (!status.queue_empty && !aq->queue_count)
++ aq->queue_count++;
+ if (aq->queue_count > 0)
+ mod_timer(&aq->timeout,
+ jiffies + aq->request_timeout);
+diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
+index ffb3919675734..97be0765cb9bd 100644
+--- a/drivers/scsi/advansys.c
++++ b/drivers/scsi/advansys.c
+@@ -3308,8 +3308,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
+ shost->host_no);
+
+ seq_printf(m,
+- " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+- (unsigned long)v->iop_base,
++ " iop_base 0x%p, cable_detect: %X, err_code %u\n",
++ v->iop_base,
+ AdvReadWordRegister(iop_base,IOPW_SCSI_CFG1) & CABLE_DETECT,
+ v->err_code);
+
+diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
+index dc98f51f466fb..d5ac938970232 100644
+--- a/drivers/scsi/csiostor/csio_lnode.c
++++ b/drivers/scsi/csiostor/csio_lnode.c
+@@ -619,7 +619,7 @@ csio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
+ struct fc_els_csp *csp;
+ struct fc_els_cssp *clsp;
+ enum fw_retval retval;
+- __be32 nport_id;
++ __be32 nport_id = 0;
+
+ retval = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
+ if (retval != FW_SUCCESS) {
+diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
+index 24c7cefb0b78a..1c79e6c271630 100644
+--- a/drivers/scsi/dc395x.c
++++ b/drivers/scsi/dc395x.c
+@@ -4618,6 +4618,7 @@ static int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+ /* initialise the adapter and everything we need */
+ if (adapter_init(acb, io_port_base, io_port_len, irq)) {
+ dprintkl(KERN_INFO, "adapter init failed\n");
++ acb = NULL;
+ goto fail;
+ }
+
+diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
+index 24b72ee4246fb..0165dad803001 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -388,6 +388,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
+ shost->shost_state = SHOST_CREATED;
+ INIT_LIST_HEAD(&shost->__devices);
+ INIT_LIST_HEAD(&shost->__targets);
++ INIT_LIST_HEAD(&shost->eh_abort_list);
+ INIT_LIST_HEAD(&shost->eh_cmd_q);
+ INIT_LIST_HEAD(&shost->starved_list);
+ init_waitqueue_head(&shost->host_wait);
+diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
+index c512f41991429..c9770b1d2366a 100644
+--- a/drivers/scsi/lpfc/lpfc_crtn.h
++++ b/drivers/scsi/lpfc/lpfc_crtn.h
+@@ -119,6 +119,8 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_nodelist *lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did);
+ struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+ int lpfc_nlp_put(struct lpfc_nodelist *);
++void lpfc_check_nlp_post_devloss(struct lpfc_vport *vport,
++ struct lpfc_nodelist *ndlp);
+ void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb);
+ int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
+diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
+index 871b665bd72e3..37a4b79010bfc 100644
+--- a/drivers/scsi/lpfc/lpfc_disc.h
++++ b/drivers/scsi/lpfc/lpfc_disc.h
+@@ -85,6 +85,13 @@ enum lpfc_fc4_xpt_flags {
+ NLP_XPT_HAS_HH = 0x10
+ };
+
++enum lpfc_nlp_save_flags {
++ /* devloss occurred during recovery */
++ NLP_IN_RECOV_POST_DEV_LOSS = 0x1,
++ /* wait for outstanding LOGO to cmpl */
++ NLP_WAIT_FOR_LOGO = 0x2,
++};
++
+ struct lpfc_nodelist {
+ struct list_head nlp_listp;
+ struct serv_parm fc_sparam; /* buffer for service params */
+@@ -144,8 +151,9 @@ struct lpfc_nodelist {
+ unsigned long *active_rrqs_xri_bitmap;
+ struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
+ uint32_t fc4_prli_sent;
+- u32 upcall_flags;
+-#define NLP_WAIT_FOR_LOGO 0x2
++
++ /* flags to keep ndlp alive until special conditions are met */
++ enum lpfc_nlp_save_flags save_flags;
+
+ enum lpfc_fc4_xpt_flags fc4_xpt_flags;
+
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 052c0e5b11195..f7197b7161d52 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -1059,9 +1059,10 @@ stop_rr_fcf_flogi:
+
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT,
+ "0150 FLOGI failure Status:x%x/x%x "
+- "xri x%x TMO:x%x\n",
++ "xri x%x TMO:x%x refcnt %d\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+- cmdiocb->sli4_xritag, irsp->ulpTimeout);
++ cmdiocb->sli4_xritag, irsp->ulpTimeout,
++ kref_read(&ndlp->kref));
+
+ /* If this is not a loop open failure, bail out */
+ if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT &&
+@@ -1122,12 +1123,12 @@ stop_rr_fcf_flogi:
+ /* FLOGI completes successfully */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0101 FLOGI completes successfully, I/O tag:x%x, "
+- "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x\n",
++ "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x %d\n",
+ cmdiocb->iotag, cmdiocb->sli4_xritag,
+ irsp->un.ulpWord[4], sp->cmn.e_d_tov,
+ sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution,
+ vport->port_state, vport->fc_flag,
+- sp->cmn.priority_tagging);
++ sp->cmn.priority_tagging, kref_read(&ndlp->kref));
+
+ if (sp->cmn.priority_tagging)
+ vport->vmid_flag |= LPFC_VMID_ISSUE_QFPA;
+@@ -1205,8 +1206,6 @@ flogifail:
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+
+- if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)))
+- lpfc_nlp_put(ndlp);
+ if (!lpfc_error_lost_link(irsp)) {
+ /* FLOGI failed, so just use loop map to make discovery list */
+ lpfc_disc_list_loopmap(vport);
+@@ -2899,9 +2898,9 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ irsp = &(rspiocb->iocb);
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_flag &= ~NLP_LOGO_SND;
+- if (ndlp->upcall_flags & NLP_WAIT_FOR_LOGO) {
++ if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) {
+ wake_up_waiter = 1;
+- ndlp->upcall_flags &= ~NLP_WAIT_FOR_LOGO;
++ ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO;
+ }
+ spin_unlock_irq(&ndlp->lock);
+
+@@ -5076,14 +5075,9 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ /* NPort Recovery mode or node is just allocated */
+ if (!lpfc_nlp_not_used(ndlp)) {
+ /* A LOGO is completing and the node is in NPR state.
+- * If this a fabric node that cleared its transport
+- * registration, release the rpi.
++ * Just unregister the RPI because the node is still
++ * required.
+ */
+- spin_lock_irq(&ndlp->lock);
+- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+- if (phba->sli_rev == LPFC_SLI_REV4)
+- ndlp->nlp_flag |= NLP_RELEASE_RPI;
+- spin_unlock_irq(&ndlp->lock);
+ lpfc_unreg_rpi(vport, ndlp);
+ } else {
+ /* Indicate the node has already released, should
+@@ -6216,6 +6210,7 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport)
+ * from backend
+ */
+ lpfc_nlp_unreg_node(vport, ndlp);
++ lpfc_unreg_rpi(vport, ndlp);
+ continue;
+ }
+
+@@ -10713,6 +10708,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+ goto fdisc_failed;
+ }
++
++ lpfc_check_nlp_post_devloss(vport, ndlp);
++
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+ vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index 7195ca0275f93..9ccb904e35fcf 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -209,7 +209,12 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ ndlp->nlp_flag |= NLP_IN_DEV_LOSS;
+- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
++
++ /* If there is a PLOGI in progress, and we are in a
++ * NLP_NPR_2B_DISC state, don't turn off the flag.
++ */
++ if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE)
++ ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+
+ /*
+ * The backend does not expect any more calls associated with this
+@@ -340,6 +345,37 @@ static void lpfc_check_inactive_vmid(struct lpfc_hba *phba)
+ lpfc_destroy_vport_work_array(phba, vports);
+ }
+
++/**
++ * lpfc_check_nlp_post_devloss - Check to restore ndlp refcnt after devloss
++ * @vport: Pointer to vport object.
++ * @ndlp: Pointer to remote node object.
++ *
++ * If NLP_IN_RECOV_POST_DEV_LOSS flag was set due to outstanding recovery of
++ * node during dev_loss_tmo processing, then this function restores the nlp_put
++ * kref decrement from lpfc_dev_loss_tmo_handler.
++ **/
++void
++lpfc_check_nlp_post_devloss(struct lpfc_vport *vport,
++ struct lpfc_nodelist *ndlp)
++{
++ unsigned long iflags;
++
++ spin_lock_irqsave(&ndlp->lock, iflags);
++ if (ndlp->save_flags & NLP_IN_RECOV_POST_DEV_LOSS) {
++ ndlp->save_flags &= ~NLP_IN_RECOV_POST_DEV_LOSS;
++ spin_unlock_irqrestore(&ndlp->lock, iflags);
++ lpfc_nlp_get(ndlp);
++ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE,
++ "8438 Devloss timeout reversed on DID x%x "
++ "refcnt %d ndlp %p flag x%x "
++ "port_state = x%x\n",
++ ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp,
++ ndlp->nlp_flag, vport->port_state);
++ spin_lock_irqsave(&ndlp->lock, iflags);
++ }
++ spin_unlock_irqrestore(&ndlp->lock, iflags);
++}
++
+ /**
+ * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
+ * @ndlp: Pointer to remote node object.
+@@ -358,6 +394,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ uint8_t *name;
+ int warn_on = 0;
+ int fcf_inuse = 0;
++ bool recovering = false;
++ struct fc_vport *fc_vport = NULL;
+ unsigned long iflags;
+
+ vport = ndlp->vport;
+@@ -394,6 +432,64 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+
+ /* Fabric nodes are done. */
+ if (ndlp->nlp_type & NLP_FABRIC) {
++ spin_lock_irqsave(&ndlp->lock, iflags);
++ /* In massive vport configuration settings, it's possible
++ * dev_loss_tmo fired during node recovery. So, check if
++ * fabric nodes are in discovery states outstanding.
++ */
++ switch (ndlp->nlp_DID) {
++ case Fabric_DID:
++ fc_vport = vport->fc_vport;
++ if (fc_vport &&
++ fc_vport->vport_state == FC_VPORT_INITIALIZING)
++ recovering = true;
++ break;
++ case Fabric_Cntl_DID:
++ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
++ recovering = true;
++ break;
++ case FDMI_DID:
++ fallthrough;
++ case NameServer_DID:
++ if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
++ ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
++ recovering = true;
++ break;
++ }
++ spin_unlock_irqrestore(&ndlp->lock, iflags);
++
++ /* Mark an NLP_IN_RECOV_POST_DEV_LOSS flag to know if reversing
++ * the following lpfc_nlp_put is necessary after fabric node is
++ * recovered.
++ */
++ if (recovering) {
++ lpfc_printf_vlog(vport, KERN_INFO,
++ LOG_DISCOVERY | LOG_NODE,
++ "8436 Devloss timeout marked on "
++ "DID x%x refcnt %d ndlp %p "
++ "flag x%x port_state = x%x\n",
++ ndlp->nlp_DID, kref_read(&ndlp->kref),
++ ndlp, ndlp->nlp_flag,
++ vport->port_state);
++ spin_lock_irqsave(&ndlp->lock, iflags);
++ ndlp->save_flags |= NLP_IN_RECOV_POST_DEV_LOSS;
++ spin_unlock_irqrestore(&ndlp->lock, iflags);
++ } else if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
++ /* Fabric node fully recovered before this dev_loss_tmo
++ * queue work is processed. Thus, ignore the
++ * dev_loss_tmo event.
++ */
++ lpfc_printf_vlog(vport, KERN_INFO,
++ LOG_DISCOVERY | LOG_NODE,
++ "8437 Devloss timeout ignored on "
++ "DID x%x refcnt %d ndlp %p "
++ "flag x%x port_state = x%x\n",
++ ndlp->nlp_DID, kref_read(&ndlp->kref),
++ ndlp, ndlp->nlp_flag,
++ vport->port_state);
++ return fcf_inuse;
++ }
++
+ lpfc_nlp_put(ndlp);
+ return fcf_inuse;
+ }
+@@ -423,6 +519,14 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+ ndlp->nlp_state, ndlp->nlp_rpi);
+ }
+
++ /* If we are devloss, but we are in the process of rediscovering the
++ * ndlp, don't issue a NLP_EVT_DEVICE_RM event.
++ */
++ if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
++ ndlp->nlp_state <= NLP_STE_PRLI_ISSUE) {
++ return fcf_inuse;
++ }
++
+ if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD))
+ lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
+
+@@ -4351,6 +4455,8 @@ lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ goto out;
+ }
+
++ lpfc_check_nlp_post_devloss(vport, ndlp);
++
+ if (phba->sli_rev < LPFC_SLI_REV4)
+ ndlp->nlp_rpi = mb->un.varWords[0];
+
+@@ -4360,6 +4466,7 @@ lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+ ndlp->nlp_state);
+
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
++ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+ ndlp->nlp_type |= NLP_FABRIC;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+
+@@ -4449,8 +4556,9 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ fc_remote_port_rolechg(rport, rport_ids.roles);
+
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
+- "3183 %s rport x%px DID x%x, role x%x\n",
+- __func__, rport, rport->port_id, rport->roles);
++ "3183 %s rport x%px DID x%x, role x%x refcnt %d\n",
++ __func__, rport, rport->port_id, rport->roles,
++ kref_read(&ndlp->kref));
+
+ if ((rport->scsi_target_id != -1) &&
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
+@@ -4475,8 +4583,9 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "3184 rport unregister x%06x, rport x%px "
+- "xptflg x%x\n",
+- ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags);
++ "xptflg x%x refcnt %d\n",
++ ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags,
++ kref_read(&ndlp->kref));
+
+ fc_remote_port_delete(rport);
+ lpfc_nlp_put(ndlp);
+@@ -4525,9 +4634,10 @@ lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
+ void
+ lpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+ {
+-
+ unsigned long iflags;
+
++ lpfc_check_nlp_post_devloss(vport, ndlp);
++
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) {
+ /* Already registered with backend, trigger rescan */
+diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
+index 195169badb372..0fee8d590b0c4 100644
+--- a/drivers/scsi/lpfc/lpfc_init.c
++++ b/drivers/scsi/lpfc/lpfc_init.c
+@@ -3694,12 +3694,16 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
+ lpfc_disc_state_machine(vports[i], ndlp,
+ NULL, NLP_EVT_DEVICE_RECOVERY);
+
+- /* Don't remove the node unless the
++ /* Don't remove the node unless the node
+ * has been unregistered with the
+- * transport. If so, let dev_loss
+- * take care of the node.
++ * transport, and we're not in recovery
++ * before dev_loss_tmo triggered.
++ * Otherwise, let dev_loss take care of
++ * the node.
+ */
+- if (!(ndlp->fc4_xpt_flags &
++ if (!(ndlp->save_flags &
++ NLP_IN_RECOV_POST_DEV_LOSS) &&
++ !(ndlp->fc4_xpt_flags &
+ (NVME_XPT_REGD | SCSI_XPT_REGD)))
+ lpfc_disc_state_machine
+ (vports[i], ndlp,
+diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
+index 479b3eed62085..66cb66aea2cf9 100644
+--- a/drivers/scsi/lpfc/lpfc_nvme.c
++++ b/drivers/scsi/lpfc/lpfc_nvme.c
+@@ -209,8 +209,9 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport)
+ * calling state machine to remove the node.
+ */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+- "6146 remoteport delete of remoteport x%px\n",
+- remoteport);
++ "6146 remoteport delete of remoteport x%px, ndlp x%px "
++ "DID x%x xflags x%x\n",
++ remoteport, ndlp, ndlp->nlp_DID, ndlp->fc4_xpt_flags);
+ spin_lock_irq(&ndlp->lock);
+
+ /* The register rebind might have occurred before the delete
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index befdf864c43bd..3d9175f1b6787 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -6455,28 +6455,28 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
+
+ /* Issue LOGO, if no LOGO is outstanding */
+ spin_lock_irqsave(&pnode->lock, flags);
+- if (!(pnode->upcall_flags & NLP_WAIT_FOR_LOGO) &&
++ if (!(pnode->save_flags & NLP_WAIT_FOR_LOGO) &&
+ !pnode->logo_waitq) {
+ pnode->logo_waitq = &waitq;
+ pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+ pnode->nlp_flag |= NLP_ISSUE_LOGO;
+- pnode->upcall_flags |= NLP_WAIT_FOR_LOGO;
++ pnode->save_flags |= NLP_WAIT_FOR_LOGO;
+ spin_unlock_irqrestore(&pnode->lock, flags);
+ lpfc_unreg_rpi(vport, pnode);
+ wait_event_timeout(waitq,
+- (!(pnode->upcall_flags &
++ (!(pnode->save_flags &
+ NLP_WAIT_FOR_LOGO)),
+ msecs_to_jiffies(dev_loss_tmo *
+ 1000));
+
+- if (pnode->upcall_flags & NLP_WAIT_FOR_LOGO) {
++ if (pnode->save_flags & NLP_WAIT_FOR_LOGO) {
+ lpfc_printf_vlog(vport, KERN_ERR, logit,
+ "0725 SCSI layer TGTRST "
+ "failed & LOGO TMO (%d, %llu) "
+ "return x%x\n",
+ tgt_id, lun_id, status);
+ spin_lock_irqsave(&pnode->lock, flags);
+- pnode->upcall_flags &= ~NLP_WAIT_FOR_LOGO;
++ pnode->save_flags &= ~NLP_WAIT_FOR_LOGO;
+ } else {
+ spin_lock_irqsave(&pnode->lock, flags);
+ }
+@@ -6628,6 +6628,13 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd)
+ if (rc)
+ goto error;
+
++ /* Wait for successful restart of adapter */
++ if (phba->sli_rev < LPFC_SLI_REV4) {
++ rc = lpfc_sli_chipset_init(phba);
++ if (rc)
++ goto error;
++ }
++
+ rc = lpfc_online(phba);
+ if (rc)
+ goto error;
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index 026a1196a54d5..9c1f485952ef7 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -12404,17 +12404,17 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+
+ /* ABTS WQE must go to the same WQ as the WQE to be aborted */
+ abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx;
+- if (cmdiocb->iocb_flag & LPFC_IO_FCP) {
+- abtsiocbp->iocb_flag |= LPFC_IO_FCP;
+- abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
+- }
++ if (cmdiocb->iocb_flag & LPFC_IO_FCP)
++ abtsiocbp->iocb_flag |= (LPFC_IO_FCP | LPFC_USE_FCPWQIDX);
+ if (cmdiocb->iocb_flag & LPFC_IO_FOF)
+ abtsiocbp->iocb_flag |= LPFC_IO_FOF;
+
+- if (phba->link_state >= LPFC_LINK_UP)
+- iabt->ulpCommand = CMD_ABORT_XRI_CN;
+- else
++ if (phba->link_state < LPFC_LINK_UP ||
++ (phba->sli_rev == LPFC_SLI_REV4 &&
++ phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN))
+ iabt->ulpCommand = CMD_CLOSE_XRI_CN;
++ else
++ iabt->ulpCommand = CMD_ABORT_XRI_CN;
+
+ if (cmpl)
+ abtsiocbp->iocb_cmpl = cmpl;
+@@ -12488,15 +12488,54 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
+ }
+
+ /**
+- * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN
++ * lpfc_sli_validate_fcp_iocb_for_abort - filter iocbs appropriate for FCP aborts
++ * @iocbq: Pointer to iocb object.
++ * @vport: Pointer to driver virtual port object.
++ *
++ * This function acts as an iocb filter for functions which abort FCP iocbs.
++ *
++ * Return values
++ * -ENODEV, if a null iocb or vport ptr is encountered
++ * -EINVAL, if the iocb is not an FCP I/O, not on the TX cmpl queue, premarked as
++ * driver already started the abort process, or is an abort iocb itself
++ * 0, passes criteria for aborting the FCP I/O iocb
++ **/
++static int
++lpfc_sli_validate_fcp_iocb_for_abort(struct lpfc_iocbq *iocbq,
++ struct lpfc_vport *vport)
++{
++ IOCB_t *icmd = NULL;
++
++ /* No null ptr vports */
++ if (!iocbq || iocbq->vport != vport)
++ return -ENODEV;
++
++ /* iocb must be for FCP IO, already exists on the TX cmpl queue,
++ * can't be premarked as driver aborted, nor be an ABORT iocb itself
++ */
++ icmd = &iocbq->iocb;
++ if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
++ !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) ||
++ (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) ||
++ (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
++ icmd->ulpCommand == CMD_CLOSE_XRI_CN))
++ return -EINVAL;
++
++ return 0;
++}
++
++/**
++ * lpfc_sli_validate_fcp_iocb - validate commands associated with a SCSI target
+ * @iocbq: Pointer to driver iocb object.
+ * @vport: Pointer to driver virtual port object.
+ * @tgt_id: SCSI ID of the target.
+ * @lun_id: LUN ID of the scsi device.
+ * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST
+ *
+- * This function acts as an iocb filter for functions which abort or count
+- * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return
++ * This function acts as an iocb filter for validating a lun/SCSI target/SCSI
++ * host.
++ *
++ * It will return
+ * 0 if the filtering criteria is met for the given iocb and will return
+ * 1 if the filtering criteria is not met.
+ * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the
+@@ -12515,22 +12554,8 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
+ lpfc_ctx_cmd ctx_cmd)
+ {
+ struct lpfc_io_buf *lpfc_cmd;
+- IOCB_t *icmd = NULL;
+ int rc = 1;
+
+- if (!iocbq || iocbq->vport != vport)
+- return rc;
+-
+- if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
+- !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) ||
+- iocbq->iocb_flag & LPFC_DRIVER_ABORTED)
+- return rc;
+-
+- icmd = &iocbq->iocb;
+- if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+- icmd->ulpCommand == CMD_CLOSE_XRI_CN)
+- return rc;
+-
+ lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
+
+ if (lpfc_cmd->pCmd == NULL)
+@@ -12585,17 +12610,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
+ {
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *iocbq;
++ IOCB_t *icmd = NULL;
+ int sum, i;
++ unsigned long iflags;
+
+- spin_lock_irq(&phba->hbalock);
++ spin_lock_irqsave(&phba->hbalock, iflags);
+ for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
+ iocbq = phba->sli.iocbq_lookup[i];
+
+- if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id,
+- ctx_cmd) == 0)
++ if (!iocbq || iocbq->vport != vport)
++ continue;
++ if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
++ !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ))
++ continue;
++
++ /* Include counting outstanding aborts */
++ icmd = &iocbq->iocb;
++ if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
++ icmd->ulpCommand == CMD_CLOSE_XRI_CN) {
++ sum++;
++ continue;
++ }
++
++ if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
++ ctx_cmd) == 0)
+ sum++;
+ }
+- spin_unlock_irq(&phba->hbalock);
++ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ return sum;
+ }
+@@ -12662,7 +12703,11 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ *
+ * This function sends an abort command for every SCSI command
+ * associated with the given virtual port pending on the ring
+- * filtered by lpfc_sli_validate_fcp_iocb function.
++ * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
++ * lpfc_sli_validate_fcp_iocb function. The ordering for validation before
++ * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
++ * followed by lpfc_sli_validate_fcp_iocb.
++ *
+ * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the
+ * FCP iocbs associated with lun specified by tgt_id and lun_id
+ * parameters
+@@ -12694,6 +12739,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id,
+ for (i = 1; i <= phba->sli.last_iotag; i++) {
+ iocbq = phba->sli.iocbq_lookup[i];
+
++ if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
++ continue;
++
+ if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
+ abort_cmd) != 0)
+ continue;
+@@ -12726,7 +12774,11 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id,
+ *
+ * This function sends an abort command for every SCSI command
+ * associated with the given virtual port pending on the ring
+- * filtered by lpfc_sli_validate_fcp_iocb function.
++ * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
++ * lpfc_sli_validate_fcp_iocb function. The ordering for validation before
++ * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
++ * followed by lpfc_sli_validate_fcp_iocb.
++ *
+ * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the
+ * FCP iocbs associated with lun specified by tgt_id and lun_id
+ * parameters
+@@ -12764,6 +12816,9 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
+ for (i = 1; i <= phba->sli.last_iotag; i++) {
+ iocbq = phba->sli.iocbq_lookup[i];
+
++ if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
++ continue;
++
+ if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
+ cmd) != 0)
+ continue;
+@@ -21107,6 +21162,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
+ fail_msg,
+ piocbq->iotag, piocbq->sli4_xritag);
+ list_add_tail(&piocbq->list, &completions);
++ fail_msg = NULL;
+ }
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+ }
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index 26d0cf9353dd6..eb5ceb75a15ec 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -3530,6 +3530,9 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
+ return IRQ_HANDLED;
+
++ if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1))
++ return 0;
++
+ desc = fusion->reply_frames_desc[MSIxIndex] +
+ fusion->last_reply_idx[MSIxIndex];
+
+@@ -3540,11 +3543,11 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+ reply_descript_type = reply_desc->ReplyFlags &
+ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+
+- if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
++ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
++ if (irq_context)
++ atomic_dec(&irq_context->in_used);
+ return IRQ_NONE;
+-
+- if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1))
+- return 0;
++ }
+
+ num_completed = 0;
+
+diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
+index 27eb652b564f5..81dab9b82f79f 100644
+--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
++++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
+@@ -639,8 +639,8 @@ static void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc)
+ mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP;
+ current_time = ktime_get_real();
+ TimeStamp = ktime_to_ms(current_time);
+- mpi_request->Reserved7 = cpu_to_le32(TimeStamp & 0xFFFFFFFF);
+- mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp >> 32);
++ mpi_request->Reserved7 = cpu_to_le32(TimeStamp >> 32);
++ mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp & 0xFFFFFFFF);
+ init_completion(&ioc->scsih_cmds.done);
+ ioc->put_smid_default(ioc, smid);
+ dinitprintk(ioc, ioc_info(ioc,
+diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
+index f87c0911f66ad..1b3a44ce65aae 100644
+--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
++++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
+@@ -142,6 +142,8 @@
+
+ #define MPT_MAX_CALLBACKS 32
+
++#define MPT_MAX_HBA_NUM_PHYS 32
++
+ #define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
+ /* reserved for issuing internally framed scsi io cmds */
+ #define INTERNAL_SCSIIO_CMDS_COUNT 3
+@@ -798,6 +800,7 @@ struct _sas_phy {
+ * @enclosure_handle: handle for this a member of an enclosure
+ * @device_info: bitwise defining capabilities of this sas_host/expander
+ * @responding: used in _scsih_expander_device_mark_responding
++ * @nr_phys_allocated: Allocated memory for this many count phys
+ * @phy: a list of phys that make up this sas_host/expander
+ * @sas_port_list: list of ports attached to this sas_host/expander
+ * @port: hba port entry containing node's port number info
+@@ -813,6 +816,7 @@ struct _sas_node {
+ u16 enclosure_handle;
+ u64 enclosure_logical_id;
+ u8 responding;
++ u8 nr_phys_allocated;
+ struct hba_port *port;
+ struct _sas_phy *phy;
+ struct list_head sas_port_list;
+diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+index ad1b6c2b37a74..c1f900c6ea003 100644
+--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
++++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+@@ -3869,7 +3869,7 @@ _scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc,
+
+ shost_for_each_device(sdev, ioc->shost) {
+ sas_device_priv_data = sdev->hostdata;
+- if (!sas_device_priv_data)
++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
+ continue;
+ if (sas_device_priv_data->sas_target->sas_address
+ != sas_address)
+@@ -6406,11 +6406,26 @@ _scsih_sas_port_refresh(struct MPT3SAS_ADAPTER *ioc)
+ int i, j, count = 0, lcount = 0;
+ int ret;
+ u64 sas_addr;
++ u8 num_phys;
+
+ drsprintk(ioc, ioc_info(ioc,
+ "updating ports for sas_host(0x%016llx)\n",
+ (unsigned long long)ioc->sas_hba.sas_address));
+
++ mpt3sas_config_get_number_hba_phys(ioc, &num_phys);
++ if (!num_phys) {
++ ioc_err(ioc, "failure at %s:%d/%s()!\n",
++ __FILE__, __LINE__, __func__);
++ return;
++ }
++
++ if (num_phys > ioc->sas_hba.nr_phys_allocated) {
++ ioc_err(ioc, "failure at %s:%d/%s()!\n",
++ __FILE__, __LINE__, __func__);
++ return;
++ }
++ ioc->sas_hba.num_phys = num_phys;
++
+ port_table = kcalloc(ioc->sas_hba.num_phys,
+ sizeof(struct hba_port), GFP_KERNEL);
+ if (!port_table)
+@@ -6611,6 +6626,30 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc)
+ ioc->sas_hba.phy[i].hba_vphy = 1;
+ }
+
++ /*
++ * Add new HBA phys to STL if these new phys got added as part
++ * of HBA Firmware upgrade/downgrade operation.
++ */
++ if (!ioc->sas_hba.phy[i].phy) {
++ if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply,
++ &phy_pg0, i))) {
++ ioc_err(ioc, "failure at %s:%d/%s()!\n",
++ __FILE__, __LINE__, __func__);
++ continue;
++ }
++ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
++ MPI2_IOCSTATUS_MASK;
++ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
++ ioc_err(ioc, "failure at %s:%d/%s()!\n",
++ __FILE__, __LINE__, __func__);
++ continue;
++ }
++ ioc->sas_hba.phy[i].phy_id = i;
++ mpt3sas_transport_add_host_phy(ioc,
++ &ioc->sas_hba.phy[i], phy_pg0,
++ ioc->sas_hba.parent_dev);
++ continue;
++ }
+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
+ attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
+ AttachedDevHandle);
+@@ -6622,6 +6661,19 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc)
+ attached_handle, i, link_rate,
+ ioc->sas_hba.phy[i].port);
+ }
++ /*
++ * Clear the phy details if this phy got disabled as part of
++ * HBA Firmware upgrade/downgrade operation.
++ */
++ for (i = ioc->sas_hba.num_phys;
++ i < ioc->sas_hba.nr_phys_allocated; i++) {
++ if (ioc->sas_hba.phy[i].phy &&
++ ioc->sas_hba.phy[i].phy->negotiated_linkrate >=
++ SAS_LINK_RATE_1_5_GBPS)
++ mpt3sas_transport_update_links(ioc,
++ ioc->sas_hba.sas_address, 0, i,
++ MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED, NULL);
++ }
+ out:
+ kfree(sas_iounit_pg0);
+ }
+@@ -6654,7 +6706,10 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
+ __FILE__, __LINE__, __func__);
+ return;
+ }
+- ioc->sas_hba.phy = kcalloc(num_phys,
++
++ ioc->sas_hba.nr_phys_allocated = max_t(u8,
++ MPT_MAX_HBA_NUM_PHYS, num_phys);
++ ioc->sas_hba.phy = kcalloc(ioc->sas_hba.nr_phys_allocated,
+ sizeof(struct _sas_phy), GFP_KERNEL);
+ if (!ioc->sas_hba.phy) {
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
+index 63690508313b7..639b7e38a1947 100644
+--- a/drivers/scsi/pm8001/pm8001_hwi.c
++++ b/drivers/scsi/pm8001/pm8001_hwi.c
+@@ -3169,7 +3169,7 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ * fw_control_context->usrAddr
+ */
+ complete(pm8001_ha->nvmd_completion);
+- pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n");
++ pm8001_dbg(pm8001_ha, MSG, "Get nvmd data complete!\n");
+ ccb->task = NULL;
+ ccb->ccb_tag = 0xFFFFFFFF;
+ pm8001_tag_free(pm8001_ha, tag);
+diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
+index 47db7e0beae6f..a25a34535b7a4 100644
+--- a/drivers/scsi/pm8001/pm8001_init.c
++++ b/drivers/scsi/pm8001/pm8001_init.c
+@@ -281,12 +281,12 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
+ if (rc) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "pm8001_setup_irq failed [ret: %d]\n", rc);
+- goto err_out_shost;
++ goto err_out;
+ }
+ /* Request Interrupt */
+ rc = pm8001_request_irq(pm8001_ha);
+ if (rc)
+- goto err_out_shost;
++ goto err_out;
+
+ count = pm8001_ha->max_q_num;
+ /* Queues are chosen based on the number of cores/msix availability */
+@@ -422,8 +422,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
+ pm8001_tag_init(pm8001_ha);
+ return 0;
+
+-err_out_shost:
+- scsi_remove_host(pm8001_ha->shost);
+ err_out_nodev:
+ for (i = 0; i < pm8001_ha->max_memcnt; i++) {
+ if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
+@@ -1198,6 +1196,7 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
+ goto err_out;
+
+ /* Memory region for ccb_info*/
++ pm8001_ha->ccb_count = ccb_count;
+ pm8001_ha->ccb_info =
+ kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL);
+ if (!pm8001_ha->ccb_info) {
+@@ -1259,6 +1258,16 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
+ tasklet_kill(&pm8001_ha->tasklet[j]);
+ #endif
+ scsi_host_put(pm8001_ha->shost);
++
++ for (i = 0; i < pm8001_ha->ccb_count; i++) {
++ dma_free_coherent(&pm8001_ha->pdev->dev,
++ sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG,
++ pm8001_ha->ccb_info[i].buf_prd,
++ pm8001_ha->ccb_info[i].ccb_dma_handle);
++ }
++ kfree(pm8001_ha->ccb_info);
++ kfree(pm8001_ha->devices);
++
+ pm8001_free(pm8001_ha);
+ kfree(sha->sas_phy);
+ kfree(sha->sas_port);
+diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
+index 62d08b535a4b6..f40a41f450d9b 100644
+--- a/drivers/scsi/pm8001/pm8001_sas.h
++++ b/drivers/scsi/pm8001/pm8001_sas.h
+@@ -457,6 +457,7 @@ struct outbound_queue_table {
+ __le32 producer_index;
+ u32 consumer_idx;
+ spinlock_t oq_lock;
++ unsigned long lock_flags;
+ };
+ struct pm8001_hba_memspace {
+ void __iomem *memvirtaddr;
+@@ -516,6 +517,7 @@ struct pm8001_hba_info {
+ u32 iomb_size; /* SPC and SPCV IOMB size */
+ struct pm8001_device *devices;
+ struct pm8001_ccb_info *ccb_info;
++ u32 ccb_count;
+ #ifdef PM8001_USE_MSIX
+ int number_of_intr;/*will be used in remove()*/
+ char intr_drvname[PM8001_MAX_MSIX_VEC]
+@@ -738,9 +740,7 @@ pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
+ {
+ pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
+ smp_mb(); /*in order to force CPU ordering*/
+- spin_unlock(&pm8001_ha->lock);
+ task->task_done(task);
+- spin_lock(&pm8001_ha->lock);
+ }
+
+ #endif
+diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
+index 6ffe17b849ae8..ed02e1aaf868c 100644
+--- a/drivers/scsi/pm8001/pm80xx_hwi.c
++++ b/drivers/scsi/pm8001/pm80xx_hwi.c
+@@ -2379,7 +2379,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
+
+ /*See the comments for mpi_ssp_completion */
+ static void
+-mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
++mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
++ struct outbound_queue_table *circularQ, void *piomb)
+ {
+ struct sas_task *t;
+ struct pm8001_ccb_info *ccb;
+@@ -2616,7 +2617,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -2632,7 +2637,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -2656,7 +2665,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -2727,7 +2740,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_DS_NON_OPERATIONAL);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -2747,7 +2764,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_DS_IN_ERROR);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -2785,12 +2806,17 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ }
+ }
+
+ /*See the comments for mpi_ssp_completion */
+-static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
++static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
++ struct outbound_queue_table *circularQ, void *piomb)
+ {
+ struct sas_task *t;
+ struct task_status_struct *ts;
+@@ -2890,7 +2916,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_QUEUE_FULL;
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ return;
+ }
+ break;
+@@ -3002,7 +3032,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ } else {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
++ spin_unlock_irqrestore(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
++ spin_lock_irqsave(&circularQ->oq_lock,
++ circularQ->lock_flags);
+ }
+ }
+
+@@ -3902,7 +3936,8 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
+ * @pm8001_ha: our hba card information
+ * @piomb: IO message buffer
+ */
+-static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
++static void process_one_iomb(struct pm8001_hba_info *pm8001_ha,
++ struct outbound_queue_table *circularQ, void *piomb)
+ {
+ __le32 pHeader = *(__le32 *)piomb;
+ u32 opc = (u32)((le32_to_cpu(pHeader)) & 0xFFF);
+@@ -3944,11 +3979,11 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
+ break;
+ case OPC_OUB_SATA_COMP:
+ pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n");
+- mpi_sata_completion(pm8001_ha, piomb);
++ mpi_sata_completion(pm8001_ha, circularQ, piomb);
+ break;
+ case OPC_OUB_SATA_EVENT:
+ pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n");
+- mpi_sata_event(pm8001_ha, piomb);
++ mpi_sata_event(pm8001_ha, circularQ, piomb);
+ break;
+ case OPC_OUB_SSP_EVENT:
+ pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n");
+@@ -4117,7 +4152,6 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
+ void *pMsg1 = NULL;
+ u8 bc;
+ u32 ret = MPI_IO_STATUS_FAIL;
+- unsigned long flags;
+ u32 regval;
+
+ if (vec == (pm8001_ha->max_q_num - 1)) {
+@@ -4134,7 +4168,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
+ }
+ }
+ circularQ = &pm8001_ha->outbnd_q_tbl[vec];
+- spin_lock_irqsave(&circularQ->oq_lock, flags);
++ spin_lock_irqsave(&circularQ->oq_lock, circularQ->lock_flags);
+ do {
+ /* spurious interrupt during setup if kexec-ing and
+ * driver doing a doorbell access w/ the pre-kexec oq
+@@ -4145,7 +4179,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
+ ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
+ if (MPI_IO_STATUS_SUCCESS == ret) {
+ /* process the outbound message */
+- process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4));
++ process_one_iomb(pm8001_ha, circularQ,
++ (void *)(pMsg1 - 4));
+ /* free the message from the outbound circular buffer */
+ pm8001_mpi_msg_free_set(pm8001_ha, pMsg1,
+ circularQ, bc);
+@@ -4160,7 +4195,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
+ break;
+ }
+ } while (1);
+- spin_unlock_irqrestore(&circularQ->oq_lock, flags);
++ spin_unlock_irqrestore(&circularQ->oq_lock, circularQ->lock_flags);
+ return ret;
+ }
+
+diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
+index 42d0d941dba5c..94ee08fab46a5 100644
+--- a/drivers/scsi/qedf/qedf_main.c
++++ b/drivers/scsi/qedf/qedf_main.c
+@@ -3416,7 +3416,9 @@ retry_probe:
+ qedf->devlink = qed_ops->common->devlink_register(qedf->cdev);
+ if (IS_ERR(qedf->devlink)) {
+ QEDF_ERR(&qedf->dbg_ctx, "Cannot register devlink\n");
++ rc = PTR_ERR(qedf->devlink);
+ qedf->devlink = NULL;
++ goto err2;
+ }
+ }
+
+diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
+index d09776b77af2e..cb5f2ecb652d3 100644
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -1868,6 +1868,18 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
+ return strlen(buf);
+ }
+
++static const struct {
++ u16 rate;
++ char *str;
++} port_speed_str[] = {
++ { PORT_SPEED_4GB, "4" },
++ { PORT_SPEED_8GB, "8" },
++ { PORT_SPEED_16GB, "16" },
++ { PORT_SPEED_32GB, "32" },
++ { PORT_SPEED_64GB, "64" },
++ { PORT_SPEED_10GB, "10" },
++};
++
+ static ssize_t
+ qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -1875,7 +1887,8 @@ qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+ ssize_t rval;
+- char *spd[7] = {"0", "0", "0", "4", "8", "16", "32"};
++ u16 i;
++ char *speed = "Unknown";
+
+ rval = qla2x00_get_data_rate(vha);
+ if (rval != QLA_SUCCESS) {
+@@ -1884,7 +1897,14 @@ qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
+ return -EINVAL;
+ }
+
+- return scnprintf(buf, PAGE_SIZE, "%s\n", spd[ha->link_data_rate]);
++ for (i = 0; i < ARRAY_SIZE(port_speed_str); i++) {
++ if (port_speed_str[i].rate != ha->link_data_rate)
++ continue;
++ speed = port_speed_str[i].str;
++ break;
++ }
++
++ return scnprintf(buf, PAGE_SIZE, "%s\n", speed);
+ }
+
+ static ssize_t
+diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
+index 25549a8a2d72d..7cf1f78cbaeee 100644
+--- a/drivers/scsi/qla2xxx/qla_dbg.c
++++ b/drivers/scsi/qla2xxx/qla_dbg.c
+@@ -2491,6 +2491,9 @@ ql_dbg(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...)
+ struct va_format vaf;
+ char pbuf[64];
+
++ if (!ql_mask_match(level) && !trace_ql_dbg_log_enabled())
++ return;
++
+ va_start(va, fmt);
+
+ vaf.fmt = fmt;
+diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
+index ad746c62f0d44..a04693498dc01 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.c
++++ b/drivers/scsi/qla2xxx/qla_edif.c
+@@ -290,63 +290,6 @@ qla_edif_app_check(scsi_qla_host_t *vha, struct app_id appid)
+ return false;
+ }
+
+-static void qla_edif_reset_auth_wait(struct fc_port *fcport, int state,
+- int waitonly)
+-{
+- int cnt, max_cnt = 200;
+- bool traced = false;
+-
+- fcport->keep_nport_handle = 1;
+-
+- if (!waitonly) {
+- qla2x00_set_fcport_disc_state(fcport, state);
+- qlt_schedule_sess_for_deletion(fcport);
+- } else {
+- qla2x00_set_fcport_disc_state(fcport, state);
+- }
+-
+- ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
+- "%s: waiting for session, max_cnt=%u\n",
+- __func__, max_cnt);
+-
+- cnt = 0;
+-
+- if (waitonly) {
+- /* Marker wait min 10 msecs. */
+- msleep(50);
+- cnt += 50;
+- }
+- while (1) {
+- if (!traced) {
+- ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
+- "%s: session sleep.\n",
+- __func__);
+- traced = true;
+- }
+- msleep(20);
+- cnt++;
+- if (waitonly && (fcport->disc_state == state ||
+- fcport->disc_state == DSC_LOGIN_COMPLETE))
+- break;
+- if (fcport->disc_state == DSC_LOGIN_AUTH_PEND)
+- break;
+- if (cnt > max_cnt)
+- break;
+- }
+-
+- if (!waitonly) {
+- ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
+- "%s: waited for session - %8phC, loopid=%x portid=%06x fcport=%p state=%u, cnt=%u\n",
+- __func__, fcport->port_name, fcport->loop_id,
+- fcport->d_id.b24, fcport, fcport->disc_state, cnt);
+- } else {
+- ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
+- "%s: waited ONLY for session - %8phC, loopid=%x portid=%06x fcport=%p state=%u, cnt=%u\n",
+- __func__, fcport->port_name, fcport->loop_id,
+- fcport->d_id.b24, fcport, fcport->disc_state, cnt);
+- }
+-}
+-
+ static void
+ qla_edif_free_sa_ctl(fc_port_t *fcport, struct edif_sa_ctl *sa_ctl,
+ int index)
+@@ -529,7 +472,8 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ struct app_start_reply appreply;
+ struct fc_port *fcport, *tf;
+
+- ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app start\n", __func__);
++ ql_log(ql_log_info, vha, 0x1313,
++ "EDIF application registration with driver, FC device connections will be re-established.\n");
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, &appstart,
+@@ -554,37 +498,36 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ qla2xxx_wake_dpc(vha);
+ } else {
+ list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
++ ql_dbg(ql_dbg_edif, vha, 0x2058,
++ "FCSP - nn %8phN pn %8phN portid=%06x.\n",
++ fcport->node_name, fcport->port_name,
++ fcport->d_id.b24);
+ ql_dbg(ql_dbg_edif, vha, 0xf084,
+- "%s: sess %p %8phC lid %#04x s_id %06x logout %d\n",
+- __func__, fcport, fcport->port_name,
+- fcport->loop_id, fcport->d_id.b24,
+- fcport->logout_on_delete);
+-
+- ql_dbg(ql_dbg_edif, vha, 0xf084,
+- "keep %d els_logo %d disc state %d auth state %d stop state %d\n",
+- fcport->keep_nport_handle,
+- fcport->send_els_logo, fcport->disc_state,
+- fcport->edif.auth_state, fcport->edif.app_stop);
++ "%s: se_sess %p / sess %p from port %8phC "
++ "loop_id %#04x s_id %06x logout %d "
++ "keep %d els_logo %d disc state %d auth state %d"
++ "stop state %d\n",
++ __func__, fcport->se_sess, fcport,
++ fcport->port_name, fcport->loop_id,
++ fcport->d_id.b24, fcport->logout_on_delete,
++ fcport->keep_nport_handle, fcport->send_els_logo,
++ fcport->disc_state, fcport->edif.auth_state,
++ fcport->edif.app_stop);
+
+ if (atomic_read(&vha->loop_state) == LOOP_DOWN)
+ break;
+- if (!(fcport->flags & FCF_FCSP_DEVICE))
+- continue;
+
+ fcport->edif.app_started = 1;
+- if (fcport->edif.app_stop ||
+- (fcport->disc_state != DSC_LOGIN_COMPLETE &&
+- fcport->disc_state != DSC_LOGIN_PEND &&
+- fcport->disc_state != DSC_DELETED)) {
+- /* no activity */
+- fcport->edif.app_stop = 0;
+-
+- ql_dbg(ql_dbg_edif, vha, 0x911e,
+- "%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
+- __func__, fcport->port_name);
+- fcport->edif.app_sess_online = 1;
+- qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 0);
+- }
++ fcport->login_retry = vha->hw->login_retry_count;
++
++ /* no activity */
++ fcport->edif.app_stop = 0;
++
++ ql_dbg(ql_dbg_edif, vha, 0x911e,
++ "%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
++ __func__, fcport->port_name);
++ fcport->edif.app_sess_online = 0;
++ qlt_schedule_sess_for_deletion(fcport);
+ qla_edif_sa_ctl_init(vha, fcport);
+ }
+ }
+@@ -601,14 +544,14 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ appreply.edif_enode_active = vha->pur_cinfo.enode_flags;
+ appreply.edif_edb_active = vha->e_dbell.db_flags;
+
+- bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
+- sizeof(struct app_start_reply);
++ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+
+ SET_DID_STATUS(bsg_reply->result, DID_OK);
+
+- sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+- bsg_job->reply_payload.sg_cnt, &appreply,
+- sizeof(struct app_start_reply));
++ bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
++ bsg_job->reply_payload.sg_cnt,
++ &appreply,
++ sizeof(struct app_start_reply));
+
+ ql_dbg(ql_dbg_edif, vha, 0x911d,
+ "%s app start completed with 0x%x\n",
+@@ -800,15 +743,15 @@ qla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ ql_dbg(ql_dbg_edif, vha, 0x911e,
+ "%s AUTH complete - RESUME with prli for wwpn %8phC\n",
+ __func__, fcport->port_name);
+- qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 1);
+ qla24xx_post_prli_work(vha, fcport);
+ }
+
+ errstate_exit:
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+- sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+- bsg_job->reply_payload.sg_cnt, &appplogireply,
+- sizeof(struct app_plogi_reply));
++ bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
++ bsg_job->reply_payload.sg_cnt,
++ &appplogireply,
++ sizeof(struct app_plogi_reply));
+
+ return rval;
+ }
+@@ -873,7 +816,7 @@ qla_edif_app_authfail(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+
+ if (qla_ini_mode_enabled(fcport->vha)) {
+ fcport->send_els_logo = 1;
+- qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 0);
++ qlt_schedule_sess_for_deletion(fcport);
+ }
+ }
+
+@@ -891,7 +834,7 @@ static int
+ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ {
+ int32_t rval = 0;
+- int32_t num_cnt;
++ int32_t pcnt = 0;
+ struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+ struct app_pinfo_req app_req;
+ struct app_pinfo_reply *app_reply;
+@@ -903,16 +846,14 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ bsg_job->request_payload.sg_cnt, &app_req,
+ sizeof(struct app_pinfo_req));
+
+- num_cnt = app_req.num_ports; /* num of ports alloc'd by app */
+-
+ app_reply = kzalloc((sizeof(struct app_pinfo_reply) +
+- sizeof(struct app_pinfo) * num_cnt), GFP_KERNEL);
++ sizeof(struct app_pinfo) * app_req.num_ports), GFP_KERNEL);
++
+ if (!app_reply) {
+ SET_DID_STATUS(bsg_reply->result, DID_ERROR);
+ rval = -1;
+ } else {
+ struct fc_port *fcport = NULL, *tf;
+- uint32_t pcnt = 0;
+
+ list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
+ if (!(fcport->flags & FCF_FCSP_DEVICE))
+@@ -924,7 +865,7 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ "APP request entry - portid=%06x.\n", tdid.b24);
+
+ /* Ran out of space */
+- if (pcnt > app_req.num_ports)
++ if (pcnt >= app_req.num_ports)
+ break;
+
+ if (tdid.b24 != 0 && tdid.b24 != fcport->d_id.b24)
+@@ -981,9 +922,11 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ SET_DID_STATUS(bsg_reply->result, DID_OK);
+ }
+
+- sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+- bsg_job->reply_payload.sg_cnt, app_reply,
+- sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * num_cnt);
++ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
++ bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
++ bsg_job->reply_payload.sg_cnt,
++ app_reply,
++ sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * pcnt);
+
+ kfree(app_reply);
+
+@@ -1000,10 +943,11 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ {
+ int32_t rval = 0;
+ struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+- uint32_t ret_size, size;
++ uint32_t size;
+
+ struct app_sinfo_req app_req;
+ struct app_stats_reply *app_reply;
++ uint32_t pcnt = 0;
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, &app_req,
+@@ -1019,18 +963,12 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ size = sizeof(struct app_stats_reply) +
+ (sizeof(struct app_sinfo) * app_req.num_ports);
+
+- if (size > bsg_job->reply_payload.payload_len)
+- ret_size = bsg_job->reply_payload.payload_len;
+- else
+- ret_size = size;
+-
+ app_reply = kzalloc(size, GFP_KERNEL);
+ if (!app_reply) {
+ SET_DID_STATUS(bsg_reply->result, DID_ERROR);
+ rval = -1;
+ } else {
+ struct fc_port *fcport = NULL, *tf;
+- uint32_t pcnt = 0;
+
+ list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
+ if (fcport->edif.enable) {
+@@ -1054,9 +992,11 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
+ SET_DID_STATUS(bsg_reply->result, DID_OK);
+ }
+
++ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+- bsg_job->reply_payload.sg_cnt, app_reply, ret_size);
++ bsg_job->reply_payload.sg_cnt, app_reply,
++ sizeof(struct app_stats_reply) + (sizeof(struct app_sinfo) * pcnt));
+
+ kfree(app_reply);
+
+@@ -1130,8 +1070,7 @@ qla_edif_app_mgmt(struct bsg_job *bsg_job)
+ __func__,
+ bsg_request->rqst_data.h_vendor.vendor_cmd[1]);
+ rval = EXT_STATUS_INVALID_PARAM;
+- bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+- SET_DID_STATUS(bsg_reply->result, DID_ERROR);
++ done = false;
+ break;
+ }
+
+@@ -1651,6 +1590,40 @@ qla_enode_stop(scsi_qla_host_t *vha)
+ spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
+ }
+
++static void qla_enode_clear(scsi_qla_host_t *vha, port_id_t portid)
++{
++ unsigned long flags;
++ struct enode *e, *tmp;
++ struct purexevent *purex;
++ LIST_HEAD(enode_list);
++
++ if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
++ ql_dbg(ql_dbg_edif, vha, 0x09102,
++ "%s enode not active\n", __func__);
++ return;
++ }
++ spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
++ list_for_each_entry_safe(e, tmp, &vha->pur_cinfo.head, list) {
++ purex = &e->u.purexinfo;
++ if (purex->pur_info.pur_sid.b24 == portid.b24) {
++ ql_dbg(ql_dbg_edif, vha, 0x911d,
++ "%s free ELS sid=%06x. xchg %x, nb=%xh\n",
++ __func__, portid.b24,
++ purex->pur_info.pur_rx_xchg_address,
++ purex->pur_info.pur_bytes_rcvd);
++
++ list_del_init(&e->list);
++ list_add_tail(&e->list, &enode_list);
++ }
++ }
++ spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
++
++ list_for_each_entry_safe(e, tmp, &enode_list, list) {
++ list_del_init(&e->list);
++ qla_enode_free(vha, e);
++ }
++}
++
+ /*
+ * allocate enode struct and populate buffer
+ * returns: enode pointer with buffers
+@@ -1850,6 +1823,57 @@ qla_edb_node_free(scsi_qla_host_t *vha, struct edb_node *node)
+ node->ntype = N_UNDEF;
+ }
+
++static void qla_edb_clear(scsi_qla_host_t *vha, port_id_t portid)
++{
++ unsigned long flags;
++ struct edb_node *e, *tmp;
++ port_id_t sid;
++ LIST_HEAD(edb_list);
++
++ if (vha->e_dbell.db_flags != EDB_ACTIVE) {
++ /* doorbell list not enabled */
++ ql_dbg(ql_dbg_edif, vha, 0x09102,
++ "%s doorbell not enabled\n", __func__);
++ return;
++ }
++
++ /* grab lock so list doesn't move */
++ spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
++ list_for_each_entry_safe(e, tmp, &vha->e_dbell.head, list) {
++ switch (e->ntype) {
++ case VND_CMD_AUTH_STATE_NEEDED:
++ case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
++ sid = e->u.plogi_did;
++ break;
++ case VND_CMD_AUTH_STATE_ELS_RCVD:
++ sid = e->u.els_sid;
++ break;
++ case VND_CMD_AUTH_STATE_SAUPDATE_COMPL:
++ /* app wants to see this */
++ continue;
++ default:
++ ql_log(ql_log_warn, vha, 0x09102,
++ "%s unknown node type: %x\n", __func__, e->ntype);
++ sid.b24 = 0;
++ break;
++ }
++ if (sid.b24 == portid.b24) {
++ ql_dbg(ql_dbg_edif, vha, 0x910f,
++ "%s free doorbell event : node type = %x %p\n",
++ __func__, e->ntype, e);
++ list_del_init(&e->list);
++ list_add_tail(&e->list, &edb_list);
++ }
++ }
++ spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
++
++ list_for_each_entry_safe(e, tmp, &edb_list, list) {
++ qla_edb_node_free(vha, e);
++ list_del_init(&e->list);
++ kfree(e);
++ }
++}
++
+ /* function called when app is stopping */
+
+ void
+@@ -2357,7 +2381,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
+ return;
+ }
+
+- if (totlen > MAX_PAYLOAD) {
++ if (totlen > ELS_MAX_PAYLOAD) {
+ ql_dbg(ql_dbg_edif, vha, 0x0910d,
+ "%s WARNING: verbose ELS frame received (totlen=%x)\n",
+ __func__, totlen);
+@@ -2436,7 +2460,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
+ ql_dbg(ql_dbg_edif, host, 0x0910c,
+ "%s COMPLETE purex->pur_info.pur_bytes_rcvd =%xh s:%06x -> d:%06x xchg=%xh\n",
+ __func__, purex->pur_info.pur_bytes_rcvd, purex->pur_info.pur_sid.b24,
+- purex->pur_info.pur_did.b24, p->rx_xchg_addr);
++ purex->pur_info.pur_did.b24, purex->pur_info.pur_rx_xchg_address);
+
+ qla_edb_eventcreate(host, VND_CMD_AUTH_STATE_ELS_RCVD, sid, 0, NULL);
+ }
+@@ -3459,3 +3483,12 @@ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess)
+ qla2x00_post_aen_work(vha, FCH_EVT_PORT_OFFLINE, sess->d_id.b24);
+ }
+ }
++
++void qla_edif_clear_appdata(struct scsi_qla_host *vha, struct fc_port *fcport)
++{
++ if (!(fcport->flags & FCF_FCSP_DEVICE))
++ return;
++
++ qla_edb_clear(vha, fcport->d_id);
++ qla_enode_clear(vha, fcport->d_id);
++}
+diff --git a/drivers/scsi/qla2xxx/qla_edif.h b/drivers/scsi/qla2xxx/qla_edif.h
+index 9e8f28d0caa1b..45cf87e337780 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.h
++++ b/drivers/scsi/qla2xxx/qla_edif.h
+@@ -93,7 +93,6 @@ struct sa_update_28xx {
+ };
+
+ #define NUM_ENTRIES 256
+-#define MAX_PAYLOAD 1024
+ #define PUR_GET 1
+
+ struct dinfo {
+@@ -128,6 +127,8 @@ struct enode {
+ } u;
+ };
+
++#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))
++
+ #define EDIF_SESSION_DOWN(_s) \
+ (qla_ini_mode_enabled(_s->vha) && (_s->disc_state == DSC_DELETE_PEND || \
+ _s->disc_state == DSC_DELETED || \
+diff --git a/drivers/scsi/qla2xxx/qla_edif_bsg.h b/drivers/scsi/qla2xxx/qla_edif_bsg.h
+index 58b718d35d19a..53026d82ebffe 100644
+--- a/drivers/scsi/qla2xxx/qla_edif_bsg.h
++++ b/drivers/scsi/qla2xxx/qla_edif_bsg.h
+@@ -8,7 +8,7 @@
+ #define __QLA_EDIF_BSG_H
+
+ /* BSG Vendor specific commands */
+-#define ELS_MAX_PAYLOAD 1024
++#define ELS_MAX_PAYLOAD 2112
+ #ifndef WWN_SIZE
+ #define WWN_SIZE 8
+ #endif
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index 1c3f055d41b8e..2c7e91bffb827 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -142,6 +142,8 @@ void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
+ void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport);
+ int qla_edif_process_els(scsi_qla_host_t *vha, struct bsg_job *bsgjob);
+ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess);
++void qla_edif_clear_appdata(struct scsi_qla_host *vha,
++ struct fc_port *fcport);
+ const char *sc_to_str(uint16_t cmd);
+
+ /*
+@@ -171,7 +173,6 @@ extern int ql2xasynctmfenable;
+ extern int ql2xgffidenable;
+ extern int ql2xenabledif;
+ extern int ql2xenablehba_err_chk;
+-extern int ql2xtargetreset;
+ extern int ql2xdontresethba;
+ extern uint64_t ql2xmaxlun;
+ extern int ql2xmdcapmask;
+@@ -816,7 +817,6 @@ extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
+ extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
+ extern void qlafx00_timer_routine(scsi_qla_host_t *);
+ extern int qlafx00_rescan_isp(scsi_qla_host_t *);
+-extern int qlafx00_loop_reset(scsi_qla_host_t *vha);
+
+ /* qla82xx related functions */
+
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 5fc7697f0af4c..847a6e5d9cb07 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -987,8 +987,6 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
+ sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1],
+ sp->u.iocb_cmd.u.mbx.in_mb[2]);
+
+- if (res == QLA_FUNCTION_TIMEOUT)
+- return;
+
+ sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
+ memset(&ea, 0, sizeof(ea));
+@@ -1026,8 +1024,8 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
+ list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
+- list_del_init(&fcport->gnl_entry);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
++ list_del_init(&fcport->gnl_entry);
+ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ ea.fcport = fcport;
+@@ -1786,16 +1784,52 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
+ fc_port_t *fcport;
+ unsigned long flags;
+
+- fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
+- if (fcport) {
+- if (fcport->flags & FCF_FCP2_DEVICE) {
+- ql_dbg(ql_dbg_disc, vha, 0x2115,
+- "Delaying session delete for FCP2 portid=%06x %8phC ",
+- fcport->d_id.b24, fcport->port_name);
+- return;
++ switch (ea->id.b.rsvd_1) {
++ case RSCN_PORT_ADDR:
++ fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
++ if (fcport) {
++ if (fcport->flags & FCF_FCP2_DEVICE) {
++ ql_dbg(ql_dbg_disc, vha, 0x2115,
++ "Delaying session delete for FCP2 portid=%06x %8phC ",
++ fcport->d_id.b24, fcport->port_name);
++ return;
++ }
++ fcport->scan_needed = 1;
++ fcport->rscn_gen++;
+ }
+- fcport->scan_needed = 1;
+- fcport->rscn_gen++;
++ break;
++ case RSCN_AREA_ADDR:
++ list_for_each_entry(fcport, &vha->vp_fcports, list) {
++ if (fcport->flags & FCF_FCP2_DEVICE)
++ continue;
++
++ if ((ea->id.b24 & 0xffff00) == (fcport->d_id.b24 & 0xffff00)) {
++ fcport->scan_needed = 1;
++ fcport->rscn_gen++;
++ }
++ }
++ break;
++ case RSCN_DOM_ADDR:
++ list_for_each_entry(fcport, &vha->vp_fcports, list) {
++ if (fcport->flags & FCF_FCP2_DEVICE)
++ continue;
++
++ if ((ea->id.b24 & 0xff0000) == (fcport->d_id.b24 & 0xff0000)) {
++ fcport->scan_needed = 1;
++ fcport->rscn_gen++;
++ }
++ }
++ break;
++ case RSCN_FAB_ADDR:
++ default:
++ list_for_each_entry(fcport, &vha->vp_fcports, list) {
++ if (fcport->flags & FCF_FCP2_DEVICE)
++ continue;
++
++ fcport->scan_needed = 1;
++ fcport->rscn_gen++;
++ }
++ break;
+ }
+
+ spin_lock_irqsave(&vha->work_lock, flags);
+@@ -4433,6 +4467,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
+ (ha->flags.fawwpn_enabled) ? "enabled" : "disabled");
+ }
+
++ /* ELS pass through payload is limit by frame size. */
++ if (ha->flags.edif_enabled)
++ mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD);
++
+ rval = qla2x00_init_firmware(vha, ha->init_cb_size);
+ next_check:
+ if (rval) {
+@@ -5335,15 +5373,14 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
+ "LOOP READY.\n");
+ ha->flags.fw_init_done = 1;
+
++ /*
++ * use link up to wake up app to get ready for
++ * authentication.
++ */
+ if (ha->flags.edif_enabled &&
+- !(vha->e_dbell.db_flags & EDB_ACTIVE) &&
+- N2N_TOPO(vha->hw)) {
+- /*
+- * use port online to wake up app to get ready
+- * for authentication
+- */
+- qla2x00_post_aen_work(vha, FCH_EVT_PORT_ONLINE, 0);
+- }
++ !(vha->e_dbell.db_flags & EDB_ACTIVE))
++ qla2x00_post_aen_work(vha, FCH_EVT_LINKUP,
++ ha->link_data_rate);
+
+ /*
+ * Process any ATIO queue entries that came in
+diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
+index 7811c4952035b..a6debeea30798 100644
+--- a/drivers/scsi/qla2xxx/qla_mbx.c
++++ b/drivers/scsi/qla2xxx/qla_mbx.c
+@@ -1695,10 +1695,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
+ mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
+ if (IS_FWI2_CAPABLE(vha->hw))
+ mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
+- if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
+- mcp->in_mb |= MBX_15;
+- mcp->out_mb |= MBX_7|MBX_21|MBX_22|MBX_23;
+- }
++ if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
++ mcp->in_mb |= MBX_15|MBX_21|MBX_22|MBX_23;
+
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
+index 6e920da64863e..350b0c4346fb6 100644
+--- a/drivers/scsi/qla2xxx/qla_mr.c
++++ b/drivers/scsi/qla2xxx/qla_mr.c
+@@ -738,29 +738,6 @@ qlafx00_lun_reset(fc_port_t *fcport, uint64_t l, int tag)
+ return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+ }
+
+-int
+-qlafx00_loop_reset(scsi_qla_host_t *vha)
+-{
+- int ret;
+- struct fc_port *fcport;
+- struct qla_hw_data *ha = vha->hw;
+-
+- if (ql2xtargetreset) {
+- list_for_each_entry(fcport, &vha->vp_fcports, list) {
+- if (fcport->port_type != FCT_TARGET)
+- continue;
+-
+- ret = ha->isp_ops->target_reset(fcport, 0, 0);
+- if (ret != QLA_SUCCESS) {
+- ql_dbg(ql_dbg_taskm, vha, 0x803d,
+- "Bus Reset failed: Reset=%d "
+- "d_id=%x.\n", ret, fcport->d_id.b24);
+- }
+- }
+- }
+- return QLA_SUCCESS;
+-}
+-
+ int
+ qlafx00_iospace_config(struct qla_hw_data *ha)
+ {
+diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
+index 1c5da2dbd6f97..877b2b6250204 100644
+--- a/drivers/scsi/qla2xxx/qla_nvme.c
++++ b/drivers/scsi/qla2xxx/qla_nvme.c
+@@ -228,6 +228,8 @@ static void qla_nvme_abort_work(struct work_struct *work)
+ fc_port_t *fcport = sp->fcport;
+ struct qla_hw_data *ha = fcport->vha->hw;
+ int rval, abts_done_called = 1;
++ bool io_wait_for_abort_done;
++ uint32_t handle;
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0xffff,
+ "%s called for sp=%p, hndl=%x on fcport=%p desc=%p deleted=%d\n",
+@@ -244,12 +246,20 @@ static void qla_nvme_abort_work(struct work_struct *work)
+ goto out;
+ }
+
++ /*
++ * sp may not be valid after abort_command if return code is either
++ * SUCCESS or ERR_FROM_FW codes, so cache the value here.
++ */
++ io_wait_for_abort_done = ql2xabts_wait_nvme &&
++ QLA_ABTS_WAIT_ENABLED(sp);
++ handle = sp->handle;
++
+ rval = ha->isp_ops->abort_command(sp);
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0x212b,
+ "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n",
+ __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
+- sp, sp->handle, fcport, rval);
++ sp, handle, fcport, rval);
+
+ /*
+ * If async tmf is enabled, the abort callback is called only on
+@@ -264,7 +274,7 @@ static void qla_nvme_abort_work(struct work_struct *work)
+ * are waited until ABTS complete. This kref is decreased
+ * at qla24xx_abort_sp_done function.
+ */
+- if (abts_done_called && ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(sp))
++ if (abts_done_called && io_wait_for_abort_done)
+ return;
+ out:
+ /* kref_get was done before work was schedule. */
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 836fedcea241b..8d87cfae9c598 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -202,12 +202,6 @@ MODULE_PARM_DESC(ql2xdbwr,
+ " 0 -- Regular doorbell.\n"
+ " 1 -- CAMRAM doorbell (faster).\n");
+
+-int ql2xtargetreset = 1;
+-module_param(ql2xtargetreset, int, S_IRUGO);
+-MODULE_PARM_DESC(ql2xtargetreset,
+- "Enable target reset."
+- "Default is 1 - use hw defaults.");
+-
+ int ql2xgffidenable;
+ module_param(ql2xgffidenable, int, S_IRUGO);
+ MODULE_PARM_DESC(ql2xgffidenable,
+@@ -1258,6 +1252,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+ uint32_t ratov_j;
+ struct qla_qpair *qpair;
+ unsigned long flags;
++ int fast_fail_status = SUCCESS;
+
+ if (qla2x00_isp_reg_stat(ha)) {
+ ql_log(ql_log_info, vha, 0x8042,
+@@ -1266,9 +1261,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+ return FAILED;
+ }
+
++ /* Save any FAST_IO_FAIL value to return later if abort succeeds */
+ ret = fc_block_scsi_eh(cmd);
+ if (ret != 0)
+- return ret;
++ fast_fail_status = ret;
+
+ sp = scsi_cmd_priv(cmd);
+ qpair = sp->qpair;
+@@ -1276,7 +1272,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+ vha->cmd_timeout_cnt++;
+
+ if ((sp->fcport && sp->fcport->deleted) || !qpair)
+- return SUCCESS;
++ return fast_fail_status != SUCCESS ? fast_fail_status : FAILED;
+
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+ sp->comp = &comp;
+@@ -1311,7 +1307,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+ __func__, ha->r_a_tov/10);
+ ret = FAILED;
+ } else {
+- ret = SUCCESS;
++ ret = fast_fail_status;
+ }
+ break;
+ default:
+@@ -1693,27 +1689,10 @@ int
+ qla2x00_loop_reset(scsi_qla_host_t *vha)
+ {
+ int ret;
+- struct fc_port *fcport;
+ struct qla_hw_data *ha = vha->hw;
+
+- if (IS_QLAFX00(ha)) {
+- return qlafx00_loop_reset(vha);
+- }
+-
+- if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
+- list_for_each_entry(fcport, &vha->vp_fcports, list) {
+- if (fcport->port_type != FCT_TARGET)
+- continue;
+-
+- ret = ha->isp_ops->target_reset(fcport, 0, 0);
+- if (ret != QLA_SUCCESS) {
+- ql_dbg(ql_dbg_taskm, vha, 0x802c,
+- "Bus Reset failed: Reset=%d "
+- "d_id=%x.\n", ret, fcport->d_id.b24);
+- }
+- }
+- }
+-
++ if (IS_QLAFX00(ha))
++ return QLA_SUCCESS;
+
+ if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+@@ -4358,7 +4337,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
+
+ /* allocate the purex dma pool */
+ ha->purex_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+- MAX_PAYLOAD, 8, 0);
++ ELS_MAX_PAYLOAD, 8, 0);
+
+ if (!ha->purex_dma_pool) {
+ ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
+diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
+index 7d8242c120fc7..1aaa4238cb722 100644
+--- a/drivers/scsi/qla2xxx/qla_target.c
++++ b/drivers/scsi/qla2xxx/qla_target.c
+@@ -1003,6 +1003,7 @@ void qlt_free_session_done(struct work_struct *work)
+ "%s bypassing release_all_sadb\n",
+ __func__);
+ }
++ qla_edif_clear_appdata(vha, sess);
+ qla_edif_sess_down(vha, sess);
+ }
+ qla2x00_mark_device_lost(vha, sess, 0);
+diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
+index 66f507469a31a..cfeadd5f61f18 100644
+--- a/drivers/scsi/scsi_debug.c
++++ b/drivers/scsi/scsi_debug.c
+@@ -1189,7 +1189,7 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
+ __func__, off_dst, scsi_bufflen(scp), act_len,
+ scsi_get_resid(scp));
+ n = scsi_bufflen(scp) - (off_dst + act_len);
+- scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
++ scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
+ return 0;
+ }
+
+@@ -1562,7 +1562,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+ unsigned char pq_pdt;
+ unsigned char *arr;
+ unsigned char *cmd = scp->cmnd;
+- int alloc_len, n, ret;
++ u32 alloc_len, n;
++ int ret;
+ bool have_wlun, is_disk, is_zbc, is_disk_zbc;
+
+ alloc_len = get_unaligned_be16(cmd + 3);
+@@ -1585,7 +1586,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+ kfree(arr);
+ return check_condition_result;
+ } else if (0x1 & cmd[1]) { /* EVPD bit set */
+- int lu_id_num, port_group_id, target_dev_id, len;
++ int lu_id_num, port_group_id, target_dev_id;
++ u32 len;
+ char lu_id_str[6];
+ int host_no = devip->sdbg_host->shost->host_no;
+
+@@ -1676,9 +1678,9 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+ kfree(arr);
+ return check_condition_result;
+ }
+- len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
++ len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
+ ret = fill_from_dev_buffer(scp, arr,
+- min(len, SDEBUG_MAX_INQ_ARR_SZ));
++ min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
+ kfree(arr);
+ return ret;
+ }
+@@ -1714,7 +1716,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+ }
+ put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
+ ret = fill_from_dev_buffer(scp, arr,
+- min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
++ min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
+ kfree(arr);
+ return ret;
+ }
+@@ -1729,8 +1731,8 @@ static int resp_requests(struct scsi_cmnd *scp,
+ unsigned char *cmd = scp->cmnd;
+ unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */
+ bool dsense = !!(cmd[1] & 1);
+- int alloc_len = cmd[4];
+- int len = 18;
++ u32 alloc_len = cmd[4];
++ u32 len = 18;
+ int stopped_state = atomic_read(&devip->stopped);
+
+ memset(arr, 0, sizeof(arr));
+@@ -1774,7 +1776,7 @@ static int resp_requests(struct scsi_cmnd *scp,
+ arr[7] = 0xa;
+ }
+ }
+- return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
++ return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
+ }
+
+ static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+@@ -1856,7 +1858,7 @@ static int resp_readcap16(struct scsi_cmnd *scp,
+ {
+ unsigned char *cmd = scp->cmnd;
+ unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
+- int alloc_len;
++ u32 alloc_len;
+
+ alloc_len = get_unaligned_be32(cmd + 10);
+ /* following just in case virtual_gb changed */
+@@ -1885,7 +1887,7 @@ static int resp_readcap16(struct scsi_cmnd *scp,
+ }
+
+ return fill_from_dev_buffer(scp, arr,
+- min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
++ min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
+ }
+
+ #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
+@@ -1896,8 +1898,9 @@ static int resp_report_tgtpgs(struct scsi_cmnd *scp,
+ unsigned char *cmd = scp->cmnd;
+ unsigned char *arr;
+ int host_no = devip->sdbg_host->shost->host_no;
+- int n, ret, alen, rlen;
+ int port_group_a, port_group_b, port_a, port_b;
++ u32 alen, n, rlen;
++ int ret;
+
+ alen = get_unaligned_be32(cmd + 6);
+ arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
+@@ -1959,9 +1962,9 @@ static int resp_report_tgtpgs(struct scsi_cmnd *scp,
+ * - The constructed command length
+ * - The maximum array size
+ */
+- rlen = min_t(int, alen, n);
++ rlen = min(alen, n);
+ ret = fill_from_dev_buffer(scp, arr,
+- min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
++ min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
+ kfree(arr);
+ return ret;
+ }
+@@ -2311,7 +2314,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ {
+ int pcontrol, pcode, subpcode, bd_len;
+ unsigned char dev_spec;
+- int alloc_len, offset, len, target_dev_id;
++ u32 alloc_len, offset, len;
++ int target_dev_id;
+ int target = scp->device->id;
+ unsigned char *ap;
+ unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
+@@ -2467,7 +2471,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
+ arr[0] = offset - 1;
+ else
+ put_unaligned_be16((offset - 2), arr + 0);
+- return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
++ return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
+ }
+
+ #define SDEBUG_MAX_MSELECT_SZ 512
+@@ -2498,11 +2502,11 @@ static int resp_mode_select(struct scsi_cmnd *scp,
+ __func__, param_len, res);
+ md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
+ bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
+- if (md_len > 2) {
++ off = bd_len + (mselect6 ? 4 : 8);
++ if (md_len > 2 || off >= res) {
+ mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
+ return check_condition_result;
+ }
+- off = bd_len + (mselect6 ? 4 : 8);
+ mpage = arr[off] & 0x3f;
+ ps = !!(arr[off] & 0x80);
+ if (ps) {
+@@ -2582,7 +2586,8 @@ static int resp_ie_l_pg(unsigned char *arr)
+ static int resp_log_sense(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
+ {
+- int ppc, sp, pcode, subpcode, alloc_len, len, n;
++ int ppc, sp, pcode, subpcode;
++ u32 alloc_len, len, n;
+ unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
+ unsigned char *cmd = scp->cmnd;
+
+@@ -2652,9 +2657,9 @@ static int resp_log_sense(struct scsi_cmnd *scp,
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
+ return check_condition_result;
+ }
+- len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
++ len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
+ return fill_from_dev_buffer(scp, arr,
+- min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
++ min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
+ }
+
+ static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
+@@ -4258,6 +4263,8 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+ mk_sense_invalid_opcode(scp);
+ return check_condition_result;
+ }
++ if (vnum == 0)
++ return 0; /* not an error */
+ a_num = is_bytchk3 ? 1 : vnum;
+ /* Treat following check like one for read (i.e. no write) access */
+ ret = check_device_access_params(scp, lba, a_num, false);
+@@ -4321,6 +4328,8 @@ static int resp_report_zones(struct scsi_cmnd *scp,
+ }
+ zs_lba = get_unaligned_be64(cmd + 2);
+ alloc_len = get_unaligned_be32(cmd + 10);
++ if (alloc_len == 0)
++ return 0; /* not an error */
+ rep_opts = cmd[14] & 0x3f;
+ partial = cmd[14] & 0x80;
+
+@@ -4333,7 +4342,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
+ rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
+ max_zones);
+
+- arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
++ arr = kzalloc(alloc_len, GFP_ATOMIC);
+ if (!arr) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
+@@ -4425,7 +4434,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
+ put_unaligned_be64(sdebug_capacity - 1, arr + 8);
+
+ rep_len = (unsigned long)desc - (unsigned long)arr;
+- ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
++ ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
+
+ fini:
+ read_unlock(macc_lckp);
+@@ -4648,6 +4657,7 @@ static void zbc_rwp_zone(struct sdebug_dev_info *devip,
+ struct sdeb_zone_state *zsp)
+ {
+ enum sdebug_z_cond zc;
++ struct sdeb_store_info *sip = devip2sip(devip, false);
+
+ if (zbc_zone_is_conv(zsp))
+ return;
+@@ -4659,6 +4669,10 @@ static void zbc_rwp_zone(struct sdebug_dev_info *devip,
+ if (zsp->z_cond == ZC4_CLOSED)
+ devip->nr_closed--;
+
++ if (zsp->z_wp > zsp->z_start)
++ memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
++ (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
++
+ zsp->z_non_seq_resource = false;
+ zsp->z_wp = zsp->z_start;
+ zsp->z_cond = ZC1_EMPTY;
+diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
+index b6c86cce57bfa..408d49c304b8d 100644
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -135,6 +135,23 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)
+ return true;
+ }
+
++static void scsi_eh_complete_abort(struct scsi_cmnd *scmd, struct Scsi_Host *shost)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(shost->host_lock, flags);
++ list_del_init(&scmd->eh_entry);
++ /*
++ * If the abort succeeds, and there is no further
++ * EH action, clear the ->last_reset time.
++ */
++ if (list_empty(&shost->eh_abort_list) &&
++ list_empty(&shost->eh_cmd_q))
++ if (shost->eh_deadline != -1)
++ shost->last_reset = 0;
++ spin_unlock_irqrestore(shost->host_lock, flags);
++}
++
+ /**
+ * scmd_eh_abort_handler - Handle command aborts
+ * @work: command to be aborted.
+@@ -152,6 +169,7 @@ scmd_eh_abort_handler(struct work_struct *work)
+ container_of(work, struct scsi_cmnd, abort_work.work);
+ struct scsi_device *sdev = scmd->device;
+ enum scsi_disposition rtn;
++ unsigned long flags;
+
+ if (scsi_host_eh_past_deadline(sdev->host)) {
+ SCSI_LOG_ERROR_RECOVERY(3,
+@@ -175,12 +193,14 @@ scmd_eh_abort_handler(struct work_struct *work)
+ SCSI_LOG_ERROR_RECOVERY(3,
+ scmd_printk(KERN_WARNING, scmd,
+ "retry aborted command\n"));
++ scsi_eh_complete_abort(scmd, sdev->host);
+ scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+ return;
+ } else {
+ SCSI_LOG_ERROR_RECOVERY(3,
+ scmd_printk(KERN_WARNING, scmd,
+ "finish aborted command\n"));
++ scsi_eh_complete_abort(scmd, sdev->host);
+ scsi_finish_command(scmd);
+ return;
+ }
+@@ -193,6 +213,9 @@ scmd_eh_abort_handler(struct work_struct *work)
+ }
+ }
+
++ spin_lock_irqsave(sdev->host->host_lock, flags);
++ list_del_init(&scmd->eh_entry);
++ spin_unlock_irqrestore(sdev->host->host_lock, flags);
+ scsi_eh_scmd_add(scmd);
+ }
+
+@@ -223,6 +246,8 @@ scsi_abort_command(struct scsi_cmnd *scmd)
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (shost->eh_deadline != -1 && !shost->last_reset)
+ shost->last_reset = jiffies;
++ BUG_ON(!list_empty(&scmd->eh_entry));
++ list_add_tail(&scmd->eh_entry, &shost->eh_abort_list);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
+diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
+index 6ff2207bd45a0..a06c61f22742e 100644
+--- a/drivers/scsi/scsi_ioctl.c
++++ b/drivers/scsi/scsi_ioctl.c
+@@ -347,6 +347,8 @@ static int scsi_fill_sghdr_rq(struct scsi_device *sdev, struct request *rq,
+ {
+ struct scsi_request *req = scsi_req(rq);
+
++ if (hdr->cmd_len < 6)
++ return -EMSGSIZE;
+ if (copy_from_user(req->cmd, hdr->cmdp, hdr->cmd_len))
+ return -EFAULT;
+ if (!scsi_cmd_allowed(req->cmd, mode))
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index 572673873ddf8..ef4361b2d1423 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -1143,6 +1143,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
+ cmd->sense_buffer = buf;
+ cmd->prot_sdb = prot;
+ cmd->flags = flags;
++ INIT_LIST_HEAD(&cmd->eh_entry);
+ INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+ cmd->jiffies_at_alloc = jiffies_at_alloc;
+ cmd->retries = retries;
+@@ -1174,8 +1175,6 @@ static blk_status_t scsi_setup_scsi_cmnd(struct scsi_device *sdev,
+ }
+
+ cmd->cmd_len = scsi_req(req)->cmd_len;
+- if (cmd->cmd_len == 0)
+- cmd->cmd_len = scsi_command_size(cmd->cmnd);
+ cmd->cmnd = scsi_req(req)->cmd;
+ cmd->transfersize = blk_rq_bytes(req);
+ cmd->allowed = scsi_req(req)->retries;
+@@ -2075,7 +2074,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
+ /**
+ * scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
+ * @sdev: SCSI device to be queried
+- * @dbd: set if mode sense will allow block descriptors to be returned
++ * @dbd: set to prevent mode sense from returning block descriptors
+ * @modepage: mode page being requested
+ * @buffer: request buffer (may not be smaller than eight bytes)
+ * @len: length of request buffer.
+@@ -2110,18 +2109,18 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ sshdr = &my_sshdr;
+
+ retry:
+- use_10_for_ms = sdev->use_10_for_ms;
++ use_10_for_ms = sdev->use_10_for_ms || len > 255;
+
+ if (use_10_for_ms) {
+- if (len < 8)
+- len = 8;
++ if (len < 8 || len > 65535)
++ return -EINVAL;
+
+ cmd[0] = MODE_SENSE_10;
+- cmd[8] = len;
++ put_unaligned_be16(len, &cmd[7]);
+ header_length = 8;
+ } else {
+ if (len < 4)
+- len = 4;
++ return -EINVAL;
+
+ cmd[0] = MODE_SENSE;
+ cmd[4] = len;
+@@ -2145,9 +2144,15 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ if ((sshdr->sense_key == ILLEGAL_REQUEST) &&
+ (sshdr->asc == 0x20) && (sshdr->ascq == 0)) {
+ /*
+- * Invalid command operation code
++ * Invalid command operation code: retry using
++ * MODE SENSE(6) if this was a MODE SENSE(10)
++ * request, except if the request mode page is
++ * too large for MODE SENSE single byte
++ * allocation length field.
+ */
+ if (use_10_for_ms) {
++ if (len > 255)
++ return -EIO;
+ sdev->use_10_for_ms = 0;
+ goto retry;
+ }
+@@ -2171,12 +2176,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ data->longlba = 0;
+ data->block_descriptor_length = 0;
+ } else if (use_10_for_ms) {
+- data->length = buffer[0]*256 + buffer[1] + 2;
++ data->length = get_unaligned_be16(&buffer[0]) + 2;
+ data->medium_type = buffer[2];
+ data->device_specific = buffer[3];
+ data->longlba = buffer[4] & 0x01;
+- data->block_descriptor_length = buffer[6]*256
+- + buffer[7];
++ data->block_descriptor_length = get_unaligned_be16(&buffer[6]);
+ } else {
+ data->length = buffer[0] + 1;
+ data->medium_type = buffer[1];
+diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
+index a35841b34bfd9..920aae661c5b2 100644
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -797,6 +797,7 @@ store_state_field(struct device *dev, struct device_attribute *attr,
+ int i, ret;
+ struct scsi_device *sdev = to_scsi_device(dev);
+ enum scsi_device_state state = 0;
++ bool rescan_dev = false;
+
+ for (i = 0; i < ARRAY_SIZE(sdev_states); i++) {
+ const int len = strlen(sdev_states[i].name);
+@@ -815,20 +816,27 @@ store_state_field(struct device *dev, struct device_attribute *attr,
+ }
+
+ mutex_lock(&sdev->state_mutex);
+- ret = scsi_device_set_state(sdev, state);
+- /*
+- * If the device state changes to SDEV_RUNNING, we need to
+- * run the queue to avoid I/O hang, and rescan the device
+- * to revalidate it. Running the queue first is necessary
+- * because another thread may be waiting inside
+- * blk_mq_freeze_queue_wait() and because that call may be
+- * waiting for pending I/O to finish.
+- */
+- if (ret == 0 && state == SDEV_RUNNING) {
++ if (sdev->sdev_state == SDEV_RUNNING && state == SDEV_RUNNING) {
++ ret = 0;
++ } else {
++ ret = scsi_device_set_state(sdev, state);
++ if (ret == 0 && state == SDEV_RUNNING)
++ rescan_dev = true;
++ }
++ mutex_unlock(&sdev->state_mutex);
++
++ if (rescan_dev) {
++ /*
++ * If the device state changes to SDEV_RUNNING, we need to
++ * run the queue to avoid I/O hang, and rescan the device
++ * to revalidate it. Running the queue first is necessary
++ * because another thread may be waiting inside
++ * blk_mq_freeze_queue_wait() and because that call may be
++ * waiting for pending I/O to finish.
++ */
+ blk_mq_run_hw_queues(sdev->request_queue, true);
+ scsi_rescan_device(dev);
+ }
+- mutex_unlock(&sdev->state_mutex);
+
+ return ret == 0 ? count : -EINVAL;
+ }
+@@ -1388,6 +1396,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
+ * We're treating error on bsg register as non-fatal, so
+ * pretend nothing went wrong.
+ */
++ error = PTR_ERR(sdev->bsg_dev);
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to register bsg queue, errno=%d\n",
+ error);
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 78343d3f93857..554b6f7842236 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -1899,12 +1899,12 @@ static void session_recovery_timedout(struct work_struct *work)
+ }
+ spin_unlock_irqrestore(&session->lock, flags);
+
+- if (session->transport->session_recovery_timedout)
+- session->transport->session_recovery_timedout(session);
+-
+ ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
+ scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
+ ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
++
++ if (session->transport->session_recovery_timedout)
++ session->transport->session_recovery_timedout(session);
+ }
+
+ static void __iscsi_unblock_session(struct work_struct *work)
+diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
+index fce63335084ed..78ead3369779c 100644
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -2607,6 +2607,13 @@ sd_do_mode_sense(struct scsi_disk *sdkp, int dbd, int modepage,
+ unsigned char *buffer, int len, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *sshdr)
+ {
++ /*
++ * If we must use MODE SENSE(10), make sure that the buffer length
++ * is at least 8 bytes so that the mode sense header fits.
++ */
++ if (sdkp->device->use_10_for_ms && len < 8)
++ len = 8;
++
+ return scsi_mode_sense(sdkp->device, dbd, modepage, buffer, len,
+ SD_TIMEOUT, sdkp->max_retries, data,
+ sshdr);
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index ecb2af3f43ca3..a5453f5e87c3e 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -234,15 +234,46 @@ static inline bool pqi_is_hba_lunid(u8 *scsi3addr)
+ return pqi_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID);
+ }
+
++#define PQI_DRIVER_SCRATCH_PQI_MODE 0x1
++#define PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED 0x2
++
+ static inline enum pqi_ctrl_mode pqi_get_ctrl_mode(struct pqi_ctrl_info *ctrl_info)
+ {
+- return sis_read_driver_scratch(ctrl_info);
++ return sis_read_driver_scratch(ctrl_info) & PQI_DRIVER_SCRATCH_PQI_MODE ? PQI_MODE : SIS_MODE;
+ }
+
+ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info,
+ enum pqi_ctrl_mode mode)
+ {
+- sis_write_driver_scratch(ctrl_info, mode);
++ u32 driver_scratch;
++
++ driver_scratch = sis_read_driver_scratch(ctrl_info);
++
++ if (mode == PQI_MODE)
++ driver_scratch |= PQI_DRIVER_SCRATCH_PQI_MODE;
++ else
++ driver_scratch &= ~PQI_DRIVER_SCRATCH_PQI_MODE;
++
++ sis_write_driver_scratch(ctrl_info, driver_scratch);
++}
++
++static inline bool pqi_is_fw_triage_supported(struct pqi_ctrl_info *ctrl_info)
++{
++ return (sis_read_driver_scratch(ctrl_info) & PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED) != 0;
++}
++
++static inline void pqi_save_fw_triage_setting(struct pqi_ctrl_info *ctrl_info, bool is_supported)
++{
++ u32 driver_scratch;
++
++ driver_scratch = sis_read_driver_scratch(ctrl_info);
++
++ if (is_supported)
++ driver_scratch |= PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED;
++ else
++ driver_scratch &= ~PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED;
++
++ sis_write_driver_scratch(ctrl_info, driver_scratch);
+ }
+
+ static inline void pqi_ctrl_block_scan(struct pqi_ctrl_info *ctrl_info)
+@@ -7301,6 +7332,7 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info,
+ ctrl_info->unique_wwid_in_report_phys_lun_supported =
+ firmware_feature->enabled;
+ break;
++ pqi_save_fw_triage_setting(ctrl_info, firmware_feature->enabled);
+ }
+
+ pqi_firmware_feature_status(ctrl_info, firmware_feature);
+@@ -7627,6 +7659,11 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
+ u32 product_id;
+
+ if (reset_devices) {
++ if (pqi_is_fw_triage_supported(ctrl_info)) {
++ rc = sis_wait_for_fw_triage_completion(ctrl_info);
++ if (rc)
++ return rc;
++ }
+ sis_soft_reset(ctrl_info);
+ msleep(PQI_POST_RESET_DELAY_SECS * PQI_HZ);
+ } else {
+diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c
+index d63c46a8e38bb..8acd3a80f5822 100644
+--- a/drivers/scsi/smartpqi/smartpqi_sis.c
++++ b/drivers/scsi/smartpqi/smartpqi_sis.c
+@@ -51,12 +51,20 @@
+ #define SIS_BASE_STRUCT_REVISION 9
+ #define SIS_BASE_STRUCT_ALIGNMENT 16
+
++#define SIS_CTRL_KERNEL_FW_TRIAGE 0x3
+ #define SIS_CTRL_KERNEL_UP 0x80
+ #define SIS_CTRL_KERNEL_PANIC 0x100
+ #define SIS_CTRL_READY_TIMEOUT_SECS 180
+ #define SIS_CTRL_READY_RESUME_TIMEOUT_SECS 90
+ #define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10
+
++enum sis_fw_triage_status {
++ FW_TRIAGE_NOT_STARTED = 0,
++ FW_TRIAGE_STARTED,
++ FW_TRIAGE_COND_INVALID,
++ FW_TRIAGE_COMPLETED
++};
++
+ #pragma pack(1)
+
+ /* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */
+@@ -419,12 +427,55 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info)
+ return readl(&ctrl_info->registers->sis_driver_scratch);
+ }
+
++static inline enum sis_fw_triage_status
++ sis_read_firmware_triage_status(struct pqi_ctrl_info *ctrl_info)
++{
++ return ((enum sis_fw_triage_status)(readl(&ctrl_info->registers->sis_firmware_status) &
++ SIS_CTRL_KERNEL_FW_TRIAGE));
++}
++
+ void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
+ {
+ writel(SIS_SOFT_RESET,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ }
+
++#define SIS_FW_TRIAGE_STATUS_TIMEOUT_SECS 300
++#define SIS_FW_TRIAGE_STATUS_POLL_INTERVAL_SECS 1
++
++int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info)
++{
++ int rc;
++ enum sis_fw_triage_status status;
++ unsigned long timeout;
++
++ timeout = (SIS_FW_TRIAGE_STATUS_TIMEOUT_SECS * PQI_HZ) + jiffies;
++ while (1) {
++ status = sis_read_firmware_triage_status(ctrl_info);
++ if (status == FW_TRIAGE_COND_INVALID) {
++ dev_err(&ctrl_info->pci_dev->dev,
++ "firmware triage condition invalid\n");
++ rc = -EINVAL;
++ break;
++ } else if (status == FW_TRIAGE_NOT_STARTED ||
++ status == FW_TRIAGE_COMPLETED) {
++ rc = 0;
++ break;
++ }
++
++ if (time_after(jiffies, timeout)) {
++ dev_err(&ctrl_info->pci_dev->dev,
++ "timed out waiting for firmware triage status\n");
++ rc = -ETIMEDOUT;
++ break;
++ }
++
++ ssleep(SIS_FW_TRIAGE_STATUS_POLL_INTERVAL_SECS);
++ }
++
++ return rc;
++}
++
+ static void __attribute__((unused)) verify_structures(void)
+ {
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h
+index d29c1352a826a..c1db93054c863 100644
+--- a/drivers/scsi/smartpqi/smartpqi_sis.h
++++ b/drivers/scsi/smartpqi/smartpqi_sis.h
+@@ -28,5 +28,6 @@ void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
+ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);
+ void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
+ u32 sis_get_product_id(struct pqi_ctrl_info *ctrl_info);
++int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info);
+
+ #endif /* _SMARTPQI_SIS_H */
+diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
+index 51424557810da..f725248ba57f4 100644
+--- a/drivers/scsi/ufs/ufshcd-pci.c
++++ b/drivers/scsi/ufs/ufshcd-pci.c
+@@ -421,6 +421,13 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba)
+ return err;
+ }
+
++static int ufs_intel_adl_init(struct ufs_hba *hba)
++{
++ hba->nop_out_timeout = 200;
++ hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
++ return ufs_intel_common_init(hba);
++}
++
+ static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = {
+ .name = "intel-pci",
+ .init = ufs_intel_common_init,
+@@ -449,6 +456,15 @@ static struct ufs_hba_variant_ops ufs_intel_lkf_hba_vops = {
+ .device_reset = ufs_intel_device_reset,
+ };
+
++static struct ufs_hba_variant_ops ufs_intel_adl_hba_vops = {
++ .name = "intel-pci",
++ .init = ufs_intel_adl_init,
++ .exit = ufs_intel_common_exit,
++ .link_startup_notify = ufs_intel_link_startup_notify,
++ .resume = ufs_intel_resume,
++ .device_reset = ufs_intel_device_reset,
++};
++
+ #ifdef CONFIG_PM_SLEEP
+ static int ufshcd_pci_restore(struct device *dev)
+ {
+@@ -563,6 +579,8 @@ static const struct pci_device_id ufshcd_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops },
++ { PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops },
++ { PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops },
+ { } /* terminate list */
+ };
+
+diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
+index 8859c13f4e091..eaeae83b999fd 100644
+--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
++++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
+@@ -91,7 +91,7 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
+
+ clki->min_freq = clkfreq[i];
+ clki->max_freq = clkfreq[i+1];
+- clki->name = kstrdup(name, GFP_KERNEL);
++ clki->name = devm_kstrdup(dev, name, GFP_KERNEL);
+ if (!strcmp(name, "ref_clk"))
+ clki->keep_link_active = true;
+ dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
+@@ -126,7 +126,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
+ if (!vreg)
+ return -ENOMEM;
+
+- vreg->name = kstrdup(name, GFP_KERNEL);
++ vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
+
+ snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
+ if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
+diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
+index 41f2ff35f82b2..31adf25e57b0d 100644
+--- a/drivers/scsi/ufs/ufshcd.c
++++ b/drivers/scsi/ufs/ufshcd.c
+@@ -222,8 +222,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
+ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
+ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
+ static void ufshcd_hba_exit(struct ufs_hba *hba);
+-static int ufshcd_clear_ua_wluns(struct ufs_hba *hba);
+-static int ufshcd_probe_hba(struct ufs_hba *hba, bool async);
++static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params);
+ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+ static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
+ static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
+@@ -4073,8 +4072,6 @@ int ufshcd_link_recovery(struct ufs_hba *hba)
+ if (ret)
+ dev_err(hba->dev, "%s: link recovery failed, err %d",
+ __func__, ret);
+- else
+- ufshcd_clear_ua_wluns(hba);
+
+ return ret;
+ }
+@@ -5959,7 +5956,6 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
+ ufshcd_release(hba);
+ if (ufshcd_is_clkscaling_supported(hba))
+ ufshcd_clk_scaling_suspend(hba, false);
+- ufshcd_clear_ua_wluns(hba);
+ ufshcd_rpm_put(hba);
+ }
+
+@@ -6386,9 +6382,8 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
+ irqreturn_t ret = IRQ_NONE;
+ int tag;
+
+- pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
+-
+ spin_lock_irqsave(hba->host->host_lock, flags);
++ pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
+ issued = hba->outstanding_tasks & ~pending;
+ for_each_set_bit(tag, &issued, hba->nutmrs) {
+ struct request *req = hba->tmf_rqs[tag];
+@@ -6545,11 +6540,6 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
+ err = wait_for_completion_io_timeout(&wait,
+ msecs_to_jiffies(TM_CMD_TIMEOUT));
+ if (!err) {
+- /*
+- * Make sure that ufshcd_compl_tm() does not trigger a
+- * use-after-free.
+- */
+- req->end_io_data = NULL;
+ ufshcd_add_tm_upiu_trace(hba, task_tag, UFS_TM_ERR);
+ dev_err(hba->dev, "%s: task management cmd 0x%.2x timed-out\n",
+ __func__, tm_function);
+@@ -7044,6 +7034,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
+ goto release;
+ }
+
++ lrbp->cmd = NULL;
+ err = SUCCESS;
+
+ release:
+@@ -7875,8 +7866,6 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
+ if (ret)
+ goto out;
+
+- ufshcd_clear_ua_wluns(hba);
+-
+ /* Initialize devfreq after UFS device is detected */
+ if (ufshcd_is_clkscaling_supported(hba)) {
+ memcpy(&hba->clk_scaling.saved_pwr_info.info,
+@@ -7902,116 +7891,6 @@ out:
+ return ret;
+ }
+
+-static void ufshcd_request_sense_done(struct request *rq, blk_status_t error)
+-{
+- if (error != BLK_STS_OK)
+- pr_err("%s: REQUEST SENSE failed (%d)\n", __func__, error);
+- kfree(rq->end_io_data);
+- blk_put_request(rq);
+-}
+-
+-static int
+-ufshcd_request_sense_async(struct ufs_hba *hba, struct scsi_device *sdev)
+-{
+- /*
+- * Some UFS devices clear unit attention condition only if the sense
+- * size used (UFS_SENSE_SIZE in this case) is non-zero.
+- */
+- static const u8 cmd[6] = {REQUEST_SENSE, 0, 0, 0, UFS_SENSE_SIZE, 0};
+- struct scsi_request *rq;
+- struct request *req;
+- char *buffer;
+- int ret;
+-
+- buffer = kzalloc(UFS_SENSE_SIZE, GFP_KERNEL);
+- if (!buffer)
+- return -ENOMEM;
+-
+- req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN,
+- /*flags=*/BLK_MQ_REQ_PM);
+- if (IS_ERR(req)) {
+- ret = PTR_ERR(req);
+- goto out_free;
+- }
+-
+- ret = blk_rq_map_kern(sdev->request_queue, req,
+- buffer, UFS_SENSE_SIZE, GFP_NOIO);
+- if (ret)
+- goto out_put;
+-
+- rq = scsi_req(req);
+- rq->cmd_len = ARRAY_SIZE(cmd);
+- memcpy(rq->cmd, cmd, rq->cmd_len);
+- rq->retries = 3;
+- req->timeout = 1 * HZ;
+- req->rq_flags |= RQF_PM | RQF_QUIET;
+- req->end_io_data = buffer;
+-
+- blk_execute_rq_nowait(/*bd_disk=*/NULL, req, /*at_head=*/true,
+- ufshcd_request_sense_done);
+- return 0;
+-
+-out_put:
+- blk_put_request(req);
+-out_free:
+- kfree(buffer);
+- return ret;
+-}
+-
+-static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun)
+-{
+- struct scsi_device *sdp;
+- unsigned long flags;
+- int ret = 0;
+-
+- spin_lock_irqsave(hba->host->host_lock, flags);
+- if (wlun == UFS_UPIU_UFS_DEVICE_WLUN)
+- sdp = hba->sdev_ufs_device;
+- else if (wlun == UFS_UPIU_RPMB_WLUN)
+- sdp = hba->sdev_rpmb;
+- else
+- BUG();
+- if (sdp) {
+- ret = scsi_device_get(sdp);
+- if (!ret && !scsi_device_online(sdp)) {
+- ret = -ENODEV;
+- scsi_device_put(sdp);
+- }
+- } else {
+- ret = -ENODEV;
+- }
+- spin_unlock_irqrestore(hba->host->host_lock, flags);
+- if (ret)
+- goto out_err;
+-
+- ret = ufshcd_request_sense_async(hba, sdp);
+- scsi_device_put(sdp);
+-out_err:
+- if (ret)
+- dev_err(hba->dev, "%s: UAC clear LU=%x ret = %d\n",
+- __func__, wlun, ret);
+- return ret;
+-}
+-
+-static int ufshcd_clear_ua_wluns(struct ufs_hba *hba)
+-{
+- int ret = 0;
+-
+- if (!hba->wlun_dev_clr_ua)
+- goto out;
+-
+- ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);
+- if (!ret)
+- ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN);
+- if (!ret)
+- hba->wlun_dev_clr_ua = false;
+-out:
+- if (ret)
+- dev_err(hba->dev, "%s: Failed to clear UAC WLUNS ret = %d\n",
+- __func__, ret);
+- return ret;
+-}
+-
+ /**
+ * ufshcd_probe_hba - probe hba to detect device and initialize it
+ * @hba: per-adapter instance
+@@ -8062,8 +7941,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
+ /* UFS device is also active now */
+ ufshcd_set_ufs_dev_active(hba);
+ ufshcd_force_reset_auto_bkops(hba);
+- hba->wlun_dev_clr_ua = true;
+- hba->wlun_rpmb_clr_ua = true;
+
+ /* Gear up to HS gear if supported */
+ if (hba->max_pwr_info.is_valid) {
+@@ -8600,7 +8477,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
+ struct scsi_sense_hdr sshdr;
+ struct scsi_device *sdp;
+ unsigned long flags;
+- int ret;
++ int ret, retries;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ sdp = hba->sdev_ufs_device;
+@@ -8625,8 +8502,6 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
+ * handling context.
+ */
+ hba->host->eh_noresume = 1;
+- if (hba->wlun_dev_clr_ua)
+- ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);
+
+ cmd[4] = pwr_mode << 4;
+
+@@ -8635,8 +8510,14 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
+ * callbacks hence set the RQF_PM flag so that it doesn't resume the
+ * already suspended childs.
+ */
+- ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
+- START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL);
++ for (retries = 3; retries > 0; --retries) {
++ ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
++ START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL);
++ if (!scsi_status_is_check_condition(ret) ||
++ !scsi_sense_valid(&sshdr) ||
++ sshdr.sense_key != UNIT_ATTENTION)
++ break;
++ }
+ if (ret) {
+ sdev_printk(KERN_WARNING, sdp,
+ "START_STOP failed for power mode: %d, result %x\n",
+@@ -9699,10 +9580,6 @@ void ufshcd_resume_complete(struct device *dev)
+ ufshcd_rpm_put(hba);
+ hba->complete_put = false;
+ }
+- if (hba->rpmb_complete_put) {
+- ufshcd_rpmb_rpm_put(hba);
+- hba->rpmb_complete_put = false;
+- }
+ }
+ EXPORT_SYMBOL_GPL(ufshcd_resume_complete);
+
+@@ -9725,10 +9602,6 @@ int ufshcd_suspend_prepare(struct device *dev)
+ }
+ hba->complete_put = true;
+ }
+- if (hba->sdev_rpmb) {
+- ufshcd_rpmb_rpm_get_sync(hba);
+- hba->rpmb_complete_put = true;
+- }
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(ufshcd_suspend_prepare);
+@@ -9797,49 +9670,6 @@ static struct scsi_driver ufs_dev_wlun_template = {
+ },
+ };
+
+-static int ufshcd_rpmb_probe(struct device *dev)
+-{
+- return is_rpmb_wlun(to_scsi_device(dev)) ? 0 : -ENODEV;
+-}
+-
+-static inline int ufshcd_clear_rpmb_uac(struct ufs_hba *hba)
+-{
+- int ret = 0;
+-
+- if (!hba->wlun_rpmb_clr_ua)
+- return 0;
+- ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN);
+- if (!ret)
+- hba->wlun_rpmb_clr_ua = 0;
+- return ret;
+-}
+-
+-#ifdef CONFIG_PM
+-static int ufshcd_rpmb_resume(struct device *dev)
+-{
+- struct ufs_hba *hba = wlun_dev_to_hba(dev);
+-
+- if (hba->sdev_rpmb)
+- ufshcd_clear_rpmb_uac(hba);
+- return 0;
+-}
+-#endif
+-
+-static const struct dev_pm_ops ufs_rpmb_pm_ops = {
+- SET_RUNTIME_PM_OPS(NULL, ufshcd_rpmb_resume, NULL)
+- SET_SYSTEM_SLEEP_PM_OPS(NULL, ufshcd_rpmb_resume)
+-};
+-
+-/* ufs_rpmb_wlun_template - Describes UFS RPMB WLUN. Used only to send UAC. */
+-static struct scsi_driver ufs_rpmb_wlun_template = {
+- .gendrv = {
+- .name = "ufs_rpmb_wlun",
+- .owner = THIS_MODULE,
+- .probe = ufshcd_rpmb_probe,
+- .pm = &ufs_rpmb_pm_ops,
+- },
+-};
+-
+ static int __init ufshcd_core_init(void)
+ {
+ int ret;
+@@ -9848,24 +9678,13 @@ static int __init ufshcd_core_init(void)
+
+ ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);
+ if (ret)
+- goto debugfs_exit;
+-
+- ret = scsi_register_driver(&ufs_rpmb_wlun_template.gendrv);
+- if (ret)
+- goto unregister;
+-
+- return ret;
+-unregister:
+- scsi_unregister_driver(&ufs_dev_wlun_template.gendrv);
+-debugfs_exit:
+- ufs_debugfs_exit();
++ ufs_debugfs_exit();
+ return ret;
+ }
+
+ static void __exit ufshcd_core_exit(void)
+ {
+ ufs_debugfs_exit();
+- scsi_unregister_driver(&ufs_rpmb_wlun_template.gendrv);
+ scsi_unregister_driver(&ufs_dev_wlun_template.gendrv);
+ }
+
+diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
+index 41f6e06f91856..07ada6676c3b4 100644
+--- a/drivers/scsi/ufs/ufshcd.h
++++ b/drivers/scsi/ufs/ufshcd.h
+@@ -871,9 +871,6 @@ struct ufs_hba {
+ struct ufs_vreg_info vreg_info;
+ struct list_head clk_list_head;
+
+- bool wlun_dev_clr_ua;
+- bool wlun_rpmb_clr_ua;
+-
+ /* Number of requests aborts */
+ int req_abort_count;
+
+@@ -920,7 +917,6 @@ struct ufs_hba {
+ #endif
+ u32 luns_avail;
+ bool complete_put;
+- bool rpmb_complete_put;
+ };
+
+ /* Returns true if clocks can be gated. Otherwise false */
+@@ -1393,14 +1389,4 @@ static inline int ufshcd_rpm_put(struct ufs_hba *hba)
+ return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev);
+ }
+
+-static inline int ufshcd_rpmb_rpm_get_sync(struct ufs_hba *hba)
+-{
+- return pm_runtime_get_sync(&hba->sdev_rpmb->sdev_gendev);
+-}
+-
+-static inline int ufshcd_rpmb_rpm_put(struct ufs_hba *hba)
+-{
+- return pm_runtime_put(&hba->sdev_rpmb->sdev_gendev);
+-}
+-
+ #endif /* End of Header */
+diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
+index 026a133149dce..a86d0cc50de21 100644
+--- a/drivers/scsi/ufs/ufshpb.c
++++ b/drivers/scsi/ufs/ufshpb.c
+@@ -394,8 +394,6 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+ if (!ufshpb_is_supported_chunk(hpb, transfer_len))
+ return 0;
+
+- WARN_ON_ONCE(transfer_len > HPB_MULTI_CHUNK_HIGH);
+-
+ if (hpb->is_hcm) {
+ /*
+ * in host control mode, reads are the main source for
+@@ -1572,7 +1570,7 @@ static void ufshpb_lu_parameter_init(struct ufs_hba *hba,
+ if (ufshpb_is_legacy(hba))
+ hpb->pre_req_max_tr_len = HPB_LEGACY_CHUNK_HIGH;
+ else
+- hpb->pre_req_max_tr_len = HPB_MULTI_CHUNK_HIGH;
++ hpb->pre_req_max_tr_len = hpb_dev_info->max_hpb_single_cmd;
+
+ hpb->lu_pinned_start = hpb_lu_info->pinned_start;
+ hpb->lu_pinned_end = hpb_lu_info->num_pinned ?
+@@ -2371,11 +2369,11 @@ static int ufshpb_get_lu_info(struct ufs_hba *hba, int lun,
+
+ ufshcd_map_desc_id_to_length(hba, QUERY_DESC_IDN_UNIT, &size);
+
+- pm_runtime_get_sync(hba->dev);
++ ufshcd_rpm_get_sync(hba);
+ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ QUERY_DESC_IDN_UNIT, lun, 0,
+ desc_buf, &size);
+- pm_runtime_put_sync(hba->dev);
++ ufshcd_rpm_put_sync(hba);
+
+ if (ret) {
+ dev_err(hba->dev,
+@@ -2582,7 +2580,7 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
+ {
+ struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev;
+ int version, ret;
+- u32 max_hpb_single_cmd = HPB_MULTI_CHUNK_LOW;
++ int max_single_cmd;
+
+ hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
+
+@@ -2598,21 +2596,22 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
+ if (version == HPB_SUPPORT_LEGACY_VERSION)
+ hpb_dev_info->is_legacy = true;
+
+- pm_runtime_get_sync(hba->dev);
+- ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+- QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_hpb_single_cmd);
+- pm_runtime_put_sync(hba->dev);
+-
+- if (ret)
+- dev_err(hba->dev, "%s: idn: read max size of single hpb cmd query request failed",
+- __func__);
+- hpb_dev_info->max_hpb_single_cmd = max_hpb_single_cmd;
+-
+ /*
+ * Get the number of user logical unit to check whether all
+ * scsi_device finish initialization
+ */
+ hpb_dev_info->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU];
++
++ if (hpb_dev_info->is_legacy)
++ return;
++
++ ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
++ QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_single_cmd);
++
++ if (ret)
++ hpb_dev_info->max_hpb_single_cmd = HPB_LEGACY_CHUNK_HIGH;
++ else
++ hpb_dev_info->max_hpb_single_cmd = min(max_single_cmd + 1, HPB_MULTI_CHUNK_HIGH);
+ }
+
+ void ufshpb_init(struct ufs_hba *hba)
+diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
+index f15d8fdbce2ef..b475dbd789883 100644
+--- a/drivers/scsi/ufs/ufshpb.h
++++ b/drivers/scsi/ufs/ufshpb.h
+@@ -31,7 +31,6 @@
+
+ /* hpb support chunk size */
+ #define HPB_LEGACY_CHUNK_HIGH 1
+-#define HPB_MULTI_CHUNK_LOW 7
+ #define HPB_MULTI_CHUNK_HIGH 255
+
+ /* hpb vender defined opcode */
+diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
+index bd0fbcdbdefe9..e24e220e56eea 100644
+--- a/drivers/sh/maple/maple.c
++++ b/drivers/sh/maple/maple.c
+@@ -834,8 +834,10 @@ static int __init maple_bus_init(void)
+
+ maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN);
+
+- if (!maple_queue_cache)
++ if (!maple_queue_cache) {
++ retval = -ENOMEM;
+ goto cleanup_bothirqs;
++ }
+
+ INIT_LIST_HEAD(&maple_waitq);
+ INIT_LIST_HEAD(&maple_sentq);
+@@ -848,6 +850,7 @@ static int __init maple_bus_init(void)
+ if (!mdev[i]) {
+ while (i-- > 0)
+ maple_free_dev(mdev[i]);
++ retval = -ENOMEM;
+ goto cleanup_cache;
+ }
+ baseunits[i] = mdev[i];
+diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c
+index 27243f706f376..53917410f2bdb 100644
+--- a/drivers/soc/fsl/dpaa2-console.c
++++ b/drivers/soc/fsl/dpaa2-console.c
+@@ -231,6 +231,7 @@ static ssize_t dpaa2_console_read(struct file *fp, char __user *buf,
+ cd->cur_ptr += bytes;
+ written += bytes;
+
++ kfree(kbuf);
+ return written;
+
+ err_free_buf:
+diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c
+index 7351f30305506..779c319a4b820 100644
+--- a/drivers/soc/fsl/dpio/dpio-service.c
++++ b/drivers/soc/fsl/dpio/dpio-service.c
+@@ -59,7 +59,7 @@ static inline struct dpaa2_io *service_select_by_cpu(struct dpaa2_io *d,
+ * potentially being migrated away.
+ */
+ if (cpu < 0)
+- cpu = smp_processor_id();
++ cpu = raw_smp_processor_id();
+
+ /* If a specific cpu was requested, pick it up immediately */
+ return dpio_by_cpu[cpu];
+diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
+index f13da4d7d1c52..3ec8ab08b9889 100644
+--- a/drivers/soc/fsl/dpio/qbman-portal.c
++++ b/drivers/soc/fsl/dpio/qbman-portal.c
+@@ -732,8 +732,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
+ int i, num_enqueued = 0;
+ unsigned long irq_flags;
+
+- spin_lock(&s->access_spinlock);
+- local_irq_save(irq_flags);
++ spin_lock_irqsave(&s->access_spinlock, irq_flags);
+
+ half_mask = (s->eqcr.pi_ci_mask>>1);
+ full_mask = s->eqcr.pi_ci_mask;
+@@ -744,8 +743,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
+ s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
+ eqcr_ci, s->eqcr.ci);
+ if (!s->eqcr.available) {
+- local_irq_restore(irq_flags);
+- spin_unlock(&s->access_spinlock);
++ spin_unlock_irqrestore(&s->access_spinlock, irq_flags);
+ return 0;
+ }
+ }
+@@ -784,8 +782,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
+ dma_wmb();
+ qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI,
+ (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb);
+- local_irq_restore(irq_flags);
+- spin_unlock(&s->access_spinlock);
++ spin_unlock_irqrestore(&s->access_spinlock, irq_flags);
+
+ return num_enqueued;
+ }
+diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
+index 34a9ac1f2b9b1..8b7a01773aec2 100644
+--- a/drivers/soc/imx/gpcv2.c
++++ b/drivers/soc/imx/gpcv2.c
+@@ -244,6 +244,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ goto out_regulator_disable;
+ }
+
++ reset_control_assert(domain->reset);
++
+ if (domain->bits.pxx) {
+ /* request the domain to power up */
+ regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ,
+@@ -266,8 +268,6 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+ GPC_PGC_CTRL_PCR);
+ }
+
+- reset_control_assert(domain->reset);
+-
+ /* delay for reset to propagate */
+ udelay(5);
+
+diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c
+index ac6d856ba228d..77bc12039c3d4 100644
+--- a/drivers/soc/imx/soc-imx.c
++++ b/drivers/soc/imx/soc-imx.c
+@@ -36,6 +36,10 @@ static int __init imx_soc_device_init(void)
+ int ret;
+ int i;
+
++ /* Return early if this is running on devices with different SoCs */
++ if (!__mxc_cpu_type)
++ return 0;
++
+ if (of_machine_is_compatible("fsl,ls1021a"))
+ return 0;
+
+diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
+index 475a57b435b24..2e455d9e3d94a 100644
+--- a/drivers/soc/qcom/apr.c
++++ b/drivers/soc/qcom/apr.c
+@@ -321,12 +321,14 @@ static int of_apr_add_pd_lookups(struct device *dev)
+ 1, &service_path);
+ if (ret < 0) {
+ dev_err(dev, "pdr service path missing: %d\n", ret);
++ of_node_put(node);
+ return ret;
+ }
+
+ pds = pdr_add_lookup(apr->pdr, service_name, service_path);
+ if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
+ dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
++ of_node_put(node);
+ return PTR_ERR(pds);
+ }
+ }
+diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
+index 15a36dcab990e..e53109a5c3da9 100644
+--- a/drivers/soc/qcom/llcc-qcom.c
++++ b/drivers/soc/qcom/llcc-qcom.c
+@@ -115,7 +115,7 @@ static const struct llcc_slice_config sc7280_data[] = {
+ { LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+ { LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+ { LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+- { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 1, 0},
++ { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0},
+ { LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+ { LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+ { LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
+index fa209b479ab35..d98cc8c2e5d5c 100644
+--- a/drivers/soc/qcom/rpmhpd.c
++++ b/drivers/soc/qcom/rpmhpd.c
+@@ -30,6 +30,7 @@
+ * @active_only: True if it represents an Active only peer
+ * @corner: current corner
+ * @active_corner: current active corner
++ * @enable_corner: lowest non-zero corner
+ * @level: An array of level (vlvl) to corner (hlvl) mappings
+ * derived from cmd-db
+ * @level_count: Number of levels supported by the power domain. max
+@@ -47,6 +48,7 @@ struct rpmhpd {
+ const bool active_only;
+ unsigned int corner;
+ unsigned int active_corner;
++ unsigned int enable_corner;
+ u32 level[RPMH_ARC_MAX_LEVELS];
+ size_t level_count;
+ bool enabled;
+@@ -204,7 +206,7 @@ static const struct rpmhpd_desc sm8250_desc = {
+ static struct rpmhpd sm8350_mxc_ao;
+ static struct rpmhpd sm8350_mxc = {
+ .pd = { .name = "mxc", },
+- .peer = &sm8150_mmcx_ao,
++ .peer = &sm8350_mxc_ao,
+ .res_name = "mxc.lvl",
+ };
+
+@@ -385,13 +387,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
+ static int rpmhpd_power_on(struct generic_pm_domain *domain)
+ {
+ struct rpmhpd *pd = domain_to_rpmhpd(domain);
+- int ret = 0;
++ unsigned int corner;
++ int ret;
+
+ mutex_lock(&rpmhpd_lock);
+
+- if (pd->corner)
+- ret = rpmhpd_aggregate_corner(pd, pd->corner);
+-
++ corner = max(pd->corner, pd->enable_corner);
++ ret = rpmhpd_aggregate_corner(pd, corner);
+ if (!ret)
+ pd->enabled = true;
+
+@@ -436,6 +438,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
+ i--;
+
+ if (pd->enabled) {
++ /* Ensure that the domain isn't turn off */
++ if (i < pd->enable_corner)
++ i = pd->enable_corner;
++
+ ret = rpmhpd_aggregate_corner(pd, i);
+ if (ret)
+ goto out;
+@@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
+ for (i = 0; i < rpmhpd->level_count; i++) {
+ rpmhpd->level[i] = buf[i];
+
++ /* Remember the first corner with non-zero level */
++ if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
++ rpmhpd->enable_corner = i;
++
+ /*
+ * The AUX data may be zero padded. These 0 valued entries at
+ * the end of the map must be ignored.
+diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
+index 52e5811671155..5beb452f24013 100644
+--- a/drivers/soc/qcom/socinfo.c
++++ b/drivers/soc/qcom/socinfo.c
+@@ -87,8 +87,8 @@ static const char *const pmic_models[] = {
+ [15] = "PM8901",
+ [16] = "PM8950/PM8027",
+ [17] = "PMI8950/ISL9519",
+- [18] = "PM8921",
+- [19] = "PM8018",
++ [18] = "PMK8001/PM8921",
++ [19] = "PMI8996/PM8018",
+ [20] = "PM8998/PM8015",
+ [21] = "PMI8998/PM8014",
+ [22] = "PM8821",
+diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
+index 5745d7e5908e9..1f643c0f5c93f 100644
+--- a/drivers/soc/samsung/Kconfig
++++ b/drivers/soc/samsung/Kconfig
+@@ -25,6 +25,7 @@ config EXYNOS_PMU
+ bool "Exynos PMU controller driver" if COMPILE_TEST
+ depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
+ select EXYNOS_PMU_ARM_DRIVERS if ARM && ARCH_EXYNOS
++ select MFD_CORE
+
+ # There is no need to enable these drivers for ARMv8
+ config EXYNOS_PMU_ARM_DRIVERS
+diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
+index f2151815db585..e714ed3b61bc3 100644
+--- a/drivers/soc/tegra/fuse/fuse-tegra.c
++++ b/drivers/soc/tegra/fuse/fuse-tegra.c
+@@ -320,7 +320,7 @@ static struct platform_driver tegra_fuse_driver = {
+ };
+ builtin_platform_driver(tegra_fuse_driver);
+
+-bool __init tegra_fuse_read_spare(unsigned int spare)
++u32 __init tegra_fuse_read_spare(unsigned int spare)
+ {
+ unsigned int offset = fuse->soc->info->spare + spare * 4;
+
+diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
+index de58feba04350..ecff0c08e9595 100644
+--- a/drivers/soc/tegra/fuse/fuse.h
++++ b/drivers/soc/tegra/fuse/fuse.h
+@@ -65,7 +65,7 @@ struct tegra_fuse {
+ void tegra_init_revision(void);
+ void tegra_init_apbmisc(void);
+
+-bool __init tegra_fuse_read_spare(unsigned int spare);
++u32 __init tegra_fuse_read_spare(unsigned int spare);
+ u32 __init tegra_fuse_read_early(unsigned int offset);
+
+ u8 tegra_get_major_rev(void);
+diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
+index 50091c4ec9481..a60e142ade344 100644
+--- a/drivers/soc/tegra/pmc.c
++++ b/drivers/soc/tegra/pmc.c
+@@ -782,7 +782,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,
+
+ err = reset_control_deassert(pg->reset);
+ if (err)
+- goto powergate_off;
++ goto disable_clks;
+
+ usleep_range(10, 20);
+
+diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
+index 1b115734a8f6b..67369e941d0d6 100644
+--- a/drivers/soundwire/bus.c
++++ b/drivers/soundwire/bus.c
+@@ -1110,7 +1110,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
+ if (!simple_clk_stop) {
+ ret = sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);
+ if (ret < 0)
+- dev_warn(&slave->dev, "clock stop deprepare wait failed:%d\n", ret);
++ dev_warn(bus->dev, "clock stop deprepare wait failed:%d\n", ret);
+ }
+
+ list_for_each_entry(slave, &bus->slaves, node) {
+diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
+index b6cad0d59b7b9..49900cd207bc7 100644
+--- a/drivers/soundwire/debugfs.c
++++ b/drivers/soundwire/debugfs.c
+@@ -19,7 +19,7 @@ void sdw_bus_debugfs_init(struct sdw_bus *bus)
+ return;
+
+ /* create the debugfs master-N */
+- snprintf(name, sizeof(name), "master-%d", bus->link_id);
++ snprintf(name, sizeof(name), "master-%d-%d", bus->id, bus->link_id);
+ bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root);
+ }
+
+diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
+index 95d4fa32c2995..92d9610df1fd8 100644
+--- a/drivers/spi/atmel-quadspi.c
++++ b/drivers/spi/atmel-quadspi.c
+@@ -310,7 +310,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
+ return mode;
+ ifr |= atmel_qspi_modes[mode].config;
+
+- if (op->dummy.buswidth && op->dummy.nbytes)
++ if (op->dummy.nbytes)
+ dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
+
+ /*
+diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
+index 3043677ba2226..151e154284bde 100644
+--- a/drivers/spi/spi-bcm-qspi.c
++++ b/drivers/spi/spi-bcm-qspi.c
+@@ -395,7 +395,8 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
+ if (addrlen == BSPI_ADDRLEN_4BYTES)
+ bpp = BSPI_BPP_ADDR_SELECT_MASK;
+
+- bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
++ if (op->dummy.nbytes)
++ bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
+
+ switch (width) {
+ case SPI_NBITS_SINGLE:
+@@ -1460,7 +1461,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
+ &qspi->dev_ids[val]);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ %s not found\n", name);
+- goto qspi_probe_err;
++ goto qspi_unprepare_err;
+ }
+
+ qspi->dev_ids[val].dev = qspi;
+@@ -1475,7 +1476,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
+ if (!num_ints) {
+ dev_err(&pdev->dev, "no IRQs registered, cannot init driver\n");
+ ret = -EINVAL;
+- goto qspi_probe_err;
++ goto qspi_unprepare_err;
+ }
+
+ bcm_qspi_hw_init(qspi);
+@@ -1499,6 +1500,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
+
+ qspi_reg_err:
+ bcm_qspi_hw_uninit(qspi);
++qspi_unprepare_err:
+ clk_disable_unprepare(qspi->clk);
+ qspi_probe_err:
+ kfree(qspi->dev_ids);
+diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
+index 41e7b341d2616..5c93730615f8d 100644
+--- a/drivers/spi/spi-mtk-nor.c
++++ b/drivers/spi/spi-mtk-nor.c
+@@ -160,7 +160,7 @@ static bool mtk_nor_match_read(const struct spi_mem_op *op)
+ {
+ int dummy = 0;
+
+- if (op->dummy.buswidth)
++ if (op->dummy.nbytes)
+ dummy = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth;
+
+ if ((op->data.buswidth == 2) || (op->data.buswidth == 4)) {
+diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
+index c53138ce00309..83796a4ead34a 100644
+--- a/drivers/spi/spi-rpc-if.c
++++ b/drivers/spi/spi-rpc-if.c
+@@ -139,7 +139,9 @@ static int rpcif_spi_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ rpc = spi_controller_get_devdata(ctlr);
+- rpcif_sw_init(rpc, parent);
++ error = rpcif_sw_init(rpc, parent);
++ if (error)
++ return error;
+
+ platform_set_drvdata(pdev, ctlr);
+
+diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
+index 27f35aa2d746d..514337c86d2c3 100644
+--- a/drivers/spi/spi-stm32-qspi.c
++++ b/drivers/spi/spi-stm32-qspi.c
+@@ -397,7 +397,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
+ ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
+ }
+
+- if (op->dummy.buswidth && op->dummy.nbytes)
++ if (op->dummy.nbytes)
+ ccr |= FIELD_PREP(CCR_DCYC_MASK,
+ op->dummy.nbytes * 8 / op->dummy.buswidth);
+
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 926b68aa45d3e..97b5a811bd7f7 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -451,6 +451,47 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
+ {
+ sdrv->driver.owner = owner;
+ sdrv->driver.bus = &spi_bus_type;
++
++ /*
++ * For Really Good Reasons we use spi: modaliases not of:
++ * modaliases for DT so module autoloading won't work if we
++ * don't have a spi_device_id as well as a compatible string.
++ */
++ if (sdrv->driver.of_match_table) {
++ const struct of_device_id *of_id;
++
++ for (of_id = sdrv->driver.of_match_table; of_id->compatible[0];
++ of_id++) {
++ const char *of_name;
++
++ /* Strip off any vendor prefix */
++ of_name = strnchr(of_id->compatible,
++ sizeof(of_id->compatible), ',');
++ if (of_name)
++ of_name++;
++ else
++ of_name = of_id->compatible;
++
++ if (sdrv->id_table) {
++ const struct spi_device_id *spi_id;
++
++ for (spi_id = sdrv->id_table; spi_id->name[0];
++ spi_id++)
++ if (strcmp(spi_id->name, of_name) == 0)
++ break;
++
++ if (spi_id->name[0])
++ continue;
++ } else {
++ if (strcmp(sdrv->driver.name, of_name) == 0)
++ continue;
++ }
++
++ pr_warn("SPI driver %s has no spi_device_id for %s\n",
++ sdrv->driver.name, of_id->compatible);
++ }
++ }
++
+ return driver_register(&sdrv->driver);
+ }
+ EXPORT_SYMBOL_GPL(__spi_register_driver);
+@@ -2979,12 +3020,6 @@ void spi_unregister_controller(struct spi_controller *ctlr)
+
+ device_del(&ctlr->dev);
+
+- /* Release the last reference on the controller if its driver
+- * has not yet been converted to devm_spi_alloc_master/slave().
+- */
+- if (!ctlr->devm_allocated)
+- put_device(&ctlr->dev);
+-
+ /* free bus id */
+ mutex_lock(&board_lock);
+ if (found == ctlr)
+@@ -2993,6 +3028,12 @@ void spi_unregister_controller(struct spi_controller *ctlr)
+
+ if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+ mutex_unlock(&ctlr->add_lock);
++
++ /* Release the last reference on the controller if its driver
++ * has not yet been converted to devm_spi_alloc_master/slave().
++ */
++ if (!ctlr->devm_allocated)
++ put_device(&ctlr->dev);
+ }
+ EXPORT_SYMBOL_GPL(spi_unregister_controller);
+
+diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c
+index cf263a58a1489..6fd549a424d53 100644
+--- a/drivers/staging/fbtft/fb_ssd1351.c
++++ b/drivers/staging/fbtft/fb_ssd1351.c
+@@ -187,7 +187,6 @@ static struct fbtft_display display = {
+ },
+ };
+
+-#ifdef CONFIG_FB_BACKLIGHT
+ static int update_onboard_backlight(struct backlight_device *bd)
+ {
+ struct fbtft_par *par = bl_get_data(bd);
+@@ -231,9 +230,6 @@ static void register_onboard_backlight(struct fbtft_par *par)
+ if (!par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+ }
+-#else
+-static void register_onboard_backlight(struct fbtft_par *par) { };
+-#endif
+
+ FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display);
+
+diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
+index ed992ca605ebe..1690358b8f018 100644
+--- a/drivers/staging/fbtft/fbtft-core.c
++++ b/drivers/staging/fbtft/fbtft-core.c
+@@ -128,7 +128,6 @@ static int fbtft_request_gpios(struct fbtft_par *par)
+ return 0;
+ }
+
+-#ifdef CONFIG_FB_BACKLIGHT
+ static int fbtft_backlight_update_status(struct backlight_device *bd)
+ {
+ struct fbtft_par *par = bl_get_data(bd);
+@@ -161,6 +160,7 @@ void fbtft_unregister_backlight(struct fbtft_par *par)
+ par->info->bl_dev = NULL;
+ }
+ }
++EXPORT_SYMBOL(fbtft_unregister_backlight);
+
+ static const struct backlight_ops fbtft_bl_ops = {
+ .get_brightness = fbtft_backlight_get_brightness,
+@@ -198,12 +198,7 @@ void fbtft_register_backlight(struct fbtft_par *par)
+ if (!par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+ }
+-#else
+-void fbtft_register_backlight(struct fbtft_par *par) { };
+-void fbtft_unregister_backlight(struct fbtft_par *par) { };
+-#endif
+ EXPORT_SYMBOL(fbtft_register_backlight);
+-EXPORT_SYMBOL(fbtft_unregister_backlight);
+
+ static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
+ int ye)
+@@ -853,13 +848,11 @@ int fbtft_register_framebuffer(struct fb_info *fb_info)
+ fb_info->fix.smem_len >> 10, text1,
+ HZ / fb_info->fbdefio->delay, text2);
+
+-#ifdef CONFIG_FB_BACKLIGHT
+ /* Turn on backlight if available */
+ if (fb_info->bl_dev) {
+ fb_info->bl_dev->props.power = FB_BLANK_UNBLANK;
+ fb_info->bl_dev->ops->update_status(fb_info->bl_dev);
+ }
+-#endif
+
+ return 0;
+
+diff --git a/drivers/staging/greybus/audio_helper.c b/drivers/staging/greybus/audio_helper.c
+index 1ed4772d27715..843760675876a 100644
+--- a/drivers/staging/greybus/audio_helper.c
++++ b/drivers/staging/greybus/audio_helper.c
+@@ -192,7 +192,11 @@ int gbaudio_remove_component_controls(struct snd_soc_component *component,
+ unsigned int num_controls)
+ {
+ struct snd_card *card = component->card->snd_card;
++ int err;
+
+- return gbaudio_remove_controls(card, component->dev, controls,
+- num_controls, component->name_prefix);
++ down_write(&card->controls_rwsem);
++ err = gbaudio_remove_controls(card, component->dev, controls,
++ num_controls, component->name_prefix);
++ up_write(&card->controls_rwsem);
++ return err;
+ }
+diff --git a/drivers/staging/ks7010/Kconfig b/drivers/staging/ks7010/Kconfig
+index 0987fdc2f70db..8ea6c09286798 100644
+--- a/drivers/staging/ks7010/Kconfig
++++ b/drivers/staging/ks7010/Kconfig
+@@ -5,6 +5,9 @@ config KS7010
+ select WIRELESS_EXT
+ select WEXT_PRIV
+ select FW_LOADER
++ select CRYPTO
++ select CRYPTO_HASH
++ select CRYPTO_MICHAEL_MIC
+ help
+ This is a driver for KeyStream KS7010 based SDIO WIFI cards. It is
+ found on at least later Spectec SDW-821 (FCC-ID "S2Y-WLAN-11G-K" only,
+diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
+index 362ed44b4effa..e046489cd253b 100644
+--- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
++++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
+@@ -835,7 +835,6 @@ static int lm3554_probe(struct i2c_client *client)
+ int err = 0;
+ struct lm3554 *flash;
+ unsigned int i;
+- int ret;
+
+ flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+ if (!flash)
+@@ -844,7 +843,7 @@ static int lm3554_probe(struct i2c_client *client)
+ flash->pdata = lm3554_platform_data_func(client);
+ if (IS_ERR(flash->pdata)) {
+ err = PTR_ERR(flash->pdata);
+- goto fail1;
++ goto free_flash;
+ }
+
+ v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops);
+@@ -852,12 +851,12 @@ static int lm3554_probe(struct i2c_client *client)
+ flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ flash->mode = ATOMISP_FLASH_MODE_OFF;
+ flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1;
+- ret =
++ err =
+ v4l2_ctrl_handler_init(&flash->ctrl_handler,
+ ARRAY_SIZE(lm3554_controls));
+- if (ret) {
++ if (err) {
+ dev_err(&client->dev, "error initialize a ctrl_handler.\n");
+- goto fail3;
++ goto unregister_subdev;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++)
+@@ -866,14 +865,15 @@ static int lm3554_probe(struct i2c_client *client)
+
+ if (flash->ctrl_handler.error) {
+ dev_err(&client->dev, "ctrl_handler error.\n");
+- goto fail3;
++ err = flash->ctrl_handler.error;
++ goto free_handler;
+ }
+
+ flash->sd.ctrl_handler = &flash->ctrl_handler;
+ err = media_entity_pads_init(&flash->sd.entity, 0, NULL);
+ if (err) {
+ dev_err(&client->dev, "error initialize a media entity.\n");
+- goto fail2;
++ goto free_handler;
+ }
+
+ flash->sd.entity.function = MEDIA_ENT_F_FLASH;
+@@ -884,16 +884,27 @@ static int lm3554_probe(struct i2c_client *client)
+
+ err = lm3554_gpio_init(client);
+ if (err) {
+- dev_err(&client->dev, "gpio request/direction_output fail");
+- goto fail3;
++ dev_err(&client->dev, "gpio request/direction_output fail.\n");
++ goto cleanup_media;
++ }
++
++ err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH);
++ if (err) {
++ dev_err(&client->dev, "fail to register atomisp i2c module.\n");
++ goto uninit_gpio;
+ }
+- return atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH);
+-fail3:
++
++ return 0;
++
++uninit_gpio:
++ lm3554_gpio_uninit(client);
++cleanup_media:
+ media_entity_cleanup(&flash->sd.entity);
++free_handler:
+ v4l2_ctrl_handler_free(&flash->ctrl_handler);
+-fail2:
++unregister_subdev:
+ v4l2_device_unregister_subdev(&flash->sd);
+-fail1:
++free_flash:
+ kfree(flash);
+
+ return err;
+diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
+index d186179388d03..4d873726a461b 100644
+--- a/drivers/staging/media/imx/imx-media-dev-common.c
++++ b/drivers/staging/media/imx/imx-media-dev-common.c
+@@ -367,6 +367,8 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev,
+ imxmd->v4l2_dev.notify = imx_media_notify;
+ strscpy(imxmd->v4l2_dev.name, "imx-media",
+ sizeof(imxmd->v4l2_dev.name));
++ snprintf(imxmd->md.bus_info, sizeof(imxmd->md.bus_info),
++ "platform:%s", dev_name(imxmd->md.dev));
+
+ media_device_init(&imxmd->md);
+
+diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c
+index 45aff76198e2c..981693eed8155 100644
+--- a/drivers/staging/media/ipu3/ipu3-css-fw.c
++++ b/drivers/staging/media/ipu3/ipu3-css-fw.c
+@@ -124,12 +124,11 @@ int imgu_css_fw_init(struct imgu_css *css)
+ /* Check and display fw header info */
+
+ css->fwp = (struct imgu_fw_header *)css->fw->data;
+- if (css->fw->size < sizeof(struct imgu_fw_header *) ||
++ if (css->fw->size < struct_size(css->fwp, binary_header, 1) ||
+ css->fwp->file_header.h_size != sizeof(struct imgu_fw_bi_file_h))
+ goto bad_fw;
+- if (sizeof(struct imgu_fw_bi_file_h) +
+- css->fwp->file_header.binary_nr * sizeof(struct imgu_fw_info) >
+- css->fw->size)
++ if (struct_size(css->fwp, binary_header,
++ css->fwp->file_header.binary_nr) > css->fw->size)
+ goto bad_fw;
+
+ dev_info(dev, "loaded firmware version %.64s, %u binaries, %zu bytes\n",
+diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.h b/drivers/staging/media/ipu3/ipu3-css-fw.h
+index 3c078f15a2959..c0bc57fd678a7 100644
+--- a/drivers/staging/media/ipu3/ipu3-css-fw.h
++++ b/drivers/staging/media/ipu3/ipu3-css-fw.h
+@@ -171,7 +171,7 @@ struct imgu_fw_bi_file_h {
+
+ struct imgu_fw_header {
+ struct imgu_fw_bi_file_h file_header;
+- struct imgu_fw_info binary_header[1]; /* binary_nr items */
++ struct imgu_fw_info binary_header[]; /* binary_nr items */
+ };
+
+ /******************* Firmware functions *******************/
+diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
+index 38a2407645096..90c86ba5040e3 100644
+--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
++++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
+@@ -592,11 +592,12 @@ static const struct imgu_fmt *find_format(struct v4l2_format *f, u32 type)
+ static int imgu_vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+ {
+- struct imgu_video_device *node = file_to_intel_imgu_node(file);
++ struct imgu_device *imgu = video_drvdata(file);
+
+ strscpy(cap->driver, IMGU_NAME, sizeof(cap->driver));
+ strscpy(cap->card, IMGU_NAME, sizeof(cap->card));
+- snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", node->name);
++ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
++ pci_name(imgu->pci_dev));
+
+ return 0;
+ }
+@@ -696,7 +697,7 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
+
+ /* CSS expects some format on OUT queue */
+ if (i != IPU3_CSS_QUEUE_OUT &&
+- !imgu_pipe->nodes[inode].enabled) {
++ !imgu_pipe->nodes[inode].enabled && !try) {
+ fmts[i] = NULL;
+ continue;
+ }
+diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
+index 76e97cbe25123..951e19231da21 100644
+--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
+@@ -1015,8 +1015,9 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
+ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+ fmt->num_planes = 1;
+- fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+- RKVDEC_H264_MAX_DEPTH_IN_BYTES;
++ if (!fmt->plane_fmt[0].sizeimage)
++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
++ RKVDEC_H264_MAX_DEPTH_IN_BYTES;
+ return 0;
+ }
+
+diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
+index 7131156c1f2cf..3f3f96488d741 100644
+--- a/drivers/staging/media/rkvdec/rkvdec.c
++++ b/drivers/staging/media/rkvdec/rkvdec.c
+@@ -280,31 +280,20 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv,
+ return 0;
+ }
+
+-static int rkvdec_s_fmt(struct file *file, void *priv,
+- struct v4l2_format *f,
+- int (*try_fmt)(struct file *, void *,
+- struct v4l2_format *))
++static int rkvdec_s_capture_fmt(struct file *file, void *priv,
++ struct v4l2_format *f)
+ {
+ struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv);
+ struct vb2_queue *vq;
++ int ret;
+
+- if (!try_fmt)
+- return -EINVAL;
+-
+- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
++ /* Change not allowed if queue is busy */
++ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
++ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+- return try_fmt(file, priv, f);
+-}
+-
+-static int rkvdec_s_capture_fmt(struct file *file, void *priv,
+- struct v4l2_format *f)
+-{
+- struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv);
+- int ret;
+-
+- ret = rkvdec_s_fmt(file, priv, f, rkvdec_try_capture_fmt);
++ ret = rkvdec_try_capture_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+@@ -319,9 +308,20 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv,
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ const struct rkvdec_coded_fmt_desc *desc;
+ struct v4l2_format *cap_fmt;
+- struct vb2_queue *peer_vq;
++ struct vb2_queue *peer_vq, *vq;
+ int ret;
+
++ /*
++ * In order to support dynamic resolution change, the decoder admits
++ * a resolution change, as long as the pixelformat remains. Can't be
++ * done if streaming.
++ */
++ vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
++ if (vb2_is_streaming(vq) ||
++ (vb2_is_busy(vq) &&
++ f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat))
++ return -EBUSY;
++
+ /*
+ * Since format change on the OUTPUT queue will reset the CAPTURE
+ * queue, we can't allow doing so when the CAPTURE queue has buffers
+@@ -331,7 +331,7 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv,
+ if (vb2_is_busy(peer_vq))
+ return -EBUSY;
+
+- ret = rkvdec_s_fmt(file, priv, f, rkvdec_try_output_fmt);
++ ret = rkvdec_try_output_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/staging/most/dim2/Makefile b/drivers/staging/most/dim2/Makefile
+index 861adacf6c729..5f9612af3fa3c 100644
+--- a/drivers/staging/most/dim2/Makefile
++++ b/drivers/staging/most/dim2/Makefile
+@@ -1,4 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_MOST_DIM2) += most_dim2.o
+
+-most_dim2-objs := dim2.o hal.o sysfs.o
++most_dim2-objs := dim2.o hal.o
+diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c
+index 093ef9a2b2919..81e062009d271 100644
+--- a/drivers/staging/most/dim2/dim2.c
++++ b/drivers/staging/most/dim2/dim2.c
+@@ -117,7 +117,8 @@ struct dim2_platform_data {
+ (((p)[1] == 0x18) && ((p)[2] == 0x05) && ((p)[3] == 0x0C) && \
+ ((p)[13] == 0x3C) && ((p)[14] == 0x00) && ((p)[15] == 0x0A))
+
+-bool dim2_sysfs_get_state_cb(void)
++static ssize_t state_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
+ {
+ bool state;
+ unsigned long flags;
+@@ -126,9 +127,18 @@ bool dim2_sysfs_get_state_cb(void)
+ state = dim_get_lock_state();
+ spin_unlock_irqrestore(&dim_lock, flags);
+
+- return state;
++ return sysfs_emit(buf, "%s\n", state ? "locked" : "");
+ }
+
++static DEVICE_ATTR_RO(state);
++
++static struct attribute *dim2_attrs[] = {
++ &dev_attr_state.attr,
++ NULL,
++};
++
++ATTRIBUTE_GROUPS(dim2);
++
+ /**
+ * dimcb_on_error - callback from HAL to report miscommunication between
+ * HDM and HAL
+@@ -716,6 +726,23 @@ static int get_dim2_clk_speed(const char *clock_speed, u8 *val)
+ return -EINVAL;
+ }
+
++static void dim2_release(struct device *d)
++{
++ struct dim2_hdm *dev = container_of(d, struct dim2_hdm, dev);
++ unsigned long flags;
++
++ kthread_stop(dev->netinfo_task);
++
++ spin_lock_irqsave(&dim_lock, flags);
++ dim_shutdown();
++ spin_unlock_irqrestore(&dim_lock, flags);
++
++ if (dev->disable_platform)
++ dev->disable_platform(to_platform_device(d->parent));
++
++ kfree(dev);
++}
++
+ /*
+ * dim2_probe - dim2 probe handler
+ * @pdev: platform device structure
+@@ -736,7 +763,7 @@ static int dim2_probe(struct platform_device *pdev)
+
+ enum { MLB_INT_IDX, AHB0_INT_IDX };
+
+- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+@@ -748,25 +775,27 @@ static int dim2_probe(struct platform_device *pdev)
+ "microchip,clock-speed", &clock_speed);
+ if (ret) {
+ dev_err(&pdev->dev, "missing dt property clock-speed\n");
+- return ret;
++ goto err_free_dev;
+ }
+
+ ret = get_dim2_clk_speed(clock_speed, &dev->clk_speed);
+ if (ret) {
+ dev_err(&pdev->dev, "bad dt property clock-speed\n");
+- return ret;
++ goto err_free_dev;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->io_base = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(dev->io_base))
+- return PTR_ERR(dev->io_base);
++ if (IS_ERR(dev->io_base)) {
++ ret = PTR_ERR(dev->io_base);
++ goto err_free_dev;
++ }
+
+ of_id = of_match_node(dim2_of_match, pdev->dev.of_node);
+ pdata = of_id->data;
+ ret = pdata && pdata->enable ? pdata->enable(pdev) : 0;
+ if (ret)
+- return ret;
++ goto err_free_dev;
+
+ dev->disable_platform = pdata ? pdata->disable : NULL;
+
+@@ -857,32 +886,19 @@ static int dim2_probe(struct platform_device *pdev)
+ dev->most_iface.request_netinfo = request_netinfo;
+ dev->most_iface.driver_dev = &pdev->dev;
+ dev->most_iface.dev = &dev->dev;
+- dev->dev.init_name = "dim2_state";
++ dev->dev.init_name = dev->name;
+ dev->dev.parent = &pdev->dev;
++ dev->dev.release = dim2_release;
+
+- ret = most_register_interface(&dev->most_iface);
+- if (ret) {
+- dev_err(&pdev->dev, "failed to register MOST interface\n");
+- goto err_stop_thread;
+- }
+-
+- ret = dim2_sysfs_probe(&dev->dev);
+- if (ret) {
+- dev_err(&pdev->dev, "failed to create sysfs attribute\n");
+- goto err_unreg_iface;
+- }
+-
+- return 0;
++ return most_register_interface(&dev->most_iface);
+
+-err_unreg_iface:
+- most_deregister_interface(&dev->most_iface);
+-err_stop_thread:
+- kthread_stop(dev->netinfo_task);
+ err_shutdown_dim:
+ dim_shutdown();
+ err_disable_platform:
+ if (dev->disable_platform)
+ dev->disable_platform(pdev);
++err_free_dev:
++ kfree(dev);
+
+ return ret;
+ }
+@@ -896,18 +912,8 @@ err_disable_platform:
+ static int dim2_remove(struct platform_device *pdev)
+ {
+ struct dim2_hdm *dev = platform_get_drvdata(pdev);
+- unsigned long flags;
+
+- dim2_sysfs_destroy(&dev->dev);
+ most_deregister_interface(&dev->most_iface);
+- kthread_stop(dev->netinfo_task);
+-
+- spin_lock_irqsave(&dim_lock, flags);
+- dim_shutdown();
+- spin_unlock_irqrestore(&dim_lock, flags);
+-
+- if (dev->disable_platform)
+- dev->disable_platform(pdev);
+
+ return 0;
+ }
+@@ -1082,6 +1088,7 @@ static struct platform_driver dim2_driver = {
+ .driver = {
+ .name = "hdm_dim2",
+ .of_match_table = dim2_of_match,
++ .dev_groups = dim2_groups,
+ },
+ };
+
+diff --git a/drivers/staging/most/dim2/sysfs.c b/drivers/staging/most/dim2/sysfs.c
+deleted file mode 100644
+index c85b2cdcdca3d..0000000000000
+--- a/drivers/staging/most/dim2/sysfs.c
++++ /dev/null
+@@ -1,49 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * sysfs.c - MediaLB sysfs information
+- *
+- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+- */
+-
+-/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+-#include <linux/kernel.h>
+-#include "sysfs.h"
+-#include <linux/device.h>
+-
+-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+- char *buf)
+-{
+- bool state = dim2_sysfs_get_state_cb();
+-
+- return sprintf(buf, "%s\n", state ? "locked" : "");
+-}
+-
+-static DEVICE_ATTR_RO(state);
+-
+-static struct attribute *dev_attrs[] = {
+- &dev_attr_state.attr,
+- NULL,
+-};
+-
+-static struct attribute_group dev_attr_group = {
+- .attrs = dev_attrs,
+-};
+-
+-static const struct attribute_group *dev_attr_groups[] = {
+- &dev_attr_group,
+- NULL,
+-};
+-
+-int dim2_sysfs_probe(struct device *dev)
+-{
+- dev->groups = dev_attr_groups;
+- return device_register(dev);
+-}
+-
+-void dim2_sysfs_destroy(struct device *dev)
+-{
+- device_unregister(dev);
+-}
+diff --git a/drivers/staging/most/dim2/sysfs.h b/drivers/staging/most/dim2/sysfs.h
+index 24277a17cff3d..09115cf4ed00e 100644
+--- a/drivers/staging/most/dim2/sysfs.h
++++ b/drivers/staging/most/dim2/sysfs.h
+@@ -16,15 +16,4 @@ struct medialb_bus {
+ struct kobject kobj_group;
+ };
+
+-struct device;
+-
+-int dim2_sysfs_probe(struct device *dev);
+-void dim2_sysfs_destroy(struct device *dev);
+-
+-/*
+- * callback,
+- * must deliver MediaLB state as true if locked or false if unlocked
+- */
+-bool dim2_sysfs_get_state_cb(void);
+-
+ #endif /* DIM2_SYSFS_H */
+diff --git a/drivers/staging/r8188eu/core/rtw_mlme.c b/drivers/staging/r8188eu/core/rtw_mlme.c
+index 1115ff5d865ad..bd991d7ed8090 100644
+--- a/drivers/staging/r8188eu/core/rtw_mlme.c
++++ b/drivers/staging/r8188eu/core/rtw_mlme.c
+@@ -1722,6 +1722,8 @@ int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, in
+ psetkeyparm->grpkey = 1;
+ break;
+ default:
++ kfree(psetkeyparm);
++ kfree(pcmd);
+ res = _FAIL;
+ goto exit;
+ }
+diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c
+index 5a472a4954b0f..63d312d01171e 100644
+--- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c
++++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c
+@@ -104,6 +104,7 @@ static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
+ {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
+ {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
+ {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
++ {0x00}, /* 0x13 */
+ {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
+ {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
+ {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
+@@ -115,6 +116,7 @@ static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
+ {0x00}, /* 0x1C, */
+ {0x00}, /* 0x1D, */
+ {0x00}, /* 0x1E, */
++ {0x00}, /* 0x1F, */
+ /* 0x20 ~ 0x7F , New Define ===== */
+ {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
+ {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
+@@ -7080,12 +7082,12 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+- pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
++ pcmd_obj = kzalloc(sizeof(*pcmd_obj), GFP_ATOMIC);
+ if (!pcmd_obj)
+ return;
+
+ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header));
+- pevtcmd = kzalloc(cmdsz, GFP_KERNEL);
++ pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+ if (!pevtcmd) {
+ kfree(pcmd_obj);
+ return;
+diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c
+index 1fd3750760018..0eccce57c63a6 100644
+--- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c
++++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c
+@@ -1978,7 +1978,7 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
+ struct ieee_param *param = NULL;
+ struct iw_point *pencoding = &wrqu->encoding;
+ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
+- int ret = 0;
++ int ret = -1;
+
+ param_len = sizeof(struct ieee_param) + pext->key_len;
+ param = kzalloc(param_len, GFP_KERNEL);
+@@ -2004,7 +2004,7 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
+ alg_name = "CCMP";
+ break;
+ default:
+- return -1;
++ goto out;
+ }
+
+ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+@@ -2031,6 +2031,7 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
+
+ ret = wpa_set_encryption(dev, param, param_len);
+
++out:
+ kfree(param);
+ return ret;
+ }
+@@ -2060,6 +2061,7 @@ static int rtw_wx_read32(struct net_device *dev,
+ u32 data32;
+ u32 bytes;
+ u8 *ptmp;
++ int ret;
+
+ padapter = (struct adapter *)rtw_netdev_priv(dev);
+ p = &wrqu->data;
+@@ -2092,12 +2094,17 @@ static int rtw_wx_read32(struct net_device *dev,
+ break;
+ default:
+ DBG_88E(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_free_ptmp;
+ }
+ DBG_88E(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra);
+
+ kfree(ptmp);
+ return 0;
++
++err_free_ptmp:
++ kfree(ptmp);
++ return ret;
+ }
+
+ static int rtw_wx_write32(struct net_device *dev,
+diff --git a/drivers/staging/r8188eu/os_dep/mlme_linux.c b/drivers/staging/r8188eu/os_dep/mlme_linux.c
+index e3ee9dc7ab900..b0d1e20edc4c2 100644
+--- a/drivers/staging/r8188eu/os_dep/mlme_linux.c
++++ b/drivers/staging/r8188eu/os_dep/mlme_linux.c
+@@ -114,7 +114,7 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
+
+ buff = NULL;
+ if (authmode == _WPA_IE_ID_) {
+- buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL);
++ buff = kzalloc(IW_CUSTOM_MAX, GFP_ATOMIC);
+ if (!buff)
+ return;
+ p = buff;
+diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+index a7dd1578b2c6a..616ab3c8fde4f 100644
+--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
++++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+@@ -2549,13 +2549,14 @@ static void _rtl92e_pci_disconnect(struct pci_dev *pdev)
+ free_irq(dev->irq, dev);
+ priv->irq = 0;
+ }
+- free_rtllib(dev);
+
+ if (dev->mem_start != 0) {
+ iounmap((void __iomem *)dev->mem_start);
+ release_mem_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+ }
++
++ free_rtllib(dev);
+ }
+
+ pci_disable_device(pdev);
+diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
+index b6698656fc014..cf5cfee2936fd 100644
+--- a/drivers/staging/rtl8192u/r8192U_core.c
++++ b/drivers/staging/rtl8192u/r8192U_core.c
+@@ -229,7 +229,7 @@ int write_nic_byte_E(struct net_device *dev, int indx, u8 data)
+
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE,
+- indx | 0xfe00, 0, usbdata, 1, HZ / 2);
++ indx | 0xfe00, 0, usbdata, 1, 500);
+ kfree(usbdata);
+
+ if (status < 0) {
+@@ -251,7 +251,7 @@ int read_nic_byte_E(struct net_device *dev, int indx, u8 *data)
+
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+- indx | 0xfe00, 0, usbdata, 1, HZ / 2);
++ indx | 0xfe00, 0, usbdata, 1, 500);
+ *data = *usbdata;
+ kfree(usbdata);
+
+@@ -279,7 +279,7 @@ int write_nic_byte(struct net_device *dev, int indx, u8 data)
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 1, HZ / 2);
++ usbdata, 1, 500);
+ kfree(usbdata);
+
+ if (status < 0) {
+@@ -305,7 +305,7 @@ int write_nic_word(struct net_device *dev, int indx, u16 data)
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 2, HZ / 2);
++ usbdata, 2, 500);
+ kfree(usbdata);
+
+ if (status < 0) {
+@@ -331,7 +331,7 @@ int write_nic_dword(struct net_device *dev, int indx, u32 data)
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 4, HZ / 2);
++ usbdata, 4, 500);
+ kfree(usbdata);
+
+ if (status < 0) {
+@@ -355,7 +355,7 @@ int read_nic_byte(struct net_device *dev, int indx, u8 *data)
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 1, HZ / 2);
++ usbdata, 1, 500);
+ *data = *usbdata;
+ kfree(usbdata);
+
+@@ -380,7 +380,7 @@ int read_nic_word(struct net_device *dev, int indx, u16 *data)
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 2, HZ / 2);
++ usbdata, 2, 500);
+ *data = *usbdata;
+ kfree(usbdata);
+
+@@ -404,7 +404,7 @@ static int read_nic_word_E(struct net_device *dev, int indx, u16 *data)
+
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+- indx | 0xfe00, 0, usbdata, 2, HZ / 2);
++ indx | 0xfe00, 0, usbdata, 2, 500);
+ *data = *usbdata;
+ kfree(usbdata);
+
+@@ -430,7 +430,7 @@ int read_nic_dword(struct net_device *dev, int indx, u32 *data)
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+ (indx & 0xff) | 0xff00, (indx >> 8) & 0x0f,
+- usbdata, 4, HZ / 2);
++ usbdata, 4, 500);
+ *data = *usbdata;
+ kfree(usbdata);
+
+diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
+index 505ebeb643dc2..cae04272deffe 100644
+--- a/drivers/staging/rtl8712/usb_intf.c
++++ b/drivers/staging/rtl8712/usb_intf.c
+@@ -595,12 +595,12 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
+
+ /* never exit with a firmware callback pending */
+ wait_for_completion(&padapter->rtl8712_fw_ready);
++ if (pnetdev->reg_state != NETREG_UNINITIALIZED)
++ unregister_netdev(pnetdev); /* will call netdev_close() */
+ usb_set_intfdata(pusb_intf, NULL);
+ release_firmware(padapter->fw);
+ if (drvpriv.drv_registered)
+ padapter->surprise_removed = true;
+- if (pnetdev->reg_state != NETREG_UNINITIALIZED)
+- unregister_netdev(pnetdev); /* will call netdev_close() */
+ r8712_flush_rwctrl_works(padapter);
+ r8712_flush_led_works(padapter);
+ udelay(1);
+diff --git a/drivers/staging/rtl8712/usb_ops_linux.c b/drivers/staging/rtl8712/usb_ops_linux.c
+index 655497cead122..f984a5ab2c6ff 100644
+--- a/drivers/staging/rtl8712/usb_ops_linux.c
++++ b/drivers/staging/rtl8712/usb_ops_linux.c
+@@ -494,7 +494,7 @@ int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value,
+ memcpy(pIo_buf, pdata, len);
+ }
+ status = usb_control_msg(udev, pipe, request, reqtype, value, index,
+- pIo_buf, len, HZ / 2);
++ pIo_buf, len, 500);
+ if (status > 0) { /* Success this control transfer. */
+ if (requesttype == 0x01) {
+ /* For Control read transfer, we have to copy the read
+diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
+index ab6a24d70cc96..cf79bec916c51 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
++++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
+@@ -897,7 +897,6 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue)
+ {
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+- struct sta_priv *pstapriv = &adapter->stapriv;
+ struct dvobj_priv *psdpriv = adapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+
+@@ -905,11 +904,7 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue)
+ struct sta_info *psta;
+
+ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.mac_address);
+- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ rtw_free_stainfo(adapter, psta);
+-
+- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+-
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) {
+@@ -1239,16 +1234,13 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
+ rtw_indicate_connect(adapter);
+ }
+
++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
++
+ /* s5. Cancel assoc_timer */
+ del_timer_sync(&pmlmepriv->assoc_timer);
+-
+ } else {
+ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
+- goto ignore_joinbss_callback;
+ }
+-
+- spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
+-
+ } else if (pnetwork->join_res == -4) {
+ rtw_reset_securitypriv(adapter);
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+index 375d2a742dd2d..ad9c237054c4b 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
++++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+@@ -1489,9 +1489,7 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame)
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+- /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */
+ /* rtw_free_stainfo(padapter, psta); */
+- /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */
+
+ netdev_dbg(padapter->pnetdev,
+ "ap recv deauth reason code(%d) sta:%pM\n", reason,
+@@ -1565,9 +1563,7 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame)
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+- /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */
+ /* rtw_free_stainfo(padapter, psta); */
+- /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */
+
+ netdev_dbg(padapter->pnetdev,
+ "ap recv disassoc reason code(%d) sta:%pM\n",
+@@ -5919,7 +5915,6 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf)
+ struct sta_info *psta_bmc;
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
+ struct xmit_frame *pxmitframe = NULL;
+- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ /* for BC/MC Frames */
+@@ -5930,8 +5925,7 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf)
+ if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len > 0)) {
+ msleep(10);/* 10ms, ATIM(HIQ) Windows */
+
+- /* spin_lock_bh(&psta_bmc->sleep_q.lock); */
+- spin_lock_bh(&pxmitpriv->lock);
++ spin_lock_bh(&psta_bmc->sleep_q.lock);
+
+ xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+@@ -5954,8 +5948,7 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf)
+ rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
+ }
+
+- /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */
+- spin_unlock_bh(&pxmitpriv->lock);
++ spin_unlock_bh(&psta_bmc->sleep_q.lock);
+
+ /* check hi queue and bmc_sleepq */
+ rtw_chk_hi_queue_cmd(padapter);
+diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c
+index 5b0a596eefb77..3564e2af5741b 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_recv.c
++++ b/drivers/staging/rtl8723bs/core/rtw_recv.c
+@@ -953,10 +953,8 @@ static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_
+ if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) {
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+- /* spin_lock_bh(&psta->sleep_q.lock); */
+- spin_lock_bh(&pxmitpriv->lock);
++ spin_lock_bh(&psta->sleep_q.lock);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+@@ -987,12 +985,10 @@ static signed int validate_recv_ctrl_frame(struct adapter *padapter, union recv_
+ update_beacon(padapter, WLAN_EID_TIM, NULL, true);
+ }
+
+- /* spin_unlock_bh(&psta->sleep_q.lock); */
+- spin_unlock_bh(&pxmitpriv->lock);
++ spin_unlock_bh(&psta->sleep_q.lock);
+
+ } else {
+- /* spin_unlock_bh(&psta->sleep_q.lock); */
+- spin_unlock_bh(&pxmitpriv->lock);
++ spin_unlock_bh(&psta->sleep_q.lock);
+
+ if (pstapriv->tim_bitmap&BIT(psta->aid)) {
+ if (psta->sleepq_len == 0) {
+diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
+index 67ca219f95bf8..3d269842677dd 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
++++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
+@@ -263,7 +263,6 @@ exit:
+ return psta;
+ }
+
+-/* using pstapriv->sta_hash_lock to protect */
+ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta)
+ {
+ int i;
+@@ -289,51 +288,55 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta)
+
+ /* list_del_init(&psta->wakeup_list); */
+
+- spin_lock_bh(&pxmitpriv->lock);
+-
++ spin_lock_bh(&psta->sleep_q.lock);
+ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q);
+ psta->sleepq_len = 0;
++ spin_unlock_bh(&psta->sleep_q.lock);
++
++ spin_lock_bh(&pxmitpriv->lock);
+
+ /* vo */
+- /* spin_lock_bh(&(pxmitpriv->vo_pending.lock)); */
++ spin_lock_bh(&pstaxmitpriv->vo_q.sta_pending.lock);
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
+ list_del_init(&(pstaxmitpriv->vo_q.tx_pending));
+ phwxmit = pxmitpriv->hwxmits;
+ phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt;
+ pstaxmitpriv->vo_q.qcnt = 0;
+- /* spin_unlock_bh(&(pxmitpriv->vo_pending.lock)); */
++ spin_unlock_bh(&pstaxmitpriv->vo_q.sta_pending.lock);
+
+ /* vi */
+- /* spin_lock_bh(&(pxmitpriv->vi_pending.lock)); */
++ spin_lock_bh(&pstaxmitpriv->vi_q.sta_pending.lock);
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
+ list_del_init(&(pstaxmitpriv->vi_q.tx_pending));
+ phwxmit = pxmitpriv->hwxmits+1;
+ phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt;
+ pstaxmitpriv->vi_q.qcnt = 0;
+- /* spin_unlock_bh(&(pxmitpriv->vi_pending.lock)); */
++ spin_unlock_bh(&pstaxmitpriv->vi_q.sta_pending.lock);
+
+ /* be */
+- /* spin_lock_bh(&(pxmitpriv->be_pending.lock)); */
++ spin_lock_bh(&pstaxmitpriv->be_q.sta_pending.lock);
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
+ list_del_init(&(pstaxmitpriv->be_q.tx_pending));
+ phwxmit = pxmitpriv->hwxmits+2;
+ phwxmit->accnt -= pstaxmitpriv->be_q.qcnt;
+ pstaxmitpriv->be_q.qcnt = 0;
+- /* spin_unlock_bh(&(pxmitpriv->be_pending.lock)); */
++ spin_unlock_bh(&pstaxmitpriv->be_q.sta_pending.lock);
+
+ /* bk */
+- /* spin_lock_bh(&(pxmitpriv->bk_pending.lock)); */
++ spin_lock_bh(&pstaxmitpriv->bk_q.sta_pending.lock);
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
+ list_del_init(&(pstaxmitpriv->bk_q.tx_pending));
+ phwxmit = pxmitpriv->hwxmits+3;
+ phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt;
+ pstaxmitpriv->bk_q.qcnt = 0;
+- /* spin_unlock_bh(&(pxmitpriv->bk_pending.lock)); */
++ spin_unlock_bh(&pstaxmitpriv->bk_q.sta_pending.lock);
+
+ spin_unlock_bh(&pxmitpriv->lock);
+
++ spin_lock_bh(&pstapriv->sta_hash_lock);
+ list_del_init(&psta->hash_list);
+ pstapriv->asoc_sta_count--;
++ spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+ /* re-init sta_info; 20061114 will be init in alloc_stainfo */
+ /* _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); */
+@@ -428,6 +431,7 @@ void rtw_free_all_stainfo(struct adapter *padapter)
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter);
++ LIST_HEAD(stainfo_free_list);
+
+ if (pstapriv->asoc_sta_count == 1)
+ return;
+@@ -440,11 +444,16 @@ void rtw_free_all_stainfo(struct adapter *padapter)
+ psta = list_entry(plist, struct sta_info, hash_list);
+
+ if (pbcmc_stainfo != psta)
+- rtw_free_stainfo(padapter, psta);
++ list_move(&psta->hash_list, &stainfo_free_list);
+ }
+ }
+
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
++
++ list_for_each_safe(plist, tmp, &stainfo_free_list) {
++ psta = list_entry(plist, struct sta_info, hash_list);
++ rtw_free_stainfo(padapter, psta);
++ }
+ }
+
+ /* any station allocated can be searched by hash list */
+diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c
+index 79e4d7df1ef57..6b37b42ec2266 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_xmit.c
++++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c
+@@ -1723,15 +1723,12 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram
+ struct list_head *plist, *phead, *tmp;
+ struct xmit_frame *pxmitframe;
+
+- spin_lock_bh(&pframequeue->lock);
+-
+ phead = get_list_head(pframequeue);
+ list_for_each_safe(plist, tmp, phead) {
+ pxmitframe = list_entry(plist, struct xmit_frame, list);
+
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ }
+- spin_unlock_bh(&pframequeue->lock);
+ }
+
+ s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
+@@ -1786,6 +1783,7 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
+ struct sta_info *psta;
+ struct tx_servq *ptxservq;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
++ struct xmit_priv *xmit_priv = &padapter->xmitpriv;
+ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
+ signed int res = _SUCCESS;
+
+@@ -1803,12 +1801,14 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
+
+ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
++ spin_lock_bh(&xmit_priv->lock);
+ if (list_empty(&ptxservq->tx_pending))
+ list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue));
+
+ list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
+ ptxservq->qcnt++;
+ phwxmits[ac_index].accnt++;
++ spin_unlock_bh(&xmit_priv->lock);
+
+ exit:
+
+@@ -2191,11 +2191,10 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
+ struct xmit_frame *pxmitframe = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+
+- spin_lock_bh(&pxmitpriv->lock);
++ spin_lock_bh(&psta->sleep_q.lock);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+@@ -2296,7 +2295,7 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
+
+ _exit:
+
+- spin_unlock_bh(&pxmitpriv->lock);
++ spin_unlock_bh(&psta->sleep_q.lock);
+
+ if (update_mask)
+ update_beacon(padapter, WLAN_EID_TIM, NULL, true);
+@@ -2308,9 +2307,8 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
+ struct xmit_frame *pxmitframe = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+- spin_lock_bh(&pxmitpriv->lock);
++ spin_lock_bh(&psta->sleep_q.lock);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+@@ -2363,7 +2361,7 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst
+ }
+ }
+
+- spin_unlock_bh(&pxmitpriv->lock);
++ spin_unlock_bh(&psta->sleep_q.lock);
+ }
+
+ void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
+index 156d6aba18ca1..5f5c4719b5868 100644
+--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
++++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
+@@ -507,9 +507,7 @@ s32 rtl8723bs_hal_xmit(
+ rtw_issue_addbareq_cmd(padapter, pxmitframe);
+ }
+
+- spin_lock_bh(&pxmitpriv->lock);
+ err = rtw_xmitframe_enqueue(padapter, pxmitframe);
+- spin_unlock_bh(&pxmitpriv->lock);
+ if (err != _SUCCESS) {
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+index 9d4a233a861e3..295121c268bd4 100644
+--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
++++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+@@ -835,9 +835,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta)
+ {
+- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ rtw_free_stainfo(padapter, psta);
+- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+
+ psta = NULL;
+ }
+diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
+index e06d7e1ebe9c3..61b8cc05f2935 100644
+--- a/drivers/staging/wfx/bus_sdio.c
++++ b/drivers/staging/wfx/bus_sdio.c
+@@ -120,19 +120,22 @@ static int wfx_sdio_irq_subscribe(void *priv)
+ return ret;
+ }
+
++ flags = irq_get_trigger_type(bus->of_irq);
++ if (!flags)
++ flags = IRQF_TRIGGER_HIGH;
++ flags |= IRQF_ONESHOT;
++ ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
++ wfx_sdio_irq_handler_ext, flags,
++ "wfx", bus);
++ if (ret)
++ return ret;
+ sdio_claim_host(bus->func);
+ cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL);
+ cccr |= BIT(0);
+ cccr |= BIT(bus->func->num);
+ sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL);
+ sdio_release_host(bus->func);
+- flags = irq_get_trigger_type(bus->of_irq);
+- if (!flags)
+- flags = IRQF_TRIGGER_HIGH;
+- flags |= IRQF_ONESHOT;
+- return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
+- wfx_sdio_irq_handler_ext, flags,
+- "wfx", bus);
++ return 0;
+ }
+
+ static int wfx_sdio_irq_unsubscribe(void *priv)
+diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
+index cb1de1ecaaa61..bd0f2ce011dd7 100644
+--- a/drivers/target/target_core_alua.c
++++ b/drivers/target/target_core_alua.c
+@@ -1674,7 +1674,6 @@ int core_alua_set_tg_pt_gp_id(
+ pr_err("Maximum ALUA alua_tg_pt_gps_count:"
+ " 0x0000ffff reached\n");
+ spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+- kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
+ return -ENOSPC;
+ }
+ again:
+diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
+index 8cb1fa0c05857..44bb380e7390c 100644
+--- a/drivers/target/target_core_device.c
++++ b/drivers/target/target_core_device.c
+@@ -772,6 +772,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
+ INIT_LIST_HEAD(&dev->t10_alua.lba_map_list);
+ spin_lock_init(&dev->t10_alua.lba_map_lock);
+
++ INIT_WORK(&dev->delayed_cmd_work, target_do_delayed_work);
++
+ dev->t10_wwn.t10_dev = dev;
+ /*
+ * Use OpenFabrics IEEE Company ID: 00 14 05
+diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
+index a343bcfa2180f..a889a6237d9c1 100644
+--- a/drivers/target/target_core_internal.h
++++ b/drivers/target/target_core_internal.h
+@@ -151,6 +151,7 @@ int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
+ void transport_clear_lun_ref(struct se_lun *);
+ sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
+ void target_qf_do_work(struct work_struct *work);
++void target_do_delayed_work(struct work_struct *work);
+ bool target_check_wce(struct se_device *dev);
+ bool target_check_fua(struct se_device *dev);
+ void __target_execute_cmd(struct se_cmd *, bool);
+diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
+index e7fcbc09f9dbc..bac111456fa1d 100644
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -50,15 +50,6 @@ EXPORT_SYMBOL(core_tmr_alloc_req);
+
+ void core_tmr_release_req(struct se_tmr_req *tmr)
+ {
+- struct se_device *dev = tmr->tmr_dev;
+- unsigned long flags;
+-
+- if (dev) {
+- spin_lock_irqsave(&dev->se_tmr_lock, flags);
+- list_del_init(&tmr->tmr_list);
+- spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+- }
+-
+ kfree(tmr);
+ }
+
+@@ -156,13 +147,6 @@ void core_tmr_abort_task(
+ se_cmd->state_active = false;
+ spin_unlock_irqrestore(&dev->queues[i].lock, flags);
+
+- /*
+- * Ensure that this ABORT request is visible to the LU
+- * RESET code.
+- */
+- if (!tmr->tmr_dev)
+- WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) < 0);
+-
+ if (dev->transport->tmr_notify)
+ dev->transport->tmr_notify(dev, TMR_ABORT_TASK,
+ &aborted_list);
+@@ -234,6 +218,7 @@ static void core_tmr_drain_tmr_list(
+ }
+
+ list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
++ tmr_p->tmr_dev = NULL;
+ }
+ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+
+diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
+index 14c6f2bb1b01d..72edf5bd75ee6 100644
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -676,6 +676,21 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
+ spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags);
+ }
+
++static void target_remove_from_tmr_list(struct se_cmd *cmd)
++{
++ struct se_device *dev = NULL;
++ unsigned long flags;
++
++ if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
++ dev = cmd->se_tmr_req->tmr_dev;
++
++ if (dev) {
++ spin_lock_irqsave(&dev->se_tmr_lock, flags);
++ if (cmd->se_tmr_req->tmr_dev)
++ list_del_init(&cmd->se_tmr_req->tmr_list);
++ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
++ }
++}
+ /*
+ * This function is called by the target core after the target core has
+ * finished processing a SCSI command or SCSI TMF. Both the regular command
+@@ -687,13 +702,6 @@ static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
+ {
+ unsigned long flags;
+
+- target_remove_from_state_list(cmd);
+-
+- /*
+- * Clear struct se_cmd->se_lun before the handoff to FE.
+- */
+- cmd->se_lun = NULL;
+-
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ /*
+ * Determine if frontend context caller is requesting the stopping of
+@@ -728,8 +736,16 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
+ if (!lun)
+ return;
+
++ target_remove_from_state_list(cmd);
++ target_remove_from_tmr_list(cmd);
++
+ if (cmpxchg(&cmd->lun_ref_active, true, false))
+ percpu_ref_put(&lun->lun_ref);
++
++ /*
++ * Clear struct se_cmd->se_lun before the handoff to FE.
++ */
++ cmd->se_lun = NULL;
+ }
+
+ static void target_complete_failure_work(struct work_struct *work)
+@@ -2173,32 +2189,35 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
+ */
+ switch (cmd->sam_task_attr) {
+ case TCM_HEAD_TAG:
++ atomic_inc_mb(&dev->non_ordered);
+ pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x\n",
+ cmd->t_task_cdb[0]);
+ return false;
+ case TCM_ORDERED_TAG:
+- atomic_inc_mb(&dev->dev_ordered_sync);
++ atomic_inc_mb(&dev->delayed_cmd_count);
+
+ pr_debug("Added ORDERED for CDB: 0x%02x to ordered list\n",
+ cmd->t_task_cdb[0]);
+-
+- /*
+- * Execute an ORDERED command if no other older commands
+- * exist that need to be completed first.
+- */
+- if (!atomic_read(&dev->simple_cmds))
+- return false;
+ break;
+ default:
+ /*
+ * For SIMPLE and UNTAGGED Task Attribute commands
+ */
+- atomic_inc_mb(&dev->simple_cmds);
++ atomic_inc_mb(&dev->non_ordered);
++
++ if (atomic_read(&dev->delayed_cmd_count) == 0)
++ return false;
+ break;
+ }
+
+- if (atomic_read(&dev->dev_ordered_sync) == 0)
+- return false;
++ if (cmd->sam_task_attr != TCM_ORDERED_TAG) {
++ atomic_inc_mb(&dev->delayed_cmd_count);
++ /*
++ * We will account for this when we dequeue from the delayed
++ * list.
++ */
++ atomic_dec_mb(&dev->non_ordered);
++ }
+
+ spin_lock(&dev->delayed_cmd_lock);
+ list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list);
+@@ -2206,6 +2225,12 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
+
+ pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to delayed CMD listn",
+ cmd->t_task_cdb[0], cmd->sam_task_attr);
++ /*
++ * We may have no non ordered cmds when this function started or we
++ * could have raced with the last simple/head cmd completing, so kick
++ * the delayed handler here.
++ */
++ schedule_work(&dev->delayed_cmd_work);
+ return true;
+ }
+
+@@ -2243,29 +2268,48 @@ EXPORT_SYMBOL(target_execute_cmd);
+ * Process all commands up to the last received ORDERED task attribute which
+ * requires another blocking boundary
+ */
+-static void target_restart_delayed_cmds(struct se_device *dev)
++void target_do_delayed_work(struct work_struct *work)
+ {
+- for (;;) {
++ struct se_device *dev = container_of(work, struct se_device,
++ delayed_cmd_work);
++
++ spin_lock(&dev->delayed_cmd_lock);
++ while (!dev->ordered_sync_in_progress) {
+ struct se_cmd *cmd;
+
+- spin_lock(&dev->delayed_cmd_lock);
+- if (list_empty(&dev->delayed_cmd_list)) {
+- spin_unlock(&dev->delayed_cmd_lock);
++ if (list_empty(&dev->delayed_cmd_list))
+ break;
+- }
+
+ cmd = list_entry(dev->delayed_cmd_list.next,
+ struct se_cmd, se_delayed_node);
++
++ if (cmd->sam_task_attr == TCM_ORDERED_TAG) {
++ /*
++ * Check if we started with:
++ * [ordered] [simple] [ordered]
++ * and we are now at the last ordered so we have to wait
++ * for the simple cmd.
++ */
++ if (atomic_read(&dev->non_ordered) > 0)
++ break;
++
++ dev->ordered_sync_in_progress = true;
++ }
++
+ list_del(&cmd->se_delayed_node);
++ atomic_dec_mb(&dev->delayed_cmd_count);
+ spin_unlock(&dev->delayed_cmd_lock);
+
++ if (cmd->sam_task_attr != TCM_ORDERED_TAG)
++ atomic_inc_mb(&dev->non_ordered);
++
+ cmd->transport_state |= CMD_T_SENT;
+
+ __target_execute_cmd(cmd, true);
+
+- if (cmd->sam_task_attr == TCM_ORDERED_TAG)
+- break;
++ spin_lock(&dev->delayed_cmd_lock);
+ }
++ spin_unlock(&dev->delayed_cmd_lock);
+ }
+
+ /*
+@@ -2283,14 +2327,17 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
+ goto restart;
+
+ if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
+- atomic_dec_mb(&dev->simple_cmds);
++ atomic_dec_mb(&dev->non_ordered);
+ dev->dev_cur_ordered_id++;
+ } else if (cmd->sam_task_attr == TCM_HEAD_TAG) {
++ atomic_dec_mb(&dev->non_ordered);
+ dev->dev_cur_ordered_id++;
+ pr_debug("Incremented dev_cur_ordered_id: %u for HEAD_OF_QUEUE\n",
+ dev->dev_cur_ordered_id);
+ } else if (cmd->sam_task_attr == TCM_ORDERED_TAG) {
+- atomic_dec_mb(&dev->dev_ordered_sync);
++ spin_lock(&dev->delayed_cmd_lock);
++ dev->ordered_sync_in_progress = false;
++ spin_unlock(&dev->delayed_cmd_lock);
+
+ dev->dev_cur_ordered_id++;
+ pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
+@@ -2299,7 +2346,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
+ cmd->se_cmd_flags &= ~SCF_TASK_ATTR_SET;
+
+ restart:
+- target_restart_delayed_cmds(dev);
++ if (atomic_read(&dev->delayed_cmd_count) > 0)
++ schedule_work(&dev->delayed_cmd_work);
+ }
+
+ static void transport_complete_qf(struct se_cmd *cmd)
+diff --git a/drivers/tee/amdtee/core.c b/drivers/tee/amdtee/core.c
+index da6b88e80dc07..297dc62bca298 100644
+--- a/drivers/tee/amdtee/core.c
++++ b/drivers/tee/amdtee/core.c
+@@ -203,9 +203,8 @@ static int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta,
+
+ *ta_size = roundup(fw->size, PAGE_SIZE);
+ *ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size));
+- if (IS_ERR(*ta)) {
+- pr_err("%s: get_free_pages failed 0x%llx\n", __func__,
+- (u64)*ta);
++ if (!*ta) {
++ pr_err("%s: get_free_pages failed\n", __func__);
+ rc = -ENOMEM;
+ goto rel_fw;
+ }
+diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
+index 59e93b04f0a9e..66cd0190bc035 100644
+--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
++++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
+@@ -7,6 +7,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
++#include <linux/io-64-nonatomic-lo-hi.h>
+ #include "processor_thermal_device.h"
+
+ #define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
+diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
+index 2b8a3235d518b..3b3e81f99a34c 100644
+--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
++++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
+@@ -29,7 +29,7 @@ static const char * const fivr_strings[] = {
+ };
+
+ static const struct mmio_reg tgl_fivr_mmio_regs[] = {
+- { 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
++ { 0, 0x5A18, 3, 0x7, 11}, /* vco_ref_code_lo */
+ { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
+ { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
+ { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
+diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
+index 7d942f71e5328..bfd889422dd32 100644
+--- a/drivers/thermal/qcom/Kconfig
++++ b/drivers/thermal/qcom/Kconfig
+@@ -34,7 +34,7 @@ config QCOM_SPMI_TEMP_ALARM
+
+ config QCOM_LMH
+ tristate "Qualcomm Limits Management Hardware"
+- depends on ARCH_QCOM
++ depends on ARCH_QCOM && QCOM_SCM
+ help
+ This enables initialization of Qualcomm limits management
+ hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on
+diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
+index b1162e566a707..99a8d9f3e03ca 100644
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -603,22 +603,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
+ int ret;
+
+ /* VER_0 doesn't have VALID bit */
+- if (tsens_version(priv) >= VER_0_1) {
+- ret = regmap_field_read(priv->rf[valid_idx], &valid);
+- if (ret)
+- return ret;
+- while (!valid) {
+- /* Valid bit is 0 for 6 AHB clock cycles.
+- * At 19.2MHz, 1 AHB clock is ~60ns.
+- * We should enter this loop very, very rarely.
+- */
+- ndelay(400);
+- ret = regmap_field_read(priv->rf[valid_idx], &valid);
+- if (ret)
+- return ret;
+- }
+- }
++ if (tsens_version(priv) == VER_0)
++ goto get_temp;
++
++ /* Valid bit is 0 for 6 AHB clock cycles.
++ * At 19.2MHz, 1 AHB clock is ~60ns.
++ * We should enter this loop very, very rarely.
++ * Wait 1 us since it's the min of poll_timeout macro.
++ * Old value was 400 ns.
++ */
++ ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
++ valid, 1, 20 * USEC_PER_MSEC);
++ if (ret)
++ return ret;
+
++get_temp:
+ /* Valid bit is set, OK to read the temperature */
+ *temp = tsens_hw_to_mC(s, temp_idx);
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 51374f4e1ccaf..13891745a9719 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -419,6 +419,8 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
+ {
+ struct thermal_instance *pos;
+ tz->temperature = THERMAL_TEMP_INVALID;
++ tz->prev_low_trip = -INT_MAX;
++ tz->prev_high_trip = INT_MAX;
+ list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+ pos->initialized = false;
+ }
+@@ -887,7 +889,7 @@ __thermal_cooling_device_register(struct device_node *np,
+ {
+ struct thermal_cooling_device *cdev;
+ struct thermal_zone_device *pos = NULL;
+- int ret;
++ int id, ret;
+
+ if (!ops || !ops->get_max_state || !ops->get_cur_state ||
+ !ops->set_cur_state)
+@@ -901,6 +903,11 @@ __thermal_cooling_device_register(struct device_node *np,
+ if (ret < 0)
+ goto out_kfree_cdev;
+ cdev->id = ret;
++ id = ret;
++
++ ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
++ if (ret)
++ goto out_ida_remove;
+
+ cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
+ if (!cdev->type) {
+@@ -916,7 +923,6 @@ __thermal_cooling_device_register(struct device_node *np,
+ cdev->device.class = &thermal_class;
+ cdev->devdata = devdata;
+ thermal_cooling_device_setup_sysfs(cdev);
+- dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
+ ret = device_register(&cdev->device);
+ if (ret)
+ goto out_kfree_type;
+@@ -941,8 +947,9 @@ __thermal_cooling_device_register(struct device_node *np,
+ out_kfree_type:
+ kfree(cdev->type);
+ put_device(&cdev->device);
++ cdev = NULL;
+ out_ida_remove:
+- ida_simple_remove(&thermal_cdev_ida, cdev->id);
++ ida_simple_remove(&thermal_cdev_ida, id);
+ out_kfree_cdev:
+ kfree(cdev);
+ return ERR_PTR(ret);
+@@ -1227,6 +1234,10 @@ thermal_zone_device_register(const char *type, int trips, int mask,
+ tz->id = id;
+ strlcpy(tz->type, type, sizeof(tz->type));
+
++ result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
++ if (result)
++ goto remove_id;
++
+ if (!ops->critical)
+ ops->critical = thermal_zone_device_critical;
+
+@@ -1248,7 +1259,6 @@ thermal_zone_device_register(const char *type, int trips, int mask,
+ /* A new thermal zone needs to be updated anyway. */
+ atomic_set(&tz->need_update, 1);
+
+- dev_set_name(&tz->device, "thermal_zone%d", tz->id);
+ result = device_register(&tz->device);
+ if (result)
+ goto release_device;
+diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
+index 6379f26a335f6..9233f7e744544 100644
+--- a/drivers/thermal/thermal_of.c
++++ b/drivers/thermal/thermal_of.c
+@@ -89,7 +89,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+- if (!data->ops->get_temp)
++ if (!data->ops || !data->ops->get_temp)
+ return -EINVAL;
+
+ return data->ops->get_temp(data->sensor_data, temp);
+@@ -186,6 +186,9 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
+ {
+ struct __thermal_zone *data = tz->devdata;
+
++ if (!data->ops || !data->ops->set_emul_temp)
++ return -EINVAL;
++
+ return data->ops->set_emul_temp(data->sensor_data, temp);
+ }
+
+@@ -194,7 +197,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+- if (!data->ops->get_trend)
++ if (!data->ops || !data->ops->get_trend)
+ return -EINVAL;
+
+ return data->ops->get_trend(data->sensor_data, trip, trend);
+@@ -301,7 +304,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
+ if (trip >= data->ntrips || trip < 0)
+ return -EDOM;
+
+- if (data->ops->set_trip_temp) {
++ if (data->ops && data->ops->set_trip_temp) {
+ int ret;
+
+ ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
+diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
+index f0bf01ea069ae..8ee7ce1206925 100644
+--- a/drivers/tty/hvc/hvc_xen.c
++++ b/drivers/tty/hvc/hvc_xen.c
+@@ -37,6 +37,8 @@ struct xencons_info {
+ struct xenbus_device *xbdev;
+ struct xencons_interface *intf;
+ unsigned int evtchn;
++ XENCONS_RING_IDX out_cons;
++ unsigned int out_cons_same;
+ struct hvc_struct *hvc;
+ int irq;
+ int vtermno;
+@@ -138,6 +140,8 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
+ XENCONS_RING_IDX cons, prod;
+ int recv = 0;
+ struct xencons_info *xencons = vtermno_to_xencons(vtermno);
++ unsigned int eoiflag = 0;
++
+ if (xencons == NULL)
+ return -EINVAL;
+ intf = xencons->intf;
+@@ -157,7 +161,27 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
+ mb(); /* read ring before consuming */
+ intf->in_cons = cons;
+
+- notify_daemon(xencons);
++ /*
++ * When to mark interrupt having been spurious:
++ * - there was no new data to be read, and
++ * - the backend did not consume some output bytes, and
++ * - the previous round with no read data didn't see consumed bytes
++ * (we might have a race with an interrupt being in flight while
++ * updating xencons->out_cons, so account for that by allowing one
++ * round without any visible reason)
++ */
++ if (intf->out_cons != xencons->out_cons) {
++ xencons->out_cons = intf->out_cons;
++ xencons->out_cons_same = 0;
++ }
++ if (recv) {
++ notify_daemon(xencons);
++ } else if (xencons->out_cons_same++ > 1) {
++ eoiflag = XEN_EOI_FLAG_SPURIOUS;
++ }
++
++ xen_irq_lateeoi(xencons->irq, eoiflag);
++
+ return recv;
+ }
+
+@@ -386,7 +410,7 @@ static int xencons_connect_backend(struct xenbus_device *dev,
+ if (ret)
+ return ret;
+ info->evtchn = evtchn;
+- irq = bind_evtchn_to_irq(evtchn);
++ irq = bind_interdomain_evtchn_to_irq_lateeoi(dev, evtchn);
+ if (irq < 0)
+ return irq;
+ info->irq = irq;
+@@ -550,7 +574,7 @@ static int __init xen_hvc_init(void)
+ return r;
+
+ info = vtermno_to_xencons(HVC_COOKIE);
+- info->irq = bind_evtchn_to_irq(info->evtchn);
++ info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
+ }
+ if (info->irq < 0)
+ info->irq = 0; /* NO_IRQ */
+diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
+index 580a37b3fe1b9..166f651fde33a 100644
+--- a/drivers/tty/n_hdlc.c
++++ b/drivers/tty/n_hdlc.c
+@@ -140,6 +140,8 @@ struct n_hdlc {
+ struct n_hdlc_buf_list rx_buf_list;
+ struct n_hdlc_buf_list tx_free_buf_list;
+ struct n_hdlc_buf_list rx_free_buf_list;
++ struct work_struct write_work;
++ struct tty_struct *tty_for_write_work;
+ };
+
+ /*
+@@ -154,6 +156,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
+ /* Local functions */
+
+ static struct n_hdlc *n_hdlc_alloc(void);
++static void n_hdlc_tty_write_work(struct work_struct *work);
+
+ /* max frame size for memory allocations */
+ static int maxframe = 4096;
+@@ -210,6 +213,8 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
+ wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible(&tty->write_wait);
+
++ cancel_work_sync(&n_hdlc->write_work);
++
+ n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
+ n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
+ n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
+@@ -241,6 +246,8 @@ static int n_hdlc_tty_open(struct tty_struct *tty)
+ return -ENFILE;
+ }
+
++ INIT_WORK(&n_hdlc->write_work, n_hdlc_tty_write_work);
++ n_hdlc->tty_for_write_work = tty;
+ tty->disc_data = n_hdlc;
+ tty->receive_room = 65536;
+
+@@ -334,6 +341,20 @@ check_again:
+ goto check_again;
+ } /* end of n_hdlc_send_frames() */
+
++/**
++ * n_hdlc_tty_write_work - Asynchronous callback for transmit wakeup
++ * @work: pointer to work_struct
++ *
++ * Called when low level device driver can accept more send data.
++ */
++static void n_hdlc_tty_write_work(struct work_struct *work)
++{
++ struct n_hdlc *n_hdlc = container_of(work, struct n_hdlc, write_work);
++ struct tty_struct *tty = n_hdlc->tty_for_write_work;
++
++ n_hdlc_send_frames(n_hdlc, tty);
++} /* end of n_hdlc_tty_write_work() */
++
+ /**
+ * n_hdlc_tty_wakeup - Callback for transmit wakeup
+ * @tty: pointer to associated tty instance data
+@@ -344,7 +365,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
+ {
+ struct n_hdlc *n_hdlc = tty->disc_data;
+
+- n_hdlc_send_frames(n_hdlc, tty);
++ schedule_work(&n_hdlc->write_work);
+ } /* end of n_hdlc_tty_wakeup() */
+
+ /**
+diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
+index 7f656fac503fe..5163d60756b73 100644
+--- a/drivers/tty/serial/8250/8250_bcm7271.c
++++ b/drivers/tty/serial/8250/8250_bcm7271.c
+@@ -237,6 +237,7 @@ struct brcmuart_priv {
+ u32 rx_err;
+ u32 rx_timeout;
+ u32 rx_abort;
++ u32 saved_mctrl;
+ };
+
+ static struct dentry *brcmuart_debugfs_root;
+@@ -1133,16 +1134,27 @@ static int brcmuart_remove(struct platform_device *pdev)
+ static int __maybe_unused brcmuart_suspend(struct device *dev)
+ {
+ struct brcmuart_priv *priv = dev_get_drvdata(dev);
++ struct uart_8250_port *up = serial8250_get_port(priv->line);
++ struct uart_port *port = &up->port;
+
+ serial8250_suspend_port(priv->line);
+ clk_disable_unprepare(priv->baud_mux_clk);
+
++ /*
++ * This will prevent resume from enabling RTS before the
++ * baud rate has been resored.
++ */
++ priv->saved_mctrl = port->mctrl;
++ port->mctrl = 0;
++
+ return 0;
+ }
+
+ static int __maybe_unused brcmuart_resume(struct device *dev)
+ {
+ struct brcmuart_priv *priv = dev_get_drvdata(dev);
++ struct uart_8250_port *up = serial8250_get_port(priv->line);
++ struct uart_port *port = &up->port;
+ int ret;
+
+ ret = clk_prepare_enable(priv->baud_mux_clk);
+@@ -1165,6 +1177,7 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
+ start_rx_dma(serial8250_get_port(priv->line));
+ }
+ serial8250_resume_port(priv->line);
++ port->mctrl = priv->saved_mctrl;
+ return 0;
+ }
+
+diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
+index a3a0154da567d..49559731bbcf1 100644
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -726,7 +726,7 @@ static struct platform_driver dw8250_platform_driver = {
+ .name = "dw-apb-uart",
+ .pm = &dw8250_pm_ops,
+ .of_match_table = dw8250_of_match,
+- .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
++ .acpi_match_table = dw8250_acpi_match,
+ },
+ .probe = dw8250_probe,
+ .remove = dw8250_remove,
+diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
+index 31c9e83ea3cb2..251f0018ae8ca 100644
+--- a/drivers/tty/serial/8250/8250_fintek.c
++++ b/drivers/tty/serial/8250/8250_fintek.c
+@@ -290,25 +290,6 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
+ }
+ }
+
+-static void fintek_8250_goto_highspeed(struct uart_8250_port *uart,
+- struct fintek_8250 *pdata)
+-{
+- sio_write_reg(pdata, LDN, pdata->index);
+-
+- switch (pdata->pid) {
+- case CHIP_ID_F81966:
+- case CHIP_ID_F81866: /* set uart clock for high speed serial mode */
+- sio_write_mask_reg(pdata, F81866_UART_CLK,
+- F81866_UART_CLK_MASK,
+- F81866_UART_CLK_14_769MHZ);
+-
+- uart->port.uartclk = 921600 * 16;
+- break;
+- default: /* leave clock speed untouched */
+- break;
+- }
+-}
+-
+ static void fintek_8250_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+@@ -430,7 +411,6 @@ static int probe_setup_port(struct fintek_8250 *pdata,
+
+ fintek_8250_set_irq_mode(pdata, level_mode);
+ fintek_8250_set_max_fifo(pdata);
+- fintek_8250_goto_highspeed(uart, pdata);
+
+ fintek_8250_exit_key(addr[i]);
+
+diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
+index 726912b16a559..f7d89440076a1 100644
+--- a/drivers/tty/serial/8250/8250_pci.c
++++ b/drivers/tty/serial/8250/8250_pci.c
+@@ -1349,29 +1349,33 @@ pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
+ {
+ int scr;
+ int lcr;
+- int actual_baud;
+- int tolerance;
+
+- for (scr = 5 ; scr <= 15 ; scr++) {
+- actual_baud = 921600 * 16 / scr;
+- tolerance = actual_baud / 50;
++ for (scr = 16; scr > 4; scr--) {
++ unsigned int maxrate = port->uartclk / scr;
++ unsigned int divisor = max(maxrate / baud, 1U);
++ int delta = maxrate / divisor - baud;
+
+- if ((baud < actual_baud + tolerance) &&
+- (baud > actual_baud - tolerance)) {
++ if (baud > maxrate + baud / 50)
++ continue;
+
++ if (delta > baud / 50)
++ divisor++;
++
++ if (divisor > 0xffff)
++ continue;
++
++ /* Update delta due to possible divisor change */
++ delta = maxrate / divisor - baud;
++ if (abs(delta) < baud / 50) {
+ lcr = serial_port_in(port, UART_LCR);
+ serial_port_out(port, UART_LCR, lcr | 0x80);
+-
+- serial_port_out(port, UART_DLL, 1);
+- serial_port_out(port, UART_DLM, 0);
++ serial_port_out(port, UART_DLL, divisor & 0xff);
++ serial_port_out(port, UART_DLM, divisor >> 8 & 0xff);
+ serial_port_out(port, 2, 16 - scr);
+ serial_port_out(port, UART_LCR, lcr);
+ return;
+- } else if (baud > actual_baud) {
+- break;
+ }
+ }
+- serial8250_do_set_divisor(port, baud, quot, quot_frac);
+ }
+ static int pci_pericom_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+@@ -2317,12 +2321,19 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+- .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
++ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
++ {
++ .vendor = PCI_VENDOR_ID_ACCESIO,
++ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = pci_pericom_setup_four_at_eight,
++ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
+index 66374704747ec..ec88b706e882f 100644
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -2024,13 +2024,6 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char mcr;
+
+- if (port->rs485.flags & SER_RS485_ENABLED) {
+- if (serial8250_in_MCR(up) & UART_MCR_RTS)
+- mctrl |= TIOCM_RTS;
+- else
+- mctrl &= ~TIOCM_RTS;
+- }
+-
+ mcr = serial8250_TIOCM_to_MCR(mctrl);
+
+ mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
+@@ -2696,21 +2689,32 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
+ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
+ {
+ struct uart_8250_port *up = up_to_u8250p(port);
++ struct tty_port *tport = &port->state->port;
+ unsigned int baud, quot, frac = 0;
+ struct ktermios *termios;
++ struct tty_struct *tty;
+ unsigned long flags;
+
+- mutex_lock(&port->state->port.mutex);
++ tty = tty_port_tty_get(tport);
++ if (!tty) {
++ mutex_lock(&tport->mutex);
++ port->uartclk = uartclk;
++ mutex_unlock(&tport->mutex);
++ return;
++ }
++
++ down_write(&tty->termios_rwsem);
++ mutex_lock(&tport->mutex);
+
+ if (port->uartclk == uartclk)
+ goto out_lock;
+
+ port->uartclk = uartclk;
+
+- if (!tty_port_initialized(&port->state->port))
++ if (!tty_port_initialized(tport))
+ goto out_lock;
+
+- termios = &port->state->port.tty->termios;
++ termios = &tty->termios;
+
+ baud = serial8250_get_baud_rate(port, termios, NULL);
+ quot = serial8250_get_divisor(port, baud, &frac);
+@@ -2727,7 +2731,9 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
+ serial8250_rpm_put(up);
+
+ out_lock:
+- mutex_unlock(&port->state->port.mutex);
++ mutex_unlock(&tport->mutex);
++ up_write(&tty->termios_rwsem);
++ tty_kref_put(tty);
+ }
+ EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index d361cd84ff8cf..52518a606c06a 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -2947,6 +2947,7 @@ MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
+
+ static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
+ { "ARMH0011", 0 },
++ { "ARMHB000", 0 },
+ {},
+ };
+ MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
+diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+index c719aa2b18328..d6d3db9c3b1f8 100644
+--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
++++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+@@ -1090,6 +1090,7 @@ static void cpm_put_poll_char(struct uart_port *port,
+ cpm_uart_early_write(pinfo, ch, 1, false);
+ }
+
++#ifdef CONFIG_SERIAL_CPM_CONSOLE
+ static struct uart_port *udbg_port;
+
+ static void udbg_cpm_putc(char c)
+@@ -1114,6 +1115,7 @@ static int udbg_cpm_getc(void)
+ cpu_relax();
+ return c;
+ }
++#endif /* CONFIG_SERIAL_CPM_CONSOLE */
+
+ #endif /* CONFIG_CONSOLE_POLL */
+
+diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
+index b1e7190ae4836..ac5112def40d1 100644
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -2625,6 +2625,7 @@ OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
+ OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
+ OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup);
+ OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
++OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup);
+ EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
+ EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
+
+diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
+index 8b121cd869e94..51a9f9423b1a6 100644
+--- a/drivers/tty/serial/imx.c
++++ b/drivers/tty/serial/imx.c
+@@ -2017,7 +2017,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+-static void __init
++static void
+ imx_uart_console_get_options(struct imx_port *sport, int *baud,
+ int *parity, int *bits)
+ {
+@@ -2076,7 +2076,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
+ }
+ }
+
+-static int __init
++static int
+ imx_uart_console_setup(struct console *co, char *options)
+ {
+ struct imx_port *sport;
+diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
+index dbc0559a91575..2941659e52747 100644
+--- a/drivers/tty/serial/liteuart.c
++++ b/drivers/tty/serial/liteuart.c
+@@ -270,8 +270,10 @@ static int liteuart_probe(struct platform_device *pdev)
+
+ /* get membase */
+ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+- if (IS_ERR(port->membase))
+- return PTR_ERR(port->membase);
++ if (IS_ERR(port->membase)) {
++ ret = PTR_ERR(port->membase);
++ goto err_erase_id;
++ }
+
+ /* values not from device tree */
+ port->dev = &pdev->dev;
+@@ -285,7 +287,18 @@ static int liteuart_probe(struct platform_device *pdev)
+ port->line = dev_id;
+ spin_lock_init(&port->lock);
+
+- return uart_add_one_port(&liteuart_driver, &uart->port);
++ platform_set_drvdata(pdev, port);
++
++ ret = uart_add_one_port(&liteuart_driver, &uart->port);
++ if (ret)
++ goto err_erase_id;
++
++ return 0;
++
++err_erase_id:
++ xa_erase(&liteuart_array, uart->id);
++
++ return ret;
+ }
+
+ static int liteuart_remove(struct platform_device *pdev)
+@@ -293,6 +306,7 @@ static int liteuart_remove(struct platform_device *pdev)
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct liteuart_port *uart = to_liteuart_port(port);
+
++ uart_remove_one_port(&liteuart_driver, port);
+ xa_erase(&liteuart_array, uart->id);
+
+ return 0;
+diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
+index fcef7a961430b..489d19274f9ad 100644
+--- a/drivers/tty/serial/msm_serial.c
++++ b/drivers/tty/serial/msm_serial.c
+@@ -598,6 +598,9 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
+ u32 val;
+ int ret;
+
++ if (IS_ENABLED(CONFIG_CONSOLE_POLL))
++ return;
++
+ if (!dma->chan)
+ return;
+
+diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
+index 45e2e4109acd0..b6223fab0687d 100644
+--- a/drivers/tty/serial/serial-tegra.c
++++ b/drivers/tty/serial/serial-tegra.c
+@@ -1506,7 +1506,7 @@ static struct tegra_uart_chip_data tegra20_uart_chip_data = {
+ .fifo_mode_enable_status = false,
+ .uart_max_port = 5,
+ .max_dma_burst_bytes = 4,
+- .error_tolerance_low_range = 0,
++ .error_tolerance_low_range = -4,
+ .error_tolerance_high_range = 4,
+ };
+
+@@ -1517,7 +1517,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = {
+ .fifo_mode_enable_status = false,
+ .uart_max_port = 5,
+ .max_dma_burst_bytes = 4,
+- .error_tolerance_low_range = 0,
++ .error_tolerance_low_range = -4,
+ .error_tolerance_high_range = 4,
+ };
+
+diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
+index 0e2e35ab64c79..61e3dd0222af1 100644
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -222,7 +222,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
+ if (retval == 0) {
+ if (uart_console(uport) && uport->cons->cflag) {
+ tty->termios.c_cflag = uport->cons->cflag;
++ tty->termios.c_ispeed = uport->cons->ispeed;
++ tty->termios.c_ospeed = uport->cons->ospeed;
+ uport->cons->cflag = 0;
++ uport->cons->ispeed = 0;
++ uport->cons->ospeed = 0;
+ }
+ /*
+ * Initialise the hardware port settings.
+@@ -290,8 +294,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
+ /*
+ * Turn off DTR and RTS early.
+ */
+- if (uport && uart_console(uport) && tty)
++ if (uport && uart_console(uport) && tty) {
+ uport->cons->cflag = tty->termios.c_cflag;
++ uport->cons->ispeed = tty->termios.c_ispeed;
++ uport->cons->ospeed = tty->termios.c_ospeed;
++ }
+
+ if (!tty || C_HUPCL(tty))
+ uart_port_dtr_rts(uport, 0);
+@@ -1068,6 +1075,11 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
+ goto out;
+
+ if (!tty_io_error(tty)) {
++ if (uport->rs485.flags & SER_RS485_ENABLED) {
++ set &= ~TIOCM_RTS;
++ clear &= ~TIOCM_RTS;
++ }
++
+ uart_update_mctrl(uport, set, clear);
+ ret = 0;
+ }
+@@ -1542,6 +1554,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
+ {
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = uart_port_check(state);
++ char *buf;
+
+ /*
+ * At this point, we stop accepting input. To do this, we
+@@ -1563,8 +1576,18 @@ static void uart_tty_port_shutdown(struct tty_port *port)
+ */
+ tty_port_set_suspended(port, 0);
+
+- uart_change_pm(state, UART_PM_STATE_OFF);
++ /*
++ * Free the transmit buffer.
++ */
++ spin_lock_irq(&uport->lock);
++ buf = state->xmit.buf;
++ state->xmit.buf = NULL;
++ spin_unlock_irq(&uport->lock);
+
++ if (buf)
++ free_page((unsigned long)buf);
++
++ uart_change_pm(state, UART_PM_STATE_OFF);
+ }
+
+ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
+@@ -2094,8 +2117,11 @@ uart_set_options(struct uart_port *port, struct console *co,
+ * Allow the setting of the UART parameters with a NULL console
+ * too:
+ */
+- if (co)
++ if (co) {
+ co->cflag = termios.c_cflag;
++ co->ispeed = termios.c_ispeed;
++ co->ospeed = termios.c_ospeed;
++ }
+
+ return 0;
+ }
+@@ -2229,6 +2255,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
+ */
+ memset(&termios, 0, sizeof(struct ktermios));
+ termios.c_cflag = uport->cons->cflag;
++ termios.c_ispeed = uport->cons->ispeed;
++ termios.c_ospeed = uport->cons->ospeed;
+
+ /*
+ * If that's unset, use the tty termios setting.
+diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
+index 962e522ccc45c..d5e243908d9fd 100644
+--- a/drivers/tty/serial/xilinx_uartps.c
++++ b/drivers/tty/serial/xilinx_uartps.c
+@@ -601,9 +601,10 @@ static void cdns_uart_start_tx(struct uart_port *port)
+ if (uart_circ_empty(&port->state->xmit))
+ return;
+
++ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
++
+ cdns_uart_handle_tx(port);
+
+- writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
+ /* Enable the TX Empty interrupt */
+ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
+ }
+diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
+index 635d0af229b72..6c7e65b1d9a1c 100644
+--- a/drivers/tty/tty_buffer.c
++++ b/drivers/tty/tty_buffer.c
+@@ -544,6 +544,9 @@ static void flush_to_ldisc(struct work_struct *work)
+ if (!count)
+ break;
+ head->read += count;
++
++ if (need_resched())
++ cond_resched();
+ }
+
+ mutex_unlock(&buf->lock);
+diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
+index 1f3b4a1422126..f9af7ebe003d7 100644
+--- a/drivers/usb/cdns3/cdns3-gadget.c
++++ b/drivers/usb/cdns3/cdns3-gadget.c
+@@ -337,19 +337,6 @@ static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep)
+ cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs, priv_ep->num_trbs);
+ }
+
+-static void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
+-{
+- struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
+- int current_trb = priv_req->start_trb;
+-
+- while (current_trb != priv_req->end_trb) {
+- cdns3_ep_inc_deq(priv_ep);
+- current_trb = priv_ep->dequeue;
+- }
+-
+- cdns3_ep_inc_deq(priv_ep);
+-}
+-
+ /**
+ * cdns3_allow_enable_l1 - enable/disable permits to transition to L1.
+ * @priv_dev: Extended gadget object
+@@ -1517,10 +1504,11 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
+
+ trb = priv_ep->trb_pool + priv_ep->dequeue;
+
+- /* Request was dequeued and TRB was changed to TRB_LINK. */
+- if (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
++ /* The TRB was changed as link TRB, and the request was handled at ep_dequeue */
++ while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
+ trace_cdns3_complete_trb(priv_ep, trb);
+- cdns3_move_deq_to_next_trb(priv_req);
++ cdns3_ep_inc_deq(priv_ep);
++ trb = priv_ep->trb_pool + priv_ep->dequeue;
+ }
+
+ if (!request->stream_id) {
+diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
+index 27df0c6978978..e85bf768c66da 100644
+--- a/drivers/usb/cdns3/cdnsp-gadget.c
++++ b/drivers/usb/cdns3/cdnsp-gadget.c
+@@ -1541,15 +1541,27 @@ static int cdnsp_gadget_pullup(struct usb_gadget *gadget, int is_on)
+ {
+ struct cdnsp_device *pdev = gadget_to_cdnsp(gadget);
+ struct cdns *cdns = dev_get_drvdata(pdev->dev);
++ unsigned long flags;
+
+ trace_cdnsp_pullup(is_on);
+
++ /*
++ * Disable events handling while controller is being
++ * enabled/disabled.
++ */
++ disable_irq(cdns->dev_irq);
++ spin_lock_irqsave(&pdev->lock, flags);
++
+ if (!is_on) {
+ cdnsp_reset_device(pdev);
+ cdns_clear_vbus(cdns);
+ } else {
+ cdns_set_vbus(cdns);
+ }
++
++ spin_unlock_irqrestore(&pdev->lock, flags);
++ enable_irq(cdns->dev_irq);
++
+ return 0;
+ }
+
+diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
+index ad9aee3f1e398..97866bfb2da9d 100644
+--- a/drivers/usb/cdns3/cdnsp-mem.c
++++ b/drivers/usb/cdns3/cdnsp-mem.c
+@@ -987,6 +987,9 @@ int cdnsp_endpoint_init(struct cdnsp_device *pdev,
+
+ /* Set up the endpoint ring. */
+ pep->ring = cdnsp_ring_alloc(pdev, 2, ring_type, max_packet, mem_flags);
++ if (!pep->ring)
++ return -ENOMEM;
++
+ pep->skip = false;
+
+ /* Fill the endpoint context */
+diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c
+index 1b1438457fb04..e45c3d6e1536c 100644
+--- a/drivers/usb/cdns3/cdnsp-ring.c
++++ b/drivers/usb/cdns3/cdnsp-ring.c
+@@ -1029,6 +1029,8 @@ static void cdnsp_process_ctrl_td(struct cdnsp_device *pdev,
+ return;
+ }
+
++ *status = 0;
++
+ cdnsp_finish_td(pdev, td, event, pep, status);
+ }
+
+@@ -1523,7 +1525,14 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
+ spin_lock_irqsave(&pdev->lock, flags);
+
+ if (pdev->cdnsp_state & (CDNSP_STATE_HALTED | CDNSP_STATE_DYING)) {
+- cdnsp_died(pdev);
++ /*
++ * While removing or stopping driver there may still be deferred
++ * not handled interrupt which should not be treated as error.
++ * Driver should simply ignore it.
++ */
++ if (pdev->gadget_driver)
++ cdnsp_died(pdev);
++
+ spin_unlock_irqrestore(&pdev->lock, flags);
+ return IRQ_HANDLED;
+ }
+diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h
+index 6a2571c6aa9ed..5983dfb996537 100644
+--- a/drivers/usb/cdns3/cdnsp-trace.h
++++ b/drivers/usb/cdns3/cdnsp-trace.h
+@@ -57,9 +57,9 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep,
+ __entry->first_prime_det = pep->stream_info.first_prime_det;
+ __entry->drbls_count = pep->stream_info.drbls_count;
+ ),
+- TP_printk("%s: SID: %08x ep state: %x stream: enabled: %d num %d "
++ TP_printk("%s: SID: %08x, ep state: %x, stream: enabled: %d num %d "
+ "tds %d, first prime: %d drbls %d",
+- __get_str(name), __entry->state, __entry->stream_id,
++ __get_str(name), __entry->stream_id, __entry->state,
+ __entry->enabled, __entry->num_streams, __entry->td_count,
+ __entry->first_prime_det, __entry->drbls_count)
+ );
+diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
+index f1d100671ee6a..097142ffb1842 100644
+--- a/drivers/usb/chipidea/ci_hdrc_imx.c
++++ b/drivers/usb/chipidea/ci_hdrc_imx.c
+@@ -420,15 +420,15 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
+ data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0);
+ if (IS_ERR(data->phy)) {
+ ret = PTR_ERR(data->phy);
+- if (ret == -ENODEV) {
+- data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+- if (IS_ERR(data->phy)) {
+- ret = PTR_ERR(data->phy);
+- if (ret == -ENODEV)
+- data->phy = NULL;
+- else
+- goto err_clk;
+- }
++ if (ret != -ENODEV)
++ goto err_clk;
++ data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0);
++ if (IS_ERR(data->phy)) {
++ ret = PTR_ERR(data->phy);
++ if (ret == -ENODEV)
++ data->phy = NULL;
++ else
++ goto err_clk;
+ }
+ }
+
+diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
+index 2b18f5088ae4a..a56f06368d142 100644
+--- a/drivers/usb/chipidea/core.c
++++ b/drivers/usb/chipidea/core.c
+@@ -514,7 +514,7 @@ int hw_device_reset(struct ci_hdrc *ci)
+ return 0;
+ }
+
+-static irqreturn_t ci_irq(int irq, void *data)
++static irqreturn_t ci_irq_handler(int irq, void *data)
+ {
+ struct ci_hdrc *ci = data;
+ irqreturn_t ret = IRQ_NONE;
+@@ -567,6 +567,15 @@ static irqreturn_t ci_irq(int irq, void *data)
+ return ret;
+ }
+
++static void ci_irq(struct ci_hdrc *ci)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ci_irq_handler(ci->irq, ci);
++ local_irq_restore(flags);
++}
++
+ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+ {
+@@ -576,7 +585,7 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
+ cbl->connected = event;
+ cbl->changed = true;
+
+- ci_irq(ci->irq, ci);
++ ci_irq(ci);
+ return NOTIFY_DONE;
+ }
+
+@@ -617,7 +626,7 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
+ if (cable) {
+ cable->changed = true;
+ cable->connected = false;
+- ci_irq(ci->irq, ci);
++ ci_irq(ci);
+ spin_unlock_irqrestore(&ci->lock, flags);
+ if (ci->wq && role != USB_ROLE_NONE)
+ flush_workqueue(ci->wq);
+@@ -635,7 +644,7 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
+ if (cable) {
+ cable->changed = true;
+ cable->connected = true;
+- ci_irq(ci->irq, ci);
++ ci_irq(ci);
+ }
+ spin_unlock_irqrestore(&ci->lock, flags);
+ pm_runtime_put_sync(ci->dev);
+@@ -1174,7 +1183,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
+ }
+ }
+
+- ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
++ ret = devm_request_irq(dev, ci->irq, ci_irq_handler, IRQF_SHARED,
+ ci->platdata->name, ci);
+ if (ret)
+ goto stop;
+@@ -1295,11 +1304,11 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
+
+ if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+ (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
+- ci_irq(ci->irq, ci);
++ ci_irq(ci);
+
+ if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+ (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
+- ci_irq(ci->irq, ci);
++ ci_irq(ci);
+ }
+
+ static int ci_controller_resume(struct device *dev)
+diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
+index b199eb65f3780..00e28456e4cc2 100644
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -406,7 +406,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
+ * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0
+ * (see the end of section 5.6.3), so don't warn about them.
+ */
+- maxp = usb_endpoint_maxp(&endpoint->desc);
++ maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
+ if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
+ dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
+@@ -422,9 +422,9 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
+ maxpacket_maxes = full_speed_maxpacket_maxes;
+ break;
+ case USB_SPEED_HIGH:
+- /* Bits 12..11 are allowed only for HS periodic endpoints */
++ /* Multiple-transactions bits are allowed only for HS periodic endpoints */
+ if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
+- i = maxp & (BIT(12) | BIT(11));
++ i = maxp & USB_EP_MAXP_MULT_MASK;
+ maxp &= ~i;
+ }
+ fallthrough;
+diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
+index 9618ba622a2d0..fa66e6e587928 100644
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -32,6 +32,7 @@
+ #include <linux/usb.h>
+ #include <linux/usbdevice_fs.h>
+ #include <linux/usb/hcd.h> /* for usbcore internals */
++#include <linux/usb/quirks.h>
+ #include <linux/cdev.h>
+ #include <linux/notifier.h>
+ #include <linux/security.h>
+@@ -1102,14 +1103,55 @@ static int usbdev_release(struct inode *inode, struct file *file)
+ return 0;
+ }
+
++static void usbfs_blocking_completion(struct urb *urb)
++{
++ complete((struct completion *) urb->context);
++}
++
++/*
++ * Much like usb_start_wait_urb, but returns status separately from
++ * actual_length and uses a killable wait.
++ */
++static int usbfs_start_wait_urb(struct urb *urb, int timeout,
++ unsigned int *actlen)
++{
++ DECLARE_COMPLETION_ONSTACK(ctx);
++ unsigned long expire;
++ int rc;
++
++ urb->context = &ctx;
++ urb->complete = usbfs_blocking_completion;
++ *actlen = 0;
++ rc = usb_submit_urb(urb, GFP_KERNEL);
++ if (unlikely(rc))
++ return rc;
++
++ expire = (timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT);
++ rc = wait_for_completion_killable_timeout(&ctx, expire);
++ if (rc <= 0) {
++ usb_kill_urb(urb);
++ *actlen = urb->actual_length;
++ if (urb->status != -ENOENT)
++ ; /* Completed before it was killed */
++ else if (rc < 0)
++ return -EINTR;
++ else
++ return -ETIMEDOUT;
++ }
++ *actlen = urb->actual_length;
++ return urb->status;
++}
++
+ static int do_proc_control(struct usb_dev_state *ps,
+ struct usbdevfs_ctrltransfer *ctrl)
+ {
+ struct usb_device *dev = ps->dev;
+ unsigned int tmo;
+ unsigned char *tbuf;
+- unsigned wLength;
++ unsigned int wLength, actlen;
+ int i, pipe, ret;
++ struct urb *urb = NULL;
++ struct usb_ctrlrequest *dr = NULL;
+
+ ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest,
+ ctrl->wIndex);
+@@ -1122,51 +1164,63 @@ static int do_proc_control(struct usb_dev_state *ps,
+ sizeof(struct usb_ctrlrequest));
+ if (ret)
+ return ret;
++
++ ret = -ENOMEM;
+ tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+- if (!tbuf) {
+- ret = -ENOMEM;
++ if (!tbuf)
+ goto done;
+- }
++ urb = usb_alloc_urb(0, GFP_NOIO);
++ if (!urb)
++ goto done;
++ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
++ if (!dr)
++ goto done;
++
++ dr->bRequestType = ctrl->bRequestType;
++ dr->bRequest = ctrl->bRequest;
++ dr->wValue = cpu_to_le16(ctrl->wValue);
++ dr->wIndex = cpu_to_le16(ctrl->wIndex);
++ dr->wLength = cpu_to_le16(ctrl->wLength);
++
+ tmo = ctrl->timeout;
+ snoop(&dev->dev, "control urb: bRequestType=%02x "
+ "bRequest=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
+ ctrl->wIndex, ctrl->wLength);
+- if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength) {
++
++ if ((ctrl->bRequestType & USB_DIR_IN) && wLength) {
+ pipe = usb_rcvctrlpipe(dev, 0);
+- snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, NULL, 0);
++ usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
++ wLength, NULL, NULL);
++ snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, NULL, 0);
+
+ usb_unlock_device(dev);
+- i = usb_control_msg(dev, pipe, ctrl->bRequest,
+- ctrl->bRequestType, ctrl->wValue, ctrl->wIndex,
+- tbuf, ctrl->wLength, tmo);
++ i = usbfs_start_wait_urb(urb, tmo, &actlen);
+ usb_lock_device(dev);
+- snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
+- tbuf, max(i, 0));
+- if ((i > 0) && ctrl->wLength) {
+- if (copy_to_user(ctrl->data, tbuf, i)) {
++ snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, tbuf, actlen);
++ if (!i && actlen) {
++ if (copy_to_user(ctrl->data, tbuf, actlen)) {
+ ret = -EFAULT;
+- goto done;
++ goto recv_fault;
+ }
+ }
+ } else {
+- if (ctrl->wLength) {
+- if (copy_from_user(tbuf, ctrl->data, ctrl->wLength)) {
++ if (wLength) {
++ if (copy_from_user(tbuf, ctrl->data, wLength)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ pipe = usb_sndctrlpipe(dev, 0);
+- snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT,
+- tbuf, ctrl->wLength);
++ usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
++ wLength, NULL, NULL);
++ snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, tbuf, wLength);
+
+ usb_unlock_device(dev);
+- i = usb_control_msg(dev, pipe, ctrl->bRequest,
+- ctrl->bRequestType, ctrl->wValue, ctrl->wIndex,
+- tbuf, ctrl->wLength, tmo);
++ i = usbfs_start_wait_urb(urb, tmo, &actlen);
+ usb_lock_device(dev);
+- snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
++ snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, NULL, 0);
+ }
+ if (i < 0 && i != -EPIPE) {
+ dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
+@@ -1174,8 +1228,15 @@ static int do_proc_control(struct usb_dev_state *ps,
+ current->comm, ctrl->bRequestType, ctrl->bRequest,
+ ctrl->wLength, i);
+ }
+- ret = i;
++ ret = (i < 0 ? i : actlen);
++
++ recv_fault:
++ /* Linger a bit, prior to the next control message. */
++ if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
++ msleep(200);
+ done:
++ kfree(dr);
++ usb_free_urb(urb);
+ free_page((unsigned long) tbuf);
+ usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+ sizeof(struct usb_ctrlrequest));
+@@ -1195,10 +1256,11 @@ static int do_proc_bulk(struct usb_dev_state *ps,
+ struct usbdevfs_bulktransfer *bulk)
+ {
+ struct usb_device *dev = ps->dev;
+- unsigned int tmo, len1, pipe;
+- int len2;
++ unsigned int tmo, len1, len2, pipe;
+ unsigned char *tbuf;
+ int i, ret;
++ struct urb *urb = NULL;
++ struct usb_host_endpoint *ep;
+
+ ret = findintfep(ps->dev, bulk->ep);
+ if (ret < 0)
+@@ -1206,14 +1268,17 @@ static int do_proc_bulk(struct usb_dev_state *ps,
+ ret = checkintf(ps, ret);
+ if (ret)
+ return ret;
++
++ len1 = bulk->len;
++ if (len1 < 0 || len1 >= (INT_MAX - sizeof(struct urb)))
++ return -EINVAL;
++
+ if (bulk->ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f);
+- if (!usb_maxpacket(dev, pipe, !(bulk->ep & USB_DIR_IN)))
+- return -EINVAL;
+- len1 = bulk->len;
+- if (len1 >= (INT_MAX - sizeof(struct urb)))
++ ep = usb_pipe_endpoint(dev, pipe);
++ if (!ep || !usb_endpoint_maxp(&ep->desc))
+ return -EINVAL;
+ ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
+ if (ret)
+@@ -1223,17 +1288,29 @@ static int do_proc_bulk(struct usb_dev_state *ps,
+ * len1 can be almost arbitrarily large. Don't WARN if it's
+ * too big, just fail the request.
+ */
++ ret = -ENOMEM;
+ tbuf = kmalloc(len1, GFP_KERNEL | __GFP_NOWARN);
+- if (!tbuf) {
+- ret = -ENOMEM;
++ if (!tbuf)
++ goto done;
++ urb = usb_alloc_urb(0, GFP_KERNEL);
++ if (!urb)
+ goto done;
++
++ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_INT) {
++ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
++ usb_fill_int_urb(urb, dev, pipe, tbuf, len1,
++ NULL, NULL, ep->desc.bInterval);
++ } else {
++ usb_fill_bulk_urb(urb, dev, pipe, tbuf, len1, NULL, NULL);
+ }
++
+ tmo = bulk->timeout;
+ if (bulk->ep & 0x80) {
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
+
+ usb_unlock_device(dev);
+- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
++ i = usbfs_start_wait_urb(urb, tmo, &len2);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
+
+@@ -1253,12 +1330,13 @@ static int do_proc_bulk(struct usb_dev_state *ps,
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
+
+ usb_unlock_device(dev);
+- i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
++ i = usbfs_start_wait_urb(urb, tmo, &len2);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
+ }
+ ret = (i < 0 ? i : len2);
+ done:
++ usb_free_urb(urb);
+ kfree(tbuf);
+ usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
+ return ret;
+diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
+index 7ee6e4cc0d89e..00d35fe1fef0b 100644
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -2795,7 +2795,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
+ {
+ int retval;
+ struct usb_device *rhdev;
+- struct usb_hcd *shared_hcd;
+
+ if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
+ hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
+@@ -2956,26 +2955,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
+ goto err_hcd_driver_start;
+ }
+
+- /* starting here, usbcore will pay attention to the shared HCD roothub */
+- shared_hcd = hcd->shared_hcd;
+- if (!usb_hcd_is_primary_hcd(hcd) && shared_hcd && HCD_DEFER_RH_REGISTER(shared_hcd)) {
+- retval = register_root_hub(shared_hcd);
+- if (retval != 0)
+- goto err_register_root_hub;
+-
+- if (shared_hcd->uses_new_polling && HCD_POLL_RH(shared_hcd))
+- usb_hcd_poll_rh_status(shared_hcd);
+- }
+-
+ /* starting here, usbcore will pay attention to this root hub */
+- if (!HCD_DEFER_RH_REGISTER(hcd)) {
+- retval = register_root_hub(hcd);
+- if (retval != 0)
+- goto err_register_root_hub;
++ retval = register_root_hub(hcd);
++ if (retval != 0)
++ goto err_register_root_hub;
+
+- if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
+- usb_hcd_poll_rh_status(hcd);
+- }
++ if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
++ usb_hcd_poll_rh_status(hcd);
+
+ return retval;
+
+@@ -3013,7 +2999,6 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
+ void usb_remove_hcd(struct usb_hcd *hcd)
+ {
+ struct usb_device *rhdev = hcd->self.root_hub;
+- bool rh_registered;
+
+ dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
+
+@@ -3024,7 +3009,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
+
+ dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
+ spin_lock_irq (&hcd_root_hub_lock);
+- rh_registered = hcd->rh_registered;
+ hcd->rh_registered = 0;
+ spin_unlock_irq (&hcd_root_hub_lock);
+
+@@ -3034,8 +3018,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
+ cancel_work_sync(&hcd->died_work);
+
+ mutex_lock(&usb_bus_idr_lock);
+- if (rh_registered)
+- usb_disconnect(&rhdev); /* Sets rhdev to NULL */
++ usb_disconnect(&rhdev); /* Sets rhdev to NULL */
+ mutex_unlock(&usb_bus_idr_lock);
+
+ /*
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 86658a81d2844..00070a8a65079 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4700,8 +4700,6 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
+ if (oldspeed == USB_SPEED_LOW)
+ delay = HUB_LONG_RESET_TIME;
+
+- mutex_lock(hcd->address0_mutex);
+-
+ /* Reset the device; full speed may morph to high speed */
+ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
+ retval = hub_port_reset(hub, port1, udev, delay, false);
+@@ -5016,7 +5014,6 @@ fail:
+ hub_port_disable(hub, port1, 0);
+ update_devnum(udev, devnum); /* for disconnect processing */
+ }
+- mutex_unlock(hcd->address0_mutex);
+ return retval;
+ }
+
+@@ -5191,6 +5188,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ static int unreliable_port = -1;
++ bool retry_locked;
+
+ /* Disconnect any existing devices under this port */
+ if (udev) {
+@@ -5246,8 +5244,11 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
+ unit_load = 100;
+
+ status = 0;
+- for (i = 0; i < PORT_INIT_TRIES; i++) {
+
++ for (i = 0; i < PORT_INIT_TRIES; i++) {
++ usb_lock_port(port_dev);
++ mutex_lock(hcd->address0_mutex);
++ retry_locked = true;
+ /* reallocate for each attempt, since references
+ * to the previous one can escape in various ways
+ */
+@@ -5255,6 +5256,8 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
+ if (!udev) {
+ dev_err(&port_dev->dev,
+ "couldn't allocate usb_device\n");
++ mutex_unlock(hcd->address0_mutex);
++ usb_unlock_port(port_dev);
+ goto done;
+ }
+
+@@ -5276,12 +5279,14 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
+ }
+
+ /* reset (non-USB 3.0 devices) and get descriptor */
+- usb_lock_port(port_dev);
+ status = hub_port_init(hub, udev, port1, i);
+- usb_unlock_port(port_dev);
+ if (status < 0)
+ goto loop;
+
++ mutex_unlock(hcd->address0_mutex);
++ usb_unlock_port(port_dev);
++ retry_locked = false;
++
+ if (udev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(2000);
+
+@@ -5374,6 +5379,10 @@ loop:
+ usb_ep0_reinit(udev);
+ release_devnum(udev);
+ hub_free_dev(udev);
++ if (retry_locked) {
++ mutex_unlock(hcd->address0_mutex);
++ usb_unlock_port(port_dev);
++ }
+ usb_put_dev(udev);
+ if ((status == -ENOTCONN) || (status == -ENOTSUPP))
+ break;
+@@ -5915,6 +5924,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
+ bos = udev->bos;
+ udev->bos = NULL;
+
++ mutex_lock(hcd->address0_mutex);
++
+ for (i = 0; i < PORT_INIT_TRIES; ++i) {
+
+ /* ep0 maxpacket size may change; let the HCD know about it.
+@@ -5924,6 +5935,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
+ if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
+ break;
+ }
++ mutex_unlock(hcd->address0_mutex);
+
+ if (ret < 0)
+ goto re_enumerate;
+diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
+index 8239fe7129dd7..d3c14b5ed4a1f 100644
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -434,6 +434,12 @@ static const struct usb_device_id usb_quirk_list[] = {
+ { USB_DEVICE(0x1532, 0x0116), .driver_info =
+ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+
++ /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
++ { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
++
++ /* Lenovo Powered USB-C Travel Hub (4X90S92381, RTL8153 GigE) */
++ { USB_DEVICE(0x17ef, 0x721e), .driver_info = USB_QUIRK_NO_LPM },
++
+ /* Lenovo ThinkCenter A630Z TI024Gen3 usb-audio */
+ { USB_DEVICE(0x17ef, 0xa012), .driver_info =
+ USB_QUIRK_DISCONNECT_SUSPEND },
+diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c
+index 2d4176f5788eb..aa6eb76f64ddc 100644
+--- a/drivers/usb/dwc2/drd.c
++++ b/drivers/usb/dwc2/drd.c
+@@ -7,6 +7,7 @@
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>
+ */
+
++#include <linux/clk.h>
+ #include <linux/iopoll.h>
+ #include <linux/platform_device.h>
+ #include <linux/usb/role.h>
+@@ -25,9 +26,9 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
+ gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
+ dwc2_writel(hsotg, gotgctl, GOTGCTL);
+
+- dwc2_force_mode(hsotg, false);
+-
+ spin_unlock_irqrestore(&hsotg->lock, flags);
++
++ dwc2_force_mode(hsotg, (hsotg->dr_mode == USB_DR_MODE_HOST));
+ }
+
+ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid)
+@@ -39,6 +40,7 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid)
+ (!valid && !(gotgctl & GOTGCTL_ASESVLD)))
+ return -EALREADY;
+
++ gotgctl &= ~GOTGCTL_BVALOVAL;
+ if (valid)
+ gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
+ else
+@@ -57,6 +59,7 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid)
+ (!valid && !(gotgctl & GOTGCTL_BSESVLD)))
+ return -EALREADY;
+
++ gotgctl &= ~GOTGCTL_AVALOVAL;
+ if (valid)
+ gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
+ else
+@@ -86,6 +89,20 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
+ }
+ #endif
+
++ /*
++ * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of
++ * the probe and enabled on udc_start.
++ * If role-switch set is called before the udc_start, we need to enable
++ * the clock to read/write GOTGCTL and GUSBCFG registers to override
++ * mode and sessions. It is the case if cable is plugged at boot.
++ */
++ if (!hsotg->ll_hw_enabled && hsotg->clk) {
++ int ret = clk_prepare_enable(hsotg->clk);
++
++ if (ret)
++ return ret;
++ }
++
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ if (role == USB_ROLE_HOST) {
+@@ -110,6 +127,9 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
+ /* This will raise a Connector ID Status Change Interrupt */
+ dwc2_force_mode(hsotg, role == USB_ROLE_HOST);
+
++ if (!hsotg->ll_hw_enabled && hsotg->clk)
++ clk_disable_unprepare(hsotg->clk);
++
+ dev_dbg(hsotg->dev, "%s-session valid\n",
+ role == USB_ROLE_NONE ? "No" :
+ role == USB_ROLE_HOST ? "A" : "B");
+diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
+index 11d85a6e0b0dc..2190225bf3da2 100644
+--- a/drivers/usb/dwc2/gadget.c
++++ b/drivers/usb/dwc2/gadget.c
+@@ -1198,6 +1198,8 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
+ }
+ ctrl |= DXEPCTL_CNAK;
+ } else {
++ hs_req->req.frame_number = hs_ep->target_frame;
++ hs_req->req.actual = 0;
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA);
+ return;
+ }
+@@ -2857,9 +2859,12 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
+
+ do {
+ hs_req = get_ep_head(hs_ep);
+- if (hs_req)
++ if (hs_req) {
++ hs_req->req.frame_number = hs_ep->target_frame;
++ hs_req->req.actual = 0;
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
+ -ENODATA);
++ }
+ dwc2_gadget_incr_frame_num(hs_ep);
+ /* Update current frame number value. */
+ hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg);
+@@ -2912,8 +2917,11 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
+
+ while (dwc2_gadget_target_frame_elapsed(ep)) {
+ hs_req = get_ep_head(ep);
+- if (hs_req)
++ if (hs_req) {
++ hs_req->req.frame_number = ep->target_frame;
++ hs_req->req.actual = 0;
+ dwc2_hsotg_complete_request(hsotg, ep, hs_req, -ENODATA);
++ }
+
+ dwc2_gadget_incr_frame_num(ep);
+ /* Update current frame number value. */
+@@ -3002,8 +3010,11 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
+
+ while (dwc2_gadget_target_frame_elapsed(hs_ep)) {
+ hs_req = get_ep_head(hs_ep);
+- if (hs_req)
++ if (hs_req) {
++ hs_req->req.frame_number = hs_ep->target_frame;
++ hs_req->req.actual = 0;
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA);
++ }
+
+ dwc2_gadget_incr_frame_num(hs_ep);
+ /* Update current frame number value. */
+diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
+index 89a788326c562..24beff610cf2c 100644
+--- a/drivers/usb/dwc2/hcd_queue.c
++++ b/drivers/usb/dwc2/hcd_queue.c
+@@ -59,7 +59,7 @@
+ #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
+
+ /* If we get a NAK, wait this long before retrying */
+-#define DWC2_RETRY_WAIT_DELAY (1 * 1E6L)
++#define DWC2_RETRY_WAIT_DELAY (1 * NSEC_PER_MSEC)
+
+ /**
+ * dwc2_periodic_channel_available() - Checks that a channel is available for a
+diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
+index c8f18f3ba9e35..c331a5128c2c0 100644
+--- a/drivers/usb/dwc2/platform.c
++++ b/drivers/usb/dwc2/platform.c
+@@ -575,6 +575,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(hsotg, ggpio, GGPIO);
++
++ /* ID/VBUS detection startup time */
++ usleep_range(5000, 7000);
+ }
+
+ retval = dwc2_drd_init(hsotg);
+diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
+index 0104a80b185e1..357b7805896e7 100644
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1565,9 +1565,11 @@ static int dwc3_probe(struct platform_device *pdev)
+
+ dwc3_get_properties(dwc);
+
+- ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
+- if (ret)
+- return ret;
++ if (!dwc->sysdev_is_parent) {
++ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
++ if (ret)
++ return ret;
++ }
+
+ dwc->reset = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(dwc->reset))
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+index 5612bfdf37da9..fd5d42ec53501 100644
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -143,7 +143,7 @@
+ #define DWC3_GHWPARAMS8 0xc600
+ #define DWC3_GUCTL3 0xc60c
+ #define DWC3_GFLADJ 0xc630
+-#define DWC3_GHWPARAMS9 0xc680
++#define DWC3_GHWPARAMS9 0xc6e0
+
+ /* Device Registers */
+ #define DWC3_DCFG 0xc700
+@@ -723,6 +723,7 @@ struct dwc3_ep {
+ #define DWC3_EP_FORCE_RESTART_STREAM BIT(9)
+ #define DWC3_EP_FIRST_STREAM_PRIMED BIT(10)
+ #define DWC3_EP_PENDING_CLEAR_STALL BIT(11)
++#define DWC3_EP_TXFIFO_RESIZED BIT(12)
+
+ /* This last one is specific to EP0 */
+ #define DWC3_EP0_DIR_IN BIT(31)
+diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
+index 9abbd01028c5f..3cb01cdd02c29 100644
+--- a/drivers/usb/dwc3/dwc3-qcom.c
++++ b/drivers/usb/dwc3/dwc3-qcom.c
+@@ -649,7 +649,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node, *dwc3_np;
+ struct device *dev = &pdev->dev;
+- struct property *prop;
+ int ret;
+
+ dwc3_np = of_get_compatible_child(np, "snps,dwc3");
+@@ -658,20 +657,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
+- prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+- if (!prop) {
+- ret = -ENOMEM;
+- dev_err(dev, "unable to allocate memory for property\n");
+- goto node_put;
+- }
+-
+- prop->name = "tx-fifo-resize";
+- ret = of_add_property(dwc3_np, prop);
+- if (ret) {
+- dev_err(dev, "unable to add property\n");
+- goto node_put;
+- }
+-
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "failed to register dwc3 core - %d\n", ret);
+diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
+index 4519d06c9ca2b..4c16805a2b310 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -310,13 +310,24 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
+ if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
+ int link_state;
+
++ /*
++ * Initiate remote wakeup if the link state is in U3 when
++ * operating in SS/SSP or L1/L2 when operating in HS/FS. If the
++ * link state is in U1/U2, no remote wakeup is needed. The Start
++ * Transfer command will initiate the link recovery.
++ */
+ link_state = dwc3_gadget_get_link_state(dwc);
+- if (link_state == DWC3_LINK_STATE_U1 ||
+- link_state == DWC3_LINK_STATE_U2 ||
+- link_state == DWC3_LINK_STATE_U3) {
++ switch (link_state) {
++ case DWC3_LINK_STATE_U2:
++ if (dwc->gadget->speed >= USB_SPEED_SUPER)
++ break;
++
++ fallthrough;
++ case DWC3_LINK_STATE_U3:
+ ret = __dwc3_gadget_wakeup(dwc);
+ dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
+ ret);
++ break;
+ }
+ }
+
+@@ -702,6 +713,7 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)
+ DWC31_GTXFIFOSIZ_TXFRAMNUM;
+
+ dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size);
++ dep->flags &= ~DWC3_EP_TXFIFO_RESIZED;
+ }
+ dwc->num_ep_resized = 0;
+ }
+@@ -747,6 +759,10 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
+ if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1)
+ return 0;
+
++ /* bail if already resized */
++ if (dep->flags & DWC3_EP_TXFIFO_RESIZED)
++ return 0;
++
+ ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+
+ if ((dep->endpoint.maxburst > 1 &&
+@@ -807,6 +823,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
+ }
+
+ dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size);
++ dep->flags |= DWC3_EP_TXFIFO_RESIZED;
+ dwc->num_ep_resized++;
+
+ return 0;
+@@ -995,7 +1012,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+
+ dep->stream_capable = false;
+ dep->type = 0;
+- dep->flags = 0;
++ dep->flags &= DWC3_EP_TXFIFO_RESIZED;
+
+ return 0;
+ }
+@@ -3246,6 +3263,9 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
+ struct dwc3 *dwc = dep->dwc;
+ bool no_started_trb = true;
+
++ if (!dep->endpoint.desc)
++ return no_started_trb;
++
+ dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
+
+ if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
+@@ -3293,6 +3313,9 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
+ {
+ int status = 0;
+
++ if (!dep->endpoint.desc)
++ return;
++
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dwc3_gadget_endpoint_frame_from_event(dep, event);
+
+@@ -3346,6 +3369,14 @@ static void dwc3_gadget_endpoint_command_complete(struct dwc3_ep *dep,
+ if (cmd != DWC3_DEPCMD_ENDTRANSFER)
+ return;
+
++ /*
++ * The END_TRANSFER command will cause the controller to generate a
++ * NoStream Event, and it's not due to the host DP NoStream rejection.
++ * Ignore the next NoStream event.
++ */
++ if (dep->stream_capable)
++ dep->flags |= DWC3_EP_IGNORE_NEXT_NOSTREAM;
++
+ dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
+ dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+ dwc3_gadget_ep_cleanup_cancelled_requests(dep);
+@@ -3568,14 +3599,6 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
+ WARN_ON_ONCE(ret);
+ dep->resource_index = 0;
+
+- /*
+- * The END_TRANSFER command will cause the controller to generate a
+- * NoStream Event, and it's not due to the host DP NoStream rejection.
+- * Ignore the next NoStream event.
+- */
+- if (dep->stream_capable)
+- dep->flags |= DWC3_EP_IGNORE_NEXT_NOSTREAM;
+-
+ if (!interrupt)
+ dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+ else
+diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
+index be4ecbabdd586..6c0434100e38c 100644
+--- a/drivers/usb/early/xhci-dbc.c
++++ b/drivers/usb/early/xhci-dbc.c
+@@ -14,7 +14,6 @@
+ #include <linux/pci_ids.h>
+ #include <linux/memblock.h>
+ #include <linux/io.h>
+-#include <linux/iopoll.h>
+ #include <asm/pci-direct.h>
+ #include <asm/fixmap.h>
+ #include <linux/bcd.h>
+@@ -136,9 +135,17 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, int wait, int delay)
+ {
+ u32 result;
+
+- return readl_poll_timeout_atomic(ptr, result,
+- ((result & mask) == done),
+- delay, wait);
++ /* Can not use readl_poll_timeout_atomic() for early boot things */
++ do {
++ result = readl(ptr);
++ result &= mask;
++ if (result == done)
++ return 0;
++ udelay(delay);
++ wait -= delay;
++ } while (wait > 0);
++
++ return -ETIMEDOUT;
+ }
+
+ static void __init xdbc_bios_handoff(void)
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+index 504c1cbc255d1..3789c329183ca 100644
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -1679,6 +1679,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+ struct usb_function *f = NULL;
+ u8 endp;
+
++ if (w_length > USB_COMP_EP0_BUFSIZ) {
++ if (ctrl->bRequestType & USB_DIR_IN) {
++ /* Cast away the const, we are going to overwrite on purpose. */
++ __le16 *temp = (__le16 *)&ctrl->wLength;
++
++ *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
++ w_length = USB_COMP_EP0_BUFSIZ;
++ } else {
++ goto done;
++ }
++ }
++
+ /* partial re-init of the response message; the function or the
+ * gadget might need to intercept e.g. a control-OUT completion
+ * when we delegate to it.
+@@ -2209,7 +2221,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite,
+ if (!cdev->req)
+ return -ENOMEM;
+
+- cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
++ cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+ if (!cdev->req->buf)
+ goto fail;
+
+diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
+index 85a3f6d4b5af3..d15a54f6c24b9 100644
+--- a/drivers/usb/gadget/function/u_ether.c
++++ b/drivers/usb/gadget/function/u_ether.c
+@@ -17,6 +17,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/ethtool.h>
+ #include <linux/if_vlan.h>
++#include <linux/etherdevice.h>
+
+ #include "u_ether.h"
+
+@@ -861,19 +862,23 @@ int gether_register_netdev(struct net_device *net)
+ {
+ struct eth_dev *dev;
+ struct usb_gadget *g;
+- struct sockaddr sa;
+ int status;
+
+ if (!net->dev.parent)
+ return -EINVAL;
+ dev = netdev_priv(net);
+ g = dev->gadget;
++
++ net->addr_assign_type = NET_ADDR_RANDOM;
++ eth_hw_addr_set(net, dev->dev_mac);
++
+ status = register_netdev(net);
+ if (status < 0) {
+ dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
+ return status;
+ } else {
+ INFO(dev, "HOST MAC %pM\n", dev->host_mac);
++ INFO(dev, "MAC %pM\n", dev->dev_mac);
+
+ /* two kinds of host-initiated state changes:
+ * - iff DATA transfer is active, carrier is "on"
+@@ -881,15 +886,6 @@ int gether_register_netdev(struct net_device *net)
+ */
+ netif_carrier_off(net);
+ }
+- sa.sa_family = net->type;
+- memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN);
+- rtnl_lock();
+- status = dev_set_mac_address(net, &sa, NULL);
+- rtnl_unlock();
+- if (status)
+- pr_warn("cannot set self ethernet address: %d\n", status);
+- else
+- INFO(dev, "MAC %pM\n", dev->dev_mac);
+
+ return status;
+ }
+diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
+index 255a61bd6a6a8..9d5f17b551bbd 100644
+--- a/drivers/usb/gadget/function/uvc.h
++++ b/drivers/usb/gadget/function/uvc.h
+@@ -126,6 +126,7 @@ struct uvc_device {
+ enum uvc_state state;
+ struct usb_function func;
+ struct uvc_video video;
++ bool func_connected;
+
+ /* Descriptors */
+ struct {
+@@ -156,6 +157,7 @@ static inline struct uvc_device *to_uvc(struct usb_function *f)
+ struct uvc_file_handle {
+ struct v4l2_fh vfh;
+ struct uvc_video *device;
++ bool is_uvc_app_handle;
+ };
+
+ #define to_uvc_file_handle(handle) \
+diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
+index 4ca89eab61590..197c26f7aec63 100644
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -227,17 +227,55 @@ static int
+ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+ {
++ struct uvc_device *uvc = video_get_drvdata(fh->vdev);
++ struct uvc_file_handle *handle = to_uvc_file_handle(fh);
++ int ret;
++
+ if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
+ return -EINVAL;
+
+- return v4l2_event_subscribe(fh, sub, 2, NULL);
++ if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
++ return -EBUSY;
++
++ ret = v4l2_event_subscribe(fh, sub, 2, NULL);
++ if (ret < 0)
++ return ret;
++
++ if (sub->type == UVC_EVENT_SETUP) {
++ uvc->func_connected = true;
++ handle->is_uvc_app_handle = true;
++ uvc_function_connect(uvc);
++ }
++
++ return 0;
++}
++
++static void uvc_v4l2_disable(struct uvc_device *uvc)
++{
++ uvc->func_connected = false;
++ uvc_function_disconnect(uvc);
++ uvcg_video_enable(&uvc->video, 0);
++ uvcg_free_buffers(&uvc->video.queue);
+ }
+
+ static int
+ uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+ {
+- return v4l2_event_unsubscribe(fh, sub);
++ struct uvc_device *uvc = video_get_drvdata(fh->vdev);
++ struct uvc_file_handle *handle = to_uvc_file_handle(fh);
++ int ret;
++
++ ret = v4l2_event_unsubscribe(fh, sub);
++ if (ret < 0)
++ return ret;
++
++ if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) {
++ uvc_v4l2_disable(uvc);
++ handle->is_uvc_app_handle = false;
++ }
++
++ return 0;
+ }
+
+ static long
+@@ -292,7 +330,6 @@ uvc_v4l2_open(struct file *file)
+ handle->device = &uvc->video;
+ file->private_data = &handle->vfh;
+
+- uvc_function_connect(uvc);
+ return 0;
+ }
+
+@@ -304,11 +341,9 @@ uvc_v4l2_release(struct file *file)
+ struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
+ struct uvc_video *video = handle->device;
+
+- uvc_function_disconnect(uvc);
+-
+ mutex_lock(&video->mutex);
+- uvcg_video_enable(video, 0);
+- uvcg_free_buffers(&video->queue);
++ if (handle->is_uvc_app_handle)
++ uvc_v4l2_disable(uvc);
+ mutex_unlock(&video->mutex);
+
+ file->private_data = NULL;
+diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c
+index e1d566c9918ae..6bcbad3825802 100644
+--- a/drivers/usb/gadget/legacy/dbgp.c
++++ b/drivers/usb/gadget/legacy/dbgp.c
+@@ -137,7 +137,7 @@ static int dbgp_enable_ep_req(struct usb_ep *ep)
+ goto fail_1;
+ }
+
+- req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
++ req->buf = kzalloc(DBGP_REQ_LEN, GFP_KERNEL);
+ if (!req->buf) {
+ err = -ENOMEM;
+ stp = 2;
+@@ -345,6 +345,19 @@ static int dbgp_setup(struct usb_gadget *gadget,
+ void *data = NULL;
+ u16 len = 0;
+
++ if (length > DBGP_REQ_LEN) {
++ if (ctrl->bRequestType & USB_DIR_IN) {
++ /* Cast away the const, we are going to overwrite on purpose. */
++ __le16 *temp = (__le16 *)&ctrl->wLength;
++
++ *temp = cpu_to_le16(DBGP_REQ_LEN);
++ length = DBGP_REQ_LEN;
++ } else {
++ return err;
++ }
++ }
++
++
+ if (request == USB_REQ_GET_DESCRIPTOR) {
+ switch (value>>8) {
+ case USB_DT_DEVICE:
+diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
+index 5b27d289443fe..3912cc805f3af 100644
+--- a/drivers/usb/gadget/legacy/hid.c
++++ b/drivers/usb/gadget/legacy/hid.c
+@@ -99,8 +99,10 @@ static int do_config(struct usb_configuration *c)
+
+ list_for_each_entry(e, &hidg_func_list, node) {
+ e->f = usb_get_function(e->fi);
+- if (IS_ERR(e->f))
++ if (IS_ERR(e->f)) {
++ status = PTR_ERR(e->f);
+ goto put;
++ }
+ status = usb_add_function(c, e->f);
+ if (status < 0) {
+ usb_put_function(e->f);
+diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
+index 539220d7f5b62..1b223cba4c2c9 100644
+--- a/drivers/usb/gadget/legacy/inode.c
++++ b/drivers/usb/gadget/legacy/inode.c
+@@ -110,6 +110,8 @@ enum ep0_state {
+ /* enough for the whole queue: most events invalidate others */
+ #define N_EVENT 5
+
++#define RBUF_SIZE 256
++
+ struct dev_data {
+ spinlock_t lock;
+ refcount_t count;
+@@ -144,7 +146,7 @@ struct dev_data {
+ struct dentry *dentry;
+
+ /* except this scratch i/o buffer for ep0 */
+- u8 rbuf [256];
++ u8 rbuf[RBUF_SIZE];
+ };
+
+ static inline void get_dev (struct dev_data *data)
+@@ -1334,6 +1336,18 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
++ if (w_length > RBUF_SIZE) {
++ if (ctrl->bRequestType & USB_DIR_IN) {
++ /* Cast away the const, we are going to overwrite on purpose. */
++ __le16 *temp = (__le16 *)&ctrl->wLength;
++
++ *temp = cpu_to_le16(RBUF_SIZE);
++ w_length = RBUF_SIZE;
++ } else {
++ return value;
++ }
++ }
++
+ spin_lock (&dev->lock);
+ dev->setup_abort = 0;
+ if (dev->state == STATE_DEV_UNCONNECTED) {
+diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
+index 8c614bb86c665..69394dc1cdfb6 100644
+--- a/drivers/usb/gadget/udc/Kconfig
++++ b/drivers/usb/gadget/udc/Kconfig
+@@ -330,6 +330,7 @@ config USB_AMD5536UDC
+ config USB_FSL_QE
+ tristate "Freescale QE/CPM USB Device Controller"
+ depends on FSL_SOC && (QUICC_ENGINE || CPM)
++ depends on !64BIT || BROKEN
+ help
+ Some of Freescale PowerPC processors have a Full Speed
+ QE/CPM2 USB controller, which support device mode with 4
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index 1776c05d0a486..1440803216297 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -635,7 +635,16 @@ static int ehci_run (struct usb_hcd *hcd)
+ /* Wait until HC become operational */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ msleep(5);
+- rc = ehci_handshake(ehci, &ehci->regs->status, STS_HALT, 0, 100 * 1000);
++
++ /* For Aspeed, STS_HALT also depends on ASS/PSS status.
++ * Check CMD_RUN instead.
++ */
++ if (ehci->is_aspeed)
++ rc = ehci_handshake(ehci, &ehci->regs->command, CMD_RUN,
++ 1, 100 * 1000);
++ else
++ rc = ehci_handshake(ehci, &ehci->regs->status, STS_HALT,
++ 0, 100 * 1000);
+
+ up_write(&ehci_cf_port_reset_rwsem);
+
+diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
+index c70f2d0b4aaf0..c3dc906274d93 100644
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -297,6 +297,12 @@ static int ehci_platform_probe(struct platform_device *dev)
+ "has-transaction-translator"))
+ hcd->has_tt = 1;
+
++ if (of_device_is_compatible(dev->dev.of_node,
++ "aspeed,ast2500-ehci") ||
++ of_device_is_compatible(dev->dev.of_node,
++ "aspeed,ast2600-ehci"))
++ ehci->is_aspeed = 1;
++
+ if (soc_device_match(quirk_poll_match))
+ priv->quirk_poll = true;
+
+diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
+index 80bb823aa9fe8..fdd073cc053b8 100644
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */
+ unsigned need_oc_pp_cycle:1; /* MPC834X port power */
+ unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
+ unsigned spurious_oc:1;
++ unsigned is_aspeed:1;
+
+ /* required for usb32 quirk */
+ #define OHCI_CTRL_HCFS (3 << 6)
+diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
+index 59cc1bc7f12f5..30de85a707fef 100644
+--- a/drivers/usb/host/max3421-hcd.c
++++ b/drivers/usb/host/max3421-hcd.c
+@@ -125,8 +125,6 @@ struct max3421_hcd {
+
+ struct task_struct *spi_thread;
+
+- struct max3421_hcd *next;
+-
+ enum max3421_rh_state rh_state;
+ /* lower 16 bits contain port status, upper 16 bits the change mask: */
+ u32 port_status;
+@@ -174,8 +172,6 @@ struct max3421_ep {
+ u8 retransmit; /* packet needs retransmission */
+ };
+
+-static struct max3421_hcd *max3421_hcd_list;
+-
+ #define MAX3421_FIFO_SIZE 64
+
+ #define MAX3421_SPI_DIR_RD 0 /* read register from MAX3421 */
+@@ -1882,9 +1878,8 @@ max3421_probe(struct spi_device *spi)
+ }
+ set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ max3421_hcd = hcd_to_max3421(hcd);
+- max3421_hcd->next = max3421_hcd_list;
+- max3421_hcd_list = max3421_hcd;
+ INIT_LIST_HEAD(&max3421_hcd->ep_list);
++ spi_set_drvdata(spi, max3421_hcd);
+
+ max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL);
+ if (!max3421_hcd->tx)
+@@ -1934,28 +1929,18 @@ error:
+ static int
+ max3421_remove(struct spi_device *spi)
+ {
+- struct max3421_hcd *max3421_hcd = NULL, **prev;
+- struct usb_hcd *hcd = NULL;
++ struct max3421_hcd *max3421_hcd;
++ struct usb_hcd *hcd;
+ unsigned long flags;
+
+- for (prev = &max3421_hcd_list; *prev; prev = &(*prev)->next) {
+- max3421_hcd = *prev;
+- hcd = max3421_to_hcd(max3421_hcd);
+- if (hcd->self.controller == &spi->dev)
+- break;
+- }
+- if (!max3421_hcd) {
+- dev_err(&spi->dev, "no MAX3421 HCD found for SPI device %p\n",
+- spi);
+- return -ENODEV;
+- }
++ max3421_hcd = spi_get_drvdata(spi);
++ hcd = max3421_to_hcd(max3421_hcd);
+
+ usb_remove_hcd(hcd);
+
+ spin_lock_irqsave(&max3421_hcd->lock, flags);
+
+ kthread_stop(max3421_hcd->spi_thread);
+- *prev = max3421_hcd->next;
+
+ spin_unlock_irqrestore(&max3421_hcd->lock, flags);
+
+diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
+index 08ec2ab0d95a5..3f3d62dc06746 100644
+--- a/drivers/usb/host/ohci-tmio.c
++++ b/drivers/usb/host/ohci-tmio.c
+@@ -199,7 +199,7 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
+ if (usb_disabled())
+ return -ENODEV;
+
+- if (!cell)
++ if (!cell || !regs || !config || !sram)
+ return -EINVAL;
+
+ if (irq < 0)
+diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
+index a3f875eea7519..df3522dab31b5 100644
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -257,7 +257,6 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
+ {
+ u16 temp;
+
+- desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+@@ -292,6 +291,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
+ desc->bDescriptorType = USB_DT_HUB;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
++ desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.8 says 20ms */
+
+ /* The Device Removable bits are reported on a byte granularity.
+ * If the port doesn't exist within that byte, the bit is set to 0.
+@@ -344,6 +344,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
+ xhci_common_hub_descriptor(xhci, desc, ports);
+ desc->bDescriptorType = USB_DT_SS_HUB;
+ desc->bDescLength = USB_DT_SS_HUB_SIZE;
++ desc->bPwrOn2PwrGood = 50; /* usb 3.1 may fail if less than 100ms */
+
+ /* header decode latency should be zero for roothubs,
+ * see section 4.23.5.2.
+@@ -716,6 +717,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
+ continue;
+
+ retval = xhci_disable_slot(xhci, i);
++ xhci_free_virt_device(xhci, i);
+ if (retval)
+ xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
+ i, retval);
+diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
+index 134f4789bd897..b4c84b3635074 100644
+--- a/drivers/usb/host/xhci-mtk-sch.c
++++ b/drivers/usb/host/xhci-mtk-sch.c
+@@ -781,7 +781,7 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+
+ ret = xhci_check_bandwidth(hcd, udev);
+ if (!ret)
+- INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
++ list_del_init(&mtk->bw_ep_chk_list);
+
+ return ret;
+ }
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index 2484a9d38ce2b..8c04a7d73388b 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -65,6 +65,15 @@
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_1 0x161a
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_2 0x161b
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_3 0x161d
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_4 0x161e
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_5 0x15d6
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_6 0x15d7
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_7 0x161c
++#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_8 0x161f
++
+ #define PCI_DEVICE_ID_ASMEDIA_1042_XHCI 0x1042
+ #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
+ #define PCI_DEVICE_ID_ASMEDIA_1142_XHCI 0x1242
+@@ -317,6 +326,17 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+ pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4))
+ xhci->quirks |= XHCI_NO_SOFT_RETRY;
+
++ if (pdev->vendor == PCI_VENDOR_ID_AMD &&
++ (pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_1 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_2 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_3 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_4 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_5 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_6 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_7 ||
++ pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_8))
++ xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
++
+ if (xhci->quirks & XHCI_RESET_ON_RESUME)
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "QUIRK: Resetting on resume");
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 311597bba80e2..d0b6806275e01 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -366,7 +366,9 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
+ /* Must be called with xhci->lock held, releases and aquires lock back */
+ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
+ {
+- u32 temp_32;
++ struct xhci_segment *new_seg = xhci->cmd_ring->deq_seg;
++ union xhci_trb *new_deq = xhci->cmd_ring->dequeue;
++ u64 crcr;
+ int ret;
+
+ xhci_dbg(xhci, "Abort command ring\n");
+@@ -375,13 +377,18 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
+
+ /*
+ * The control bits like command stop, abort are located in lower
+- * dword of the command ring control register. Limit the write
+- * to the lower dword to avoid corrupting the command ring pointer
+- * in case if the command ring is stopped by the time upper dword
+- * is written.
++ * dword of the command ring control register.
++ * Some controllers require all 64 bits to be written to abort the ring.
++ * Make sure the upper dword is valid, pointing to the next command,
++ * avoiding corrupting the command ring pointer in case the command ring
++ * is stopped by the time the upper dword is written.
+ */
+- temp_32 = readl(&xhci->op_regs->cmd_ring);
+- writel(temp_32 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
++ next_trb(xhci, NULL, &new_seg, &new_deq);
++ if (trb_is_link(new_deq))
++ next_trb(xhci, NULL, &new_seg, &new_deq);
++
++ crcr = xhci_trb_virt_to_dma(new_seg, new_deq);
++ xhci_write_64(xhci, crcr | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
+
+ /* Section 4.6.1.2 of xHCI 1.0 spec says software should also time the
+ * completion of the Command Abort operation. If CRR is not negated in 5
+@@ -1518,7 +1525,6 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
+ if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
+ /* Delete default control endpoint resources */
+ xhci_free_device_endpoint_resources(xhci, virt_dev, true);
+- xhci_free_virt_device(xhci, slot_id);
+ }
+
+ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
+diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
+index 1bf494b649bd2..c8af2cd2216d6 100644
+--- a/drivers/usb/host/xhci-tegra.c
++++ b/drivers/usb/host/xhci-tegra.c
+@@ -1400,6 +1400,7 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
+
+ static int tegra_xusb_probe(struct platform_device *pdev)
+ {
++ struct of_phandle_args args;
+ struct tegra_xusb *tegra;
+ struct device_node *np;
+ struct resource *regs;
+@@ -1454,10 +1455,17 @@ static int tegra_xusb_probe(struct platform_device *pdev)
+ goto put_padctl;
+ }
+
+- tegra->padctl_irq = of_irq_get(np, 0);
+- if (tegra->padctl_irq <= 0) {
+- err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq;
+- goto put_padctl;
++ /* Older device-trees don't have padctrl interrupt */
++ err = of_irq_parse_one(np, 0, &args);
++ if (!err) {
++ tegra->padctl_irq = of_irq_get(np, 0);
++ if (tegra->padctl_irq <= 0) {
++ err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq;
++ goto put_padctl;
++ }
++ } else {
++ dev_dbg(&pdev->dev,
++ "%pOF is missing an interrupt, disabling PM support\n", np);
+ }
+
+ tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
+@@ -1696,11 +1704,15 @@ static int tegra_xusb_probe(struct platform_device *pdev)
+ goto remove_usb3;
+ }
+
+- err = devm_request_threaded_irq(&pdev->dev, tegra->padctl_irq, NULL, tegra_xusb_padctl_irq,
+- IRQF_ONESHOT, dev_name(&pdev->dev), tegra);
+- if (err < 0) {
+- dev_err(&pdev->dev, "failed to request padctl IRQ: %d\n", err);
+- goto remove_usb3;
++ if (tegra->padctl_irq) {
++ err = devm_request_threaded_irq(&pdev->dev, tegra->padctl_irq,
++ NULL, tegra_xusb_padctl_irq,
++ IRQF_ONESHOT, dev_name(&pdev->dev),
++ tegra);
++ if (err < 0) {
++ dev_err(&pdev->dev, "failed to request padctl IRQ: %d\n", err);
++ goto remove_usb3;
++ }
+ }
+
+ err = tegra_xusb_enable_firmware_messages(tegra);
+@@ -1718,13 +1730,16 @@ static int tegra_xusb_probe(struct platform_device *pdev)
+ /* Enable wake for both USB 2.0 and USB 3.0 roothubs */
+ device_init_wakeup(&tegra->hcd->self.root_hub->dev, true);
+ device_init_wakeup(&xhci->shared_hcd->self.root_hub->dev, true);
+- device_init_wakeup(tegra->dev, true);
+
+ pm_runtime_use_autosuspend(tegra->dev);
+ pm_runtime_set_autosuspend_delay(tegra->dev, 2000);
+ pm_runtime_mark_last_busy(tegra->dev);
+ pm_runtime_set_active(tegra->dev);
+- pm_runtime_enable(tegra->dev);
++
++ if (tegra->padctl_irq) {
++ device_init_wakeup(tegra->dev, true);
++ pm_runtime_enable(tegra->dev);
++ }
+
+ return 0;
+
+@@ -1772,7 +1787,9 @@ static int tegra_xusb_remove(struct platform_device *pdev)
+ dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
+ tegra->fw.phys);
+
+- pm_runtime_disable(&pdev->dev);
++ if (tegra->padctl_irq)
++ pm_runtime_disable(&pdev->dev);
++
+ pm_runtime_put(&pdev->dev);
+
+ tegra_xusb_powergate_partitions(tegra);
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 541fe4dcc43a2..f5b1bcc875ded 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -692,7 +692,6 @@ int xhci_run(struct usb_hcd *hcd)
+ if (ret)
+ xhci_free_command(xhci, command);
+ }
+- set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Finished xhci_run for USB2 roothub");
+
+@@ -3935,7 +3934,6 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+ struct xhci_slot_ctx *slot_ctx;
+ int i, ret;
+
+-#ifndef CONFIG_USB_DEFAULT_PERSIST
+ /*
+ * We called pm_runtime_get_noresume when the device was attached.
+ * Decrement the counter here to allow controller to runtime suspend
+@@ -3943,7 +3941,6 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+ */
+ if (xhci->quirks & XHCI_RESET_ON_RESUME)
+ pm_runtime_put_noidle(hcd->self.controller);
+-#endif
+
+ ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
+ /* If the host is halted due to driver unload, we still need to free the
+@@ -3962,9 +3959,8 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+ del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
+ }
+ virt_dev->udev = NULL;
+- ret = xhci_disable_slot(xhci, udev->slot_id);
+- if (ret)
+- xhci_free_virt_device(xhci, udev->slot_id);
++ xhci_disable_slot(xhci, udev->slot_id);
++ xhci_free_virt_device(xhci, udev->slot_id);
+ }
+
+ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
+@@ -3974,7 +3970,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
+ u32 state;
+ int ret = 0;
+
+- command = xhci_alloc_command(xhci, false, GFP_KERNEL);
++ command = xhci_alloc_command(xhci, true, GFP_KERNEL);
+ if (!command)
+ return -ENOMEM;
+
+@@ -3999,6 +3995,15 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
+ }
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
++
++ wait_for_completion(command->completion);
++
++ if (command->status != COMP_SUCCESS)
++ xhci_warn(xhci, "Unsuccessful disable slot %u command, status %d\n",
++ slot_id, command->status);
++
++ xhci_free_command(xhci, command);
++
+ return ret;
+ }
+
+@@ -4095,23 +4100,20 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+
+ xhci_debugfs_create_slot(xhci, slot_id);
+
+-#ifndef CONFIG_USB_DEFAULT_PERSIST
+ /*
+ * If resetting upon resume, we can't put the controller into runtime
+ * suspend if there is a device attached.
+ */
+ if (xhci->quirks & XHCI_RESET_ON_RESUME)
+ pm_runtime_get_noresume(hcd->self.controller);
+-#endif
+
+ /* Is this a LS or FS device under a HS hub? */
+ /* Hub or peripherial? */
+ return 1;
+
+ disable_slot:
+- ret = xhci_disable_slot(xhci, udev->slot_id);
+- if (ret)
+- xhci_free_virt_device(xhci, udev->slot_id);
++ xhci_disable_slot(xhci, udev->slot_id);
++ xhci_free_virt_device(xhci, udev->slot_id);
+
+ return 0;
+ }
+@@ -4241,6 +4243,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
+
+ mutex_unlock(&xhci->mutex);
+ ret = xhci_disable_slot(xhci, udev->slot_id);
++ xhci_free_virt_device(xhci, udev->slot_id);
+ if (!ret)
+ xhci_alloc_dev(hcd, udev);
+ kfree(command->completion);
+diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
+index efbd317f2f252..988a8c02e7e24 100644
+--- a/drivers/usb/misc/iowarrior.c
++++ b/drivers/usb/misc/iowarrior.c
+@@ -99,10 +99,6 @@ struct iowarrior {
+ /* globals */
+ /*--------------*/
+
+-/*
+- * USB spec identifies 5 second timeouts.
+- */
+-#define GET_TIMEOUT 5
+ #define USB_REQ_GET_REPORT 0x01
+ //#if 0
+ static int usb_get_report(struct usb_device *dev,
+@@ -114,7 +110,7 @@ static int usb_get_report(struct usb_device *dev,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, (type << 8) + id,
+ inter->desc.bInterfaceNumber, buf, size,
+- GET_TIMEOUT*HZ);
++ USB_CTRL_GET_TIMEOUT);
+ }
+ //#endif
+
+@@ -129,7 +125,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id,
+ intf->cur_altsetting->desc.bInterfaceNumber, buf,
+- size, HZ);
++ size, 1000);
+ }
+
+ /*---------------------*/
+diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
+index 8de143807c1ae..4d61df6a9b5c8 100644
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -120,7 +120,7 @@ config USB_MUSB_MEDIATEK
+ tristate "MediaTek platforms"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on NOP_USB_XCEIV
+- depends on GENERIC_PHY
++ select GENERIC_PHY
+ select USB_ROLE_SWITCH
+
+ comment "MUSB DMA mode"
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index 98c0f4c1bffd9..51274b87f46c9 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1247,9 +1247,11 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
+ status = musb_queue_resume_work(musb,
+ musb_ep_restart_resume_work,
+ request);
+- if (status < 0)
++ if (status < 0) {
+ dev_err(musb->controller, "%s resume work: %i\n",
+ __func__, status);
++ list_del(&request->list);
++ }
+ }
+
+ unlock:
+diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
+index c968ecda42aa8..7ed4cc348d993 100644
+--- a/drivers/usb/musb/tusb6010.c
++++ b/drivers/usb/musb/tusb6010.c
+@@ -1104,6 +1104,11 @@ static int tusb_musb_init(struct musb *musb)
+
+ /* dma address for async dma */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem) {
++ pr_debug("no async dma resource?\n");
++ ret = -ENODEV;
++ goto done;
++ }
+ musb->async = mem->start;
+
+ /* dma address for sync dma */
+diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
+index 189279869a8b0..22e62c01c0aa8 100644
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -1682,6 +1682,8 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
+
+ /* 2 banks of GPIO - One for the pins taken from each serial port */
+ if (intf_num == 0) {
++ priv->gc.ngpio = 2;
++
+ if (mode.eci == CP210X_PIN_MODE_MODEM) {
+ /* mark all GPIOs of this interface as reserved */
+ priv->gpio_altfunc = 0xff;
+@@ -1692,8 +1694,9 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
+ priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
+ CP210X_ECI_GPIO_MODE_MASK) >>
+ CP210X_ECI_GPIO_MODE_OFFSET);
+- priv->gc.ngpio = 2;
+ } else if (intf_num == 1) {
++ priv->gc.ngpio = 3;
++
+ if (mode.sci == CP210X_PIN_MODE_MODEM) {
+ /* mark all GPIOs of this interface as reserved */
+ priv->gpio_altfunc = 0xff;
+@@ -1704,7 +1707,6 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
+ priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
+ CP210X_SCI_GPIO_MODE_MASK) >>
+ CP210X_SCI_GPIO_MODE_OFFSET);
+- priv->gc.ngpio = 3;
+ } else {
+ return -ENODEV;
+ }
+diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
+index 87b89c99d5177..1cfcd805f2868 100644
+--- a/drivers/usb/serial/keyspan.c
++++ b/drivers/usb/serial/keyspan.c
+@@ -2890,22 +2890,22 @@ static int keyspan_port_probe(struct usb_serial_port *port)
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
+ p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
+ if (!p_priv->in_buffer[i])
+- goto err_in_buffer;
++ goto err_free_in_buffer;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
+ p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->out_buffer[i])
+- goto err_out_buffer;
++ goto err_free_out_buffer;
+ }
+
+ p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
+ if (!p_priv->inack_buffer)
+- goto err_inack_buffer;
++ goto err_free_out_buffer;
+
+ p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->outcont_buffer)
+- goto err_outcont_buffer;
++ goto err_free_inack_buffer;
+
+ p_priv->device_details = d_details;
+
+@@ -2951,15 +2951,14 @@ static int keyspan_port_probe(struct usb_serial_port *port)
+
+ return 0;
+
+-err_outcont_buffer:
++err_free_inack_buffer:
+ kfree(p_priv->inack_buffer);
+-err_inack_buffer:
++err_free_out_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+ kfree(p_priv->out_buffer[i]);
+-err_out_buffer:
++err_free_in_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+ kfree(p_priv->in_buffer[i]);
+-err_in_buffer:
+ kfree(p_priv);
+
+ return -ENOMEM;
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index a484ff5e4ebf8..42420bfc983c2 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -1219,6 +1219,14 @@ static const struct usb_device_id option_ids[] = {
+ .driver_info = NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1063, 0xff), /* Telit LN920 (ECM) */
+ .driver_info = NCTRL(0) | RSVD(1) },
++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff), /* Telit FN990 (rmnet) */
++ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff), /* Telit FN990 (MBIM) */
++ .driver_info = NCTRL(0) | RSVD(1) },
++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff), /* Telit FN990 (RNDIS) */
++ .driver_info = NCTRL(2) | RSVD(3) },
++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990 (ECM) */
++ .driver_info = NCTRL(0) | RSVD(1) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
+@@ -1267,6 +1275,8 @@ static const struct usb_device_id option_ids[] = {
+ .driver_info = NCTRL(2) },
+ { USB_DEVICE(TELIT_VENDOR_ID, 0x9010), /* Telit SBL FN980 flashing device */
+ .driver_info = NCTRL(0) | ZLP },
++ { USB_DEVICE(TELIT_VENDOR_ID, 0x9200), /* Telit LE910S1 flashing device */
++ .driver_info = NCTRL(0) | ZLP },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
+ .driver_info = RSVD(1) },
+@@ -2094,6 +2104,9 @@ static const struct usb_device_id option_ids[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
++ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a2, 0xff) }, /* Fibocom FM101-GL (laptop MBIM) */
++ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a4, 0xff), /* Fibocom FM101-GL (laptop MBIM) */
++ .driver_info = RSVD(4) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
+diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
+index f45ca7ddf78ea..a70fd86f735ca 100644
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -432,6 +432,7 @@ static int pl2303_detect_type(struct usb_serial *serial)
+ case 0x200:
+ switch (bcdDevice) {
+ case 0x100:
++ case 0x105:
+ case 0x305:
+ case 0x405:
+ /*
+diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
+index c6b3fcf901805..29191d33c0e3e 100644
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -406,6 +406,16 @@ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110,
+ "785EPX Storage",
+ USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_SINGLE_LUN),
+
++/*
++ * Reported by James Buren <braewoods+lkml@braewoods.net>
++ * Virtual ISOs cannot be remounted if ejected while the device is locked
++ * Disable locking to mimic Windows behavior that bypasses the issue
++ */
++UNUSUAL_DEV( 0x04c5, 0x2028, 0x0001, 0x0001,
++ "iODD",
++ "2531/2541",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE),
++
+ /*
+ * Not sure who reported this originally but
+ * Pavel Machek <pavel@ucw.cz> reported that the extra US_FL_SINGLE_LUN
+diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
+index a0418f23b4aae..ab480f38523aa 100644
+--- a/drivers/usb/typec/Kconfig
++++ b/drivers/usb/typec/Kconfig
+@@ -65,9 +65,9 @@ config TYPEC_HD3SS3220
+
+ config TYPEC_STUSB160X
+ tristate "STMicroelectronics STUSB160x Type-C controller driver"
+- depends on I2C
+- depends on REGMAP_I2C
+ depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
++ depends on I2C
++ select REGMAP_I2C
+ help
+ Say Y or M here if your system has STMicroelectronics STUSB160x
+ Type-C port controller.
+diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
+index 7a2a17866a823..72f9001b07921 100644
+--- a/drivers/usb/typec/tcpm/fusb302.c
++++ b/drivers/usb/typec/tcpm/fusb302.c
+@@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
+ ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
+ FUSB_REG_MASK_BC_LVL |
+ FUSB_REG_MASK_COMP_CHNG,
+- FUSB_REG_MASK_COMP_CHNG);
++ FUSB_REG_MASK_BC_LVL);
+ if (ret < 0) {
+ fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
+ ret);
+ goto done;
+ }
+ chip->intr_comp_chng = true;
++ chip->intr_bc_lvl = false;
+ break;
+ case TYPEC_CC_RD:
+ ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
+ FUSB_REG_MASK_BC_LVL |
+ FUSB_REG_MASK_COMP_CHNG,
+- FUSB_REG_MASK_BC_LVL);
++ FUSB_REG_MASK_COMP_CHNG);
+ if (ret < 0) {
+ fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
+ ret);
+ goto done;
+ }
+ chip->intr_bc_lvl = true;
++ chip->intr_comp_chng = false;
+ break;
+ default:
+ break;
+diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
+index 7f2f3ff1b3911..59d4fa2443f2b 100644
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -324,6 +324,7 @@ struct tcpm_port {
+
+ bool attached;
+ bool connected;
++ bool registered;
+ bool pd_supported;
+ enum typec_port_type port_type;
+
+@@ -4110,11 +4111,7 @@ static void run_state_machine(struct tcpm_port *port)
+ tcpm_try_src(port) ? SRC_TRY
+ : SNK_ATTACHED,
+ 0);
+- else
+- /* Wait for VBUS, but not forever */
+- tcpm_set_state(port, PORT_RESET, PD_T_PS_SOURCE_ON);
+ break;
+-
+ case SRC_TRY:
+ port->try_src_count++;
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+@@ -6295,7 +6292,8 @@ static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer)
+ {
+ struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer);
+
+- kthread_queue_work(port->wq, &port->state_machine);
++ if (port->registered)
++ kthread_queue_work(port->wq, &port->state_machine);
+ return HRTIMER_NORESTART;
+ }
+
+@@ -6303,7 +6301,8 @@ static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *time
+ {
+ struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer);
+
+- kthread_queue_work(port->wq, &port->vdm_state_machine);
++ if (port->registered)
++ kthread_queue_work(port->wq, &port->vdm_state_machine);
+ return HRTIMER_NORESTART;
+ }
+
+@@ -6311,7 +6310,8 @@ static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer)
+ {
+ struct tcpm_port *port = container_of(timer, struct tcpm_port, enable_frs_timer);
+
+- kthread_queue_work(port->wq, &port->enable_frs);
++ if (port->registered)
++ kthread_queue_work(port->wq, &port->enable_frs);
+ return HRTIMER_NORESTART;
+ }
+
+@@ -6319,7 +6319,8 @@ static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer)
+ {
+ struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer);
+
+- kthread_queue_work(port->wq, &port->send_discover_work);
++ if (port->registered)
++ kthread_queue_work(port->wq, &port->send_discover_work);
+ return HRTIMER_NORESTART;
+ }
+
+@@ -6407,6 +6408,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
+ typec_port_register_altmodes(port->typec_port,
+ &tcpm_altmode_ops, port,
+ port->port_altmode, ALTMODE_DISCOVERY_MAX);
++ port->registered = true;
+
+ mutex_lock(&port->lock);
+ tcpm_init(port);
+@@ -6428,6 +6430,9 @@ void tcpm_unregister_port(struct tcpm_port *port)
+ {
+ int i;
+
++ port->registered = false;
++ kthread_destroy_worker(port->wq);
++
+ hrtimer_cancel(&port->send_discover_timer);
+ hrtimer_cancel(&port->enable_frs_timer);
+ hrtimer_cancel(&port->vdm_state_machine_timer);
+@@ -6439,7 +6444,6 @@ void tcpm_unregister_port(struct tcpm_port *port)
+ typec_unregister_port(port->typec_port);
+ usb_role_switch_put(port->role_sw);
+ tcpm_debugfs_exit(port);
+- kthread_destroy_worker(port->wq);
+ }
+ EXPORT_SYMBOL_GPL(tcpm_unregister_port);
+
+diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
+index ea4cc0a6e40cc..97f50f301f13b 100644
+--- a/drivers/usb/typec/tipd/core.c
++++ b/drivers/usb/typec/tipd/core.c
+@@ -117,7 +117,7 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
+ u8 data[TPS_MAX_LEN + 1];
+ int ret;
+
+- if (WARN_ON(len + 1 > sizeof(data)))
++ if (len + 1 > sizeof(data))
+ return -EINVAL;
+
+ if (!tps->i2c_protocol)
+diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+index bd56de7484dcb..ae85d2dd6eb76 100644
+--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+@@ -2192,7 +2192,6 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev)
+ clear_vqs_ready(ndev);
+ mlx5_vdpa_destroy_mr(&ndev->mvdev);
+ ndev->mvdev.status = 0;
+- ndev->mvdev.mlx_features = 0;
+ memset(ndev->event_cbs, 0, sizeof(ndev->event_cbs));
+ ndev->mvdev.actual_features = 0;
+ ++mvdev->generation;
+diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
+index 1dc121a07a934..12bf3d16a40ff 100644
+--- a/drivers/vdpa/vdpa.c
++++ b/drivers/vdpa/vdpa.c
+@@ -353,7 +353,8 @@ static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *m
+ goto msg_err;
+
+ while (mdev->id_table[i].device) {
+- supported_classes |= BIT(mdev->id_table[i].device);
++ if (mdev->id_table[i].device <= 63)
++ supported_classes |= BIT_ULL(mdev->id_table[i].device);
+ i++;
+ }
+
+diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
+index 5f484fff8dbec..41b0cd17fcbac 100644
+--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
++++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
+@@ -591,8 +591,11 @@ static void vdpasim_free(struct vdpa_device *vdpa)
+ vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov);
+ }
+
+- put_iova_domain(&vdpasim->iova);
+- iova_cache_put();
++ if (vdpa_get_dma_dev(vdpa)) {
++ put_iova_domain(&vdpasim->iova);
++ iova_cache_put();
++ }
++
+ kvfree(vdpasim->buffer);
+ if (vdpasim->iommu)
+ vhost_iotlb_free(vdpasim->iommu);
+diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
+index 841667a896dd0..8c3de5a76282a 100644
+--- a/drivers/vdpa/vdpa_user/vduse_dev.c
++++ b/drivers/vdpa/vdpa_user/vduse_dev.c
+@@ -655,7 +655,8 @@ static void vduse_vdpa_get_config(struct vdpa_device *vdpa, unsigned int offset,
+ {
+ struct vduse_dev *dev = vdpa_to_vduse(vdpa);
+
+- if (len > dev->config_size - offset)
++ if (offset > dev->config_size ||
++ len > dev->config_size - offset)
+ return;
+
+ memcpy(buf, dev->config + offset, len);
+@@ -975,7 +976,8 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd,
+ break;
+
+ ret = -EINVAL;
+- if (config.length == 0 ||
++ if (config.offset > dev->config_size ||
++ config.length == 0 ||
+ config.length > dev->config_size - config.offset)
+ break;
+
+diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
+index 39039e0461175..d62f05d056b7b 100644
+--- a/drivers/vhost/vdpa.c
++++ b/drivers/vhost/vdpa.c
+@@ -197,7 +197,7 @@ static int vhost_vdpa_config_validate(struct vhost_vdpa *v,
+ struct vdpa_device *vdpa = v->vdpa;
+ long size = vdpa->config->get_config_size(vdpa);
+
+- if (c->len == 0)
++ if (c->len == 0 || c->off > size)
+ return -EINVAL;
+
+ if (c->len > size - c->off)
+diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
+index 938aefbc75ecc..4e3b95af7ee4d 100644
+--- a/drivers/vhost/vsock.c
++++ b/drivers/vhost/vsock.c
+@@ -554,7 +554,7 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
+ virtio_transport_free_pkt(pkt);
+
+ len += sizeof(pkt->hdr);
+- vhost_add_used(vq, head, len);
++ vhost_add_used(vq, head, 0);
+ total_len += len;
+ added = true;
+ } while(likely(!vhost_exceeds_weight(vq, ++pkts, total_len)));
+diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
+index 537fe1b376ad7..fc990e576340b 100644
+--- a/drivers/video/backlight/backlight.c
++++ b/drivers/video/backlight/backlight.c
+@@ -688,12 +688,6 @@ static struct backlight_device *of_find_backlight(struct device *dev)
+ of_node_put(np);
+ if (!bd)
+ return ERR_PTR(-EPROBE_DEFER);
+- /*
+- * Note: gpio_backlight uses brightness as
+- * power state during probe
+- */
+- if (!bd->props.brightness)
+- bd->props.brightness = bd->props.max_brightness;
+ }
+ }
+
+diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
+index 1b451165311c9..40496e9e9b438 100644
+--- a/drivers/video/console/sticon.c
++++ b/drivers/video/console/sticon.c
+@@ -332,13 +332,13 @@ static u8 sticon_build_attr(struct vc_data *conp, u8 color,
+ bool blink, bool underline, bool reverse,
+ bool italic)
+ {
+- u8 attr = ((color & 0x70) >> 1) | ((color & 7));
++ u8 fg = color & 7;
++ u8 bg = (color & 0x70) >> 4;
+
+- if (reverse) {
+- color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
+- }
+-
+- return attr;
++ if (reverse)
++ return (fg << 3) | bg;
++ else
++ return (bg << 3) | fg;
+ }
+
+ static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
+diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
+index ef9c57ce09066..9a49ea6b5112f 100644
+--- a/drivers/video/console/vgacon.c
++++ b/drivers/video/console/vgacon.c
+@@ -366,11 +366,17 @@ static void vgacon_init(struct vc_data *c, int init)
+ struct uni_pagedir *p;
+
+ /*
+- * We cannot be loaded as a module, therefore init is always 1,
+- * but vgacon_init can be called more than once, and init will
+- * not be 1.
++ * We cannot be loaded as a module, therefore init will be 1
++ * if we are the default console, however if we are a fallback
++ * console, for example if fbcon has failed registration, then
++ * init will be 0, so we need to make sure our boot parameters
++ * have been copied to the console structure for vgacon_resize
++ * ultimately called by vc_resize. Any subsequent calls to
++ * vgacon_init init will have init set to 0 too.
+ */
+ c->vc_can_do_color = vga_can_do_color;
++ c->vc_scan_lines = vga_scan_lines;
++ c->vc_font.height = c->vc_cell_height = vga_video_font_height;
+
+ /* set dimensions manually if init != 0 since vc_resize() will fail */
+ if (init) {
+@@ -379,8 +385,6 @@ static void vgacon_init(struct vc_data *c, int init)
+ } else
+ vc_resize(c, vga_video_num_columns, vga_video_num_lines);
+
+- c->vc_scan_lines = vga_scan_lines;
+- c->vc_font.height = c->vc_cell_height = vga_video_font_height;
+ c->vc_complement_mask = 0x7700;
+ if (vga_512_chars)
+ c->vc_hi_font_mask = 0x0800;
+diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
+index 998067b701fa0..393894af26f84 100644
+--- a/drivers/video/fbdev/chipsfb.c
++++ b/drivers/video/fbdev/chipsfb.c
+@@ -331,7 +331,7 @@ static const struct fb_var_screeninfo chipsfb_var = {
+
+ static void init_chips(struct fb_info *p, unsigned long addr)
+ {
+- memset(p->screen_base, 0, 0x100000);
++ fb_memset(p->screen_base, 0, 0x100000);
+
+ p->fix = chipsfb_fix;
+ p->fix.smem_start = addr;
+diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
+index 8ea8f079cde26..ea42ba6445b2d 100644
+--- a/drivers/video/fbdev/efifb.c
++++ b/drivers/video/fbdev/efifb.c
+@@ -47,6 +47,8 @@ static bool use_bgrt = true;
+ static bool request_mem_succeeded = false;
+ static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
+
++static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */
++
+ static struct fb_var_screeninfo efifb_defined = {
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+@@ -243,6 +245,9 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
+
+ static void efifb_destroy(struct fb_info *info)
+ {
++ if (efifb_pci_dev)
++ pm_runtime_put(&efifb_pci_dev->dev);
++
+ if (info->screen_base) {
+ if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+ iounmap(info->screen_base);
+@@ -333,7 +338,6 @@ ATTRIBUTE_GROUPS(efifb);
+
+ static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */
+
+-static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */
+ static struct resource *bar_resource;
+ static u64 bar_offset;
+
+@@ -347,6 +351,17 @@ static int efifb_probe(struct platform_device *dev)
+ char *option = NULL;
+ efi_memory_desc_t md;
+
++ /*
++ * Generic drivers must not be registered if a framebuffer exists.
++ * If a native driver was probed, the display hardware was already
++ * taken and attempting to use the system framebuffer is dangerous.
++ */
++ if (num_registered_fb > 0) {
++ dev_err(&dev->dev,
++ "efifb: a framebuffer is already registered\n");
++ return -EINVAL;
++ }
++
+ if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
+ return -ENODEV;
+
+@@ -569,17 +584,22 @@ static int efifb_probe(struct platform_device *dev)
+ pr_err("efifb: cannot allocate colormap\n");
+ goto err_groups;
+ }
++
++ if (efifb_pci_dev)
++ WARN_ON(pm_runtime_get_sync(&efifb_pci_dev->dev) < 0);
++
+ err = register_framebuffer(info);
+ if (err < 0) {
+ pr_err("efifb: cannot register framebuffer\n");
+- goto err_fb_dealoc;
++ goto err_put_rpm_ref;
+ }
+ fb_info(info, "%s frame buffer device\n", info->fix.id);
+- if (efifb_pci_dev)
+- pm_runtime_get_sync(&efifb_pci_dev->dev);
+ return 0;
+
+-err_fb_dealoc:
++err_put_rpm_ref:
++ if (efifb_pci_dev)
++ pm_runtime_put(&efifb_pci_dev->dev);
++
+ fb_dealloc_cmap(&info->cmap);
+ err_groups:
+ sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
+@@ -603,8 +623,6 @@ static int efifb_remove(struct platform_device *pdev)
+ unregister_framebuffer(info);
+ sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
+ framebuffer_release(info);
+- if (efifb_pci_dev)
+- pm_runtime_put(&efifb_pci_dev->dev);
+
+ return 0;
+ }
+diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
+index 62f0ded706815..b63074fd892e5 100644
+--- a/drivers/video/fbdev/simplefb.c
++++ b/drivers/video/fbdev/simplefb.c
+@@ -407,6 +407,17 @@ static int simplefb_probe(struct platform_device *pdev)
+ struct simplefb_par *par;
+ struct resource *mem;
+
++ /*
++ * Generic drivers must not be registered if a framebuffer exists.
++ * If a native driver was probed, the display hardware was already
++ * taken and attempting to use the system framebuffer is dangerous.
++ */
++ if (num_registered_fb > 0) {
++ dev_err(&pdev->dev,
++ "simplefb: a framebuffer is already registered\n");
++ return -EINVAL;
++ }
++
+ if (fb_get_options("simplefb", NULL))
+ return -ENODEV;
+
+diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
+index 3035bb6f54585..9919407973cd5 100644
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -268,7 +268,7 @@ size_t virtio_max_dma_size(struct virtio_device *vdev)
+ size_t max_segment_size = SIZE_MAX;
+
+ if (vring_use_dma_api(vdev))
+- max_segment_size = dma_max_mapping_size(&vdev->dev);
++ max_segment_size = dma_max_mapping_size(vdev->dev.parent);
+
+ return max_segment_size;
+ }
+@@ -1065,6 +1065,8 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
+
+ head = vq->packed.next_avail_idx;
+ desc = alloc_indirect_packed(total_sg, gfp);
++ if (!desc)
++ return -ENOMEM;
+
+ if (unlikely(vq->vq.num_free < 1)) {
+ pr_debug("Can't add buf len 1 - avail = 0\n");
+@@ -1176,6 +1178,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
+ unsigned int i, n, c, descs_used, err_idx;
+ __le16 head_flags, flags;
+ u16 head, id, prev, curr, avail_used_flags;
++ int err;
+
+ START_USE(vq);
+
+@@ -1191,9 +1194,14 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
+
+ BUG_ON(total_sg == 0);
+
+- if (virtqueue_use_indirect(_vq, total_sg))
+- return virtqueue_add_indirect_packed(vq, sgs, total_sg,
+- out_sgs, in_sgs, data, gfp);
++ if (virtqueue_use_indirect(_vq, total_sg)) {
++ err = virtqueue_add_indirect_packed(vq, sgs, total_sg, out_sgs,
++ in_sgs, data, gfp);
++ if (err != -ENOMEM)
++ return err;
++
++ /* fall back on direct */
++ }
+
+ head = vq->packed.next_avail_idx;
+ avail_used_flags = vq->packed.avail_used_flags;
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index bf59faeb3de1b..d937f957f8df8 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1679,7 +1679,7 @@ config SIBYTE_WDOG
+
+ config AR7_WDT
+ tristate "TI AR7 Watchdog Timer"
+- depends on AR7 || (MIPS && COMPILE_TEST)
++ depends on AR7 || (MIPS && 32BIT && COMPILE_TEST)
+ help
+ Hardware driver for the TI AR7 Watchdog Timer.
+
+diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
+index f60beec1bbaea..f7d82d2619133 100644
+--- a/drivers/watchdog/f71808e_wdt.c
++++ b/drivers/watchdog/f71808e_wdt.c
+@@ -228,15 +228,17 @@ static int watchdog_set_timeout(int timeout)
+
+ mutex_lock(&watchdog.lock);
+
+- watchdog.timeout = timeout;
+ if (timeout > 0xff) {
+ watchdog.timer_val = DIV_ROUND_UP(timeout, 60);
+ watchdog.minutes_mode = true;
++ timeout = watchdog.timer_val * 60;
+ } else {
+ watchdog.timer_val = timeout;
+ watchdog.minutes_mode = false;
+ }
+
++ watchdog.timeout = timeout;
++
+ mutex_unlock(&watchdog.lock);
+
+ return 0;
+diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
+index 3a50f097ed3ed..8db96b5e72536 100644
+--- a/drivers/xen/balloon.c
++++ b/drivers/xen/balloon.c
+@@ -58,6 +58,7 @@
+ #include <linux/percpu-defs.h>
+ #include <linux/slab.h>
+ #include <linux/sysctl.h>
++#include <linux/moduleparam.h>
+
+ #include <asm/page.h>
+ #include <asm/tlb.h>
+@@ -73,6 +74,12 @@
+ #include <xen/page.h>
+ #include <xen/mem-reservation.h>
+
++#undef MODULE_PARAM_PREFIX
++#define MODULE_PARAM_PREFIX "xen."
++
++static uint __read_mostly balloon_boot_timeout = 180;
++module_param(balloon_boot_timeout, uint, 0444);
++
+ static int xen_hotplug_unpopulated;
+
+ #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
+@@ -125,12 +132,12 @@ static struct ctl_table xen_root[] = {
+ * BP_ECANCELED: error, balloon operation canceled.
+ */
+
+-enum bp_state {
++static enum bp_state {
+ BP_DONE,
+ BP_WAIT,
+ BP_EAGAIN,
+ BP_ECANCELED
+-};
++} balloon_state = BP_DONE;
+
+ /* Main waiting point for xen-balloon thread. */
+ static DECLARE_WAIT_QUEUE_HEAD(balloon_thread_wq);
+@@ -199,18 +206,15 @@ static struct page *balloon_next_page(struct page *page)
+ return list_entry(next, struct page, lru);
+ }
+
+-static enum bp_state update_schedule(enum bp_state state)
++static void update_schedule(void)
+ {
+- if (state == BP_WAIT)
+- return BP_WAIT;
+-
+- if (state == BP_ECANCELED)
+- return BP_ECANCELED;
++ if (balloon_state == BP_WAIT || balloon_state == BP_ECANCELED)
++ return;
+
+- if (state == BP_DONE) {
++ if (balloon_state == BP_DONE) {
+ balloon_stats.schedule_delay = 1;
+ balloon_stats.retry_count = 1;
+- return BP_DONE;
++ return;
+ }
+
+ ++balloon_stats.retry_count;
+@@ -219,7 +223,8 @@ static enum bp_state update_schedule(enum bp_state state)
+ balloon_stats.retry_count > balloon_stats.max_retry_count) {
+ balloon_stats.schedule_delay = 1;
+ balloon_stats.retry_count = 1;
+- return BP_ECANCELED;
++ balloon_state = BP_ECANCELED;
++ return;
+ }
+
+ balloon_stats.schedule_delay <<= 1;
+@@ -227,7 +232,7 @@ static enum bp_state update_schedule(enum bp_state state)
+ if (balloon_stats.schedule_delay > balloon_stats.max_schedule_delay)
+ balloon_stats.schedule_delay = balloon_stats.max_schedule_delay;
+
+- return BP_EAGAIN;
++ balloon_state = BP_EAGAIN;
+ }
+
+ #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
+@@ -494,9 +499,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
+ * Stop waiting if either state is BP_DONE and ballooning action is
+ * needed, or if the credit has changed while state is not BP_DONE.
+ */
+-static bool balloon_thread_cond(enum bp_state state, long credit)
++static bool balloon_thread_cond(long credit)
+ {
+- if (state == BP_DONE)
++ if (balloon_state == BP_DONE)
+ credit = 0;
+
+ return current_credit() != credit || kthread_should_stop();
+@@ -510,13 +515,12 @@ static bool balloon_thread_cond(enum bp_state state, long credit)
+ */
+ static int balloon_thread(void *unused)
+ {
+- enum bp_state state = BP_DONE;
+ long credit;
+ unsigned long timeout;
+
+ set_freezable();
+ for (;;) {
+- switch (state) {
++ switch (balloon_state) {
+ case BP_DONE:
+ case BP_ECANCELED:
+ timeout = 3600 * HZ;
+@@ -532,7 +536,7 @@ static int balloon_thread(void *unused)
+ credit = current_credit();
+
+ wait_event_freezable_timeout(balloon_thread_wq,
+- balloon_thread_cond(state, credit), timeout);
++ balloon_thread_cond(credit), timeout);
+
+ if (kthread_should_stop())
+ return 0;
+@@ -543,22 +547,23 @@ static int balloon_thread(void *unused)
+
+ if (credit > 0) {
+ if (balloon_is_inflated())
+- state = increase_reservation(credit);
++ balloon_state = increase_reservation(credit);
+ else
+- state = reserve_additional_memory();
++ balloon_state = reserve_additional_memory();
+ }
+
+ if (credit < 0) {
+ long n_pages;
+
+ n_pages = min(-credit, si_mem_available());
+- state = decrease_reservation(n_pages, GFP_BALLOON);
+- if (state == BP_DONE && n_pages != -credit &&
++ balloon_state = decrease_reservation(n_pages,
++ GFP_BALLOON);
++ if (balloon_state == BP_DONE && n_pages != -credit &&
+ n_pages < totalreserve_pages)
+- state = BP_EAGAIN;
++ balloon_state = BP_EAGAIN;
+ }
+
+- state = update_schedule(state);
++ update_schedule();
+
+ mutex_unlock(&balloon_mutex);
+
+@@ -765,3 +770,38 @@ static int __init balloon_init(void)
+ return 0;
+ }
+ subsys_initcall(balloon_init);
++
++static int __init balloon_wait_finish(void)
++{
++ long credit, last_credit = 0;
++ unsigned long last_changed = 0;
++
++ if (!xen_domain())
++ return -ENODEV;
++
++ /* PV guests don't need to wait. */
++ if (xen_pv_domain() || !current_credit())
++ return 0;
++
++ pr_notice("Waiting for initial ballooning down having finished.\n");
++
++ while ((credit = current_credit()) < 0) {
++ if (credit != last_credit) {
++ last_changed = jiffies;
++ last_credit = credit;
++ }
++ if (balloon_state == BP_ECANCELED) {
++ pr_warn_once("Initial ballooning failed, %ld pages need to be freed.\n",
++ -credit);
++ if (jiffies - last_changed >= HZ * balloon_boot_timeout)
++ panic("Initial ballooning failed!\n");
++ }
++
++ schedule_timeout_interruptible(HZ / 10);
++ }
++
++ pr_notice("Initial ballooning down finished.\n");
++
++ return 0;
++}
++late_initcall_sync(balloon_wait_finish);
+diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
+index a78704ae36186..46d9295d9a6e4 100644
+--- a/drivers/xen/events/events_base.c
++++ b/drivers/xen/events/events_base.c
+@@ -1251,6 +1251,12 @@ int bind_evtchn_to_irq(evtchn_port_t evtchn)
+ }
+ EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
++int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
++{
++ return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL);
++}
++EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
++
+ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+ {
+ struct evtchn_bind_ipi bind_ipi;
+diff --git a/drivers/xen/xen-pciback/conf_space_capability.c b/drivers/xen/xen-pciback/conf_space_capability.c
+index 22f13abbe9130..5e53b4817f167 100644
+--- a/drivers/xen/xen-pciback/conf_space_capability.c
++++ b/drivers/xen/xen-pciback/conf_space_capability.c
+@@ -160,7 +160,7 @@ static void *pm_ctrl_init(struct pci_dev *dev, int offset)
+ }
+
+ out:
+- return ERR_PTR(err);
++ return err ? ERR_PTR(err) : NULL;
+ }
+
+ static const struct config_field caplist_pm[] = {
+diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
+index bd003ca8acbe9..fe360c33ce717 100644
+--- a/drivers/xen/xenbus/xenbus_probe.c
++++ b/drivers/xen/xenbus/xenbus_probe.c
+@@ -909,7 +909,7 @@ static struct notifier_block xenbus_resume_nb = {
+
+ static int __init xenbus_init(void)
+ {
+- int err = 0;
++ int err;
+ uint64_t v = 0;
+ xen_store_domain_type = XS_UNKNOWN;
+
+@@ -949,6 +949,29 @@ static int __init xenbus_init(void)
+ err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+ if (err)
+ goto out_error;
++ /*
++ * Uninitialized hvm_params are zero and return no error.
++ * Although it is theoretically possible to have
++ * HVM_PARAM_STORE_PFN set to zero on purpose, in reality it is
++ * not zero when valid. If zero, it means that Xenstore hasn't
++ * been properly initialized. Instead of attempting to map a
++ * wrong guest physical address return error.
++ *
++ * Also recognize all bits set as an invalid value.
++ */
++ if (!v || !~v) {
++ err = -ENOENT;
++ goto out_error;
++ }
++ /* Avoid truncation on 32-bit. */
++#if BITS_PER_LONG == 32
++ if (v > ULONG_MAX) {
++ pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
++ __func__, v);
++ err = -EINVAL;
++ goto out_error;
++ }
++#endif
+ xen_store_gfn = (unsigned long)v;
+ xen_store_interface =
+ xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
+@@ -983,8 +1006,10 @@ static int __init xenbus_init(void)
+ */
+ proc_create_mount_point("xen");
+ #endif
++ return 0;
+
+ out_error:
++ xen_store_domain_type = XS_UNKNOWN;
+ return err;
+ }
+
+diff --git a/fs/afs/file.c b/fs/afs/file.c
+index e6c447ae91f38..b165377179c3c 100644
+--- a/fs/afs/file.c
++++ b/fs/afs/file.c
+@@ -502,8 +502,9 @@ static void afs_add_open_mmap(struct afs_vnode *vnode)
+ if (atomic_inc_return(&vnode->cb_nr_mmap) == 1) {
+ down_write(&vnode->volume->cell->fs_open_mmaps_lock);
+
+- list_add_tail(&vnode->cb_mmap_link,
+- &vnode->volume->cell->fs_open_mmaps);
++ if (list_empty(&vnode->cb_mmap_link))
++ list_add_tail(&vnode->cb_mmap_link,
++ &vnode->volume->cell->fs_open_mmaps);
+
+ up_write(&vnode->volume->cell->fs_open_mmaps_lock);
+ }
+diff --git a/fs/afs/super.c b/fs/afs/super.c
+index d110def8aa8eb..34c68724c98be 100644
+--- a/fs/afs/super.c
++++ b/fs/afs/super.c
+@@ -667,6 +667,7 @@ static void afs_i_init_once(void *_vnode)
+ INIT_LIST_HEAD(&vnode->pending_locks);
+ INIT_LIST_HEAD(&vnode->granted_locks);
+ INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
++ INIT_LIST_HEAD(&vnode->cb_mmap_link);
+ seqlock_init(&vnode->cb_lock);
+ }
+
+diff --git a/fs/aio.c b/fs/aio.c
+index 51b08ab01dffc..1a78979663dca 100644
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -181,8 +181,9 @@ struct poll_iocb {
+ struct file *file;
+ struct wait_queue_head *head;
+ __poll_t events;
+- bool done;
+ bool cancelled;
++ bool work_scheduled;
++ bool work_need_resched;
+ struct wait_queue_entry wait;
+ struct work_struct work;
+ };
+@@ -1620,6 +1621,51 @@ static void aio_poll_put_work(struct work_struct *work)
+ iocb_put(iocb);
+ }
+
++/*
++ * Safely lock the waitqueue which the request is on, synchronizing with the
++ * case where the ->poll() provider decides to free its waitqueue early.
++ *
++ * Returns true on success, meaning that req->head->lock was locked, req->wait
++ * is on req->head, and an RCU read lock was taken. Returns false if the
++ * request was already removed from its waitqueue (which might no longer exist).
++ */
++static bool poll_iocb_lock_wq(struct poll_iocb *req)
++{
++ wait_queue_head_t *head;
++
++ /*
++ * While we hold the waitqueue lock and the waitqueue is nonempty,
++ * wake_up_pollfree() will wait for us. However, taking the waitqueue
++ * lock in the first place can race with the waitqueue being freed.
++ *
++ * We solve this as eventpoll does: by taking advantage of the fact that
++ * all users of wake_up_pollfree() will RCU-delay the actual free. If
++ * we enter rcu_read_lock() and see that the pointer to the queue is
++ * non-NULL, we can then lock it without the memory being freed out from
++ * under us, then check whether the request is still on the queue.
++ *
++ * Keep holding rcu_read_lock() as long as we hold the queue lock, in
++ * case the caller deletes the entry from the queue, leaving it empty.
++ * In that case, only RCU prevents the queue memory from being freed.
++ */
++ rcu_read_lock();
++ head = smp_load_acquire(&req->head);
++ if (head) {
++ spin_lock(&head->lock);
++ if (!list_empty(&req->wait.entry))
++ return true;
++ spin_unlock(&head->lock);
++ }
++ rcu_read_unlock();
++ return false;
++}
++
++static void poll_iocb_unlock_wq(struct poll_iocb *req)
++{
++ spin_unlock(&req->head->lock);
++ rcu_read_unlock();
++}
++
+ static void aio_poll_complete_work(struct work_struct *work)
+ {
+ struct poll_iocb *req = container_of(work, struct poll_iocb, work);
+@@ -1639,14 +1685,27 @@ static void aio_poll_complete_work(struct work_struct *work)
+ * avoid further branches in the fast path.
+ */
+ spin_lock_irq(&ctx->ctx_lock);
+- if (!mask && !READ_ONCE(req->cancelled)) {
+- add_wait_queue(req->head, &req->wait);
+- spin_unlock_irq(&ctx->ctx_lock);
+- return;
+- }
++ if (poll_iocb_lock_wq(req)) {
++ if (!mask && !READ_ONCE(req->cancelled)) {
++ /*
++ * The request isn't actually ready to be completed yet.
++ * Reschedule completion if another wakeup came in.
++ */
++ if (req->work_need_resched) {
++ schedule_work(&req->work);
++ req->work_need_resched = false;
++ } else {
++ req->work_scheduled = false;
++ }
++ poll_iocb_unlock_wq(req);
++ spin_unlock_irq(&ctx->ctx_lock);
++ return;
++ }
++ list_del_init(&req->wait.entry);
++ poll_iocb_unlock_wq(req);
++ } /* else, POLLFREE has freed the waitqueue, so we must complete */
+ list_del_init(&iocb->ki_list);
+ iocb->ki_res.res = mangle_poll(mask);
+- req->done = true;
+ spin_unlock_irq(&ctx->ctx_lock);
+
+ iocb_put(iocb);
+@@ -1658,13 +1717,14 @@ static int aio_poll_cancel(struct kiocb *iocb)
+ struct aio_kiocb *aiocb = container_of(iocb, struct aio_kiocb, rw);
+ struct poll_iocb *req = &aiocb->poll;
+
+- spin_lock(&req->head->lock);
+- WRITE_ONCE(req->cancelled, true);
+- if (!list_empty(&req->wait.entry)) {
+- list_del_init(&req->wait.entry);
+- schedule_work(&aiocb->poll.work);
+- }
+- spin_unlock(&req->head->lock);
++ if (poll_iocb_lock_wq(req)) {
++ WRITE_ONCE(req->cancelled, true);
++ if (!req->work_scheduled) {
++ schedule_work(&aiocb->poll.work);
++ req->work_scheduled = true;
++ }
++ poll_iocb_unlock_wq(req);
++ } /* else, the request was force-cancelled by POLLFREE already */
+
+ return 0;
+ }
+@@ -1681,21 +1741,27 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+ if (mask && !(mask & req->events))
+ return 0;
+
+- list_del_init(&req->wait.entry);
+-
+- if (mask && spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) {
++ /*
++ * Complete the request inline if possible. This requires that three
++ * conditions be met:
++ * 1. An event mask must have been passed. If a plain wakeup was done
++ * instead, then mask == 0 and we have to call vfs_poll() to get
++ * the events, so inline completion isn't possible.
++ * 2. The completion work must not have already been scheduled.
++ * 3. ctx_lock must not be busy. We have to use trylock because we
++ * already hold the waitqueue lock, so this inverts the normal
++ * locking order. Use irqsave/irqrestore because not all
++ * filesystems (e.g. fuse) call this function with IRQs disabled,
++ * yet IRQs have to be disabled before ctx_lock is obtained.
++ */
++ if (mask && !req->work_scheduled &&
++ spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) {
+ struct kioctx *ctx = iocb->ki_ctx;
+
+- /*
+- * Try to complete the iocb inline if we can. Use
+- * irqsave/irqrestore because not all filesystems (e.g. fuse)
+- * call this function with IRQs disabled and because IRQs
+- * have to be disabled before ctx_lock is obtained.
+- */
++ list_del_init(&req->wait.entry);
+ list_del(&iocb->ki_list);
+ iocb->ki_res.res = mangle_poll(mask);
+- req->done = true;
+- if (iocb->ki_eventfd && eventfd_signal_allowed()) {
++ if (iocb->ki_eventfd && !eventfd_signal_allowed()) {
+ iocb = NULL;
+ INIT_WORK(&req->work, aio_poll_put_work);
+ schedule_work(&req->work);
+@@ -1704,7 +1770,43 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+ if (iocb)
+ iocb_put(iocb);
+ } else {
+- schedule_work(&req->work);
++ /*
++ * Schedule the completion work if needed. If it was already
++ * scheduled, record that another wakeup came in.
++ *
++ * Don't remove the request from the waitqueue here, as it might
++ * not actually be complete yet (we won't know until vfs_poll()
++ * is called), and we must not miss any wakeups. POLLFREE is an
++ * exception to this; see below.
++ */
++ if (req->work_scheduled) {
++ req->work_need_resched = true;
++ } else {
++ schedule_work(&req->work);
++ req->work_scheduled = true;
++ }
++
++ /*
++ * If the waitqueue is being freed early but we can't complete
++ * the request inline, we have to tear down the request as best
++ * we can. That means immediately removing the request from its
++ * waitqueue and preventing all further accesses to the
++ * waitqueue via the request. We also need to schedule the
++ * completion work (done above). Also mark the request as
++ * cancelled, to potentially skip an unneeded call to ->poll().
++ */
++ if (mask & POLLFREE) {
++ WRITE_ONCE(req->cancelled, true);
++ list_del_init(&req->wait.entry);
++
++ /*
++ * Careful: this *must* be the last step, since as soon
++ * as req->head is NULL'ed out, the request can be
++ * completed and freed, since aio_poll_complete_work()
++ * will no longer need to take the waitqueue lock.
++ */
++ smp_store_release(&req->head, NULL);
++ }
+ }
+ return 1;
+ }
+@@ -1712,6 +1814,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+ struct aio_poll_table {
+ struct poll_table_struct pt;
+ struct aio_kiocb *iocb;
++ bool queued;
+ int error;
+ };
+
+@@ -1722,11 +1825,12 @@ aio_poll_queue_proc(struct file *file, struct wait_queue_head *head,
+ struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt);
+
+ /* multiple wait queues per file are not supported */
+- if (unlikely(pt->iocb->poll.head)) {
++ if (unlikely(pt->queued)) {
+ pt->error = -EINVAL;
+ return;
+ }
+
++ pt->queued = true;
+ pt->error = 0;
+ pt->iocb->poll.head = head;
+ add_wait_queue(head, &pt->iocb->poll.wait);
+@@ -1751,12 +1855,14 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
+ req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP;
+
+ req->head = NULL;
+- req->done = false;
+ req->cancelled = false;
++ req->work_scheduled = false;
++ req->work_need_resched = false;
+
+ apt.pt._qproc = aio_poll_queue_proc;
+ apt.pt._key = req->events;
+ apt.iocb = aiocb;
++ apt.queued = false;
+ apt.error = -EINVAL; /* same as no support for IOCB_CMD_POLL */
+
+ /* initialized the list so that we can do list_empty checks */
+@@ -1765,23 +1871,35 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
+
+ mask = vfs_poll(req->file, &apt.pt) & req->events;
+ spin_lock_irq(&ctx->ctx_lock);
+- if (likely(req->head)) {
+- spin_lock(&req->head->lock);
+- if (unlikely(list_empty(&req->wait.entry))) {
+- if (apt.error)
++ if (likely(apt.queued)) {
++ bool on_queue = poll_iocb_lock_wq(req);
++
++ if (!on_queue || req->work_scheduled) {
++ /*
++ * aio_poll_wake() already either scheduled the async
++ * completion work, or completed the request inline.
++ */
++ if (apt.error) /* unsupported case: multiple queues */
+ cancel = true;
+ apt.error = 0;
+ mask = 0;
+ }
+ if (mask || apt.error) {
++ /* Steal to complete synchronously. */
+ list_del_init(&req->wait.entry);
+ } else if (cancel) {
++ /* Cancel if possible (may be too late though). */
+ WRITE_ONCE(req->cancelled, true);
+- } else if (!req->done) { /* actually waiting for an event */
++ } else if (on_queue) {
++ /*
++ * Actually waiting for an event, so add the request to
++ * active_reqs so that it can be cancelled if needed.
++ */
+ list_add_tail(&aiocb->ki_list, &ctx->active_reqs);
+ aiocb->ki_cancel = aio_poll_cancel;
+ }
+- spin_unlock(&req->head->lock);
++ if (on_queue)
++ poll_iocb_unlock_wq(req);
+ }
+ if (mask) { /* no async, we'd stolen it */
+ aiocb->ki_res.res = mangle_poll(mask);
+diff --git a/fs/attr.c b/fs/attr.c
+index 473d21b3a86de..66899b6e9bd86 100644
+--- a/fs/attr.c
++++ b/fs/attr.c
+@@ -35,7 +35,7 @@ static bool chown_ok(struct user_namespace *mnt_userns,
+ kuid_t uid)
+ {
+ kuid_t kuid = i_uid_into_mnt(mnt_userns, inode);
+- if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, kuid))
++ if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, inode->i_uid))
+ return true;
+ if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
+ return true;
+@@ -62,7 +62,7 @@ static bool chgrp_ok(struct user_namespace *mnt_userns,
+ {
+ kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
+ if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) &&
+- (in_group_p(gid) || gid_eq(gid, kgid)))
++ (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
+ return true;
+ if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
+ return true;
+diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
+index 309516e6a9682..43c89952b7d25 100644
+--- a/fs/btrfs/async-thread.c
++++ b/fs/btrfs/async-thread.c
+@@ -234,6 +234,13 @@ static void run_ordered_work(struct __btrfs_workqueue *wq,
+ ordered_list);
+ if (!test_bit(WORK_DONE_BIT, &work->flags))
+ break;
++ /*
++ * Orders all subsequent loads after reading WORK_DONE_BIT,
++ * paired with the smp_mb__before_atomic in btrfs_work_helper
++ * this guarantees that the ordered function will see all
++ * updates from ordinary work function.
++ */
++ smp_rmb();
+
+ /*
+ * we are going to call the ordered done function, but
+@@ -317,6 +324,13 @@ static void btrfs_work_helper(struct work_struct *normal_work)
+ thresh_exec_hook(wq);
+ work->func(work);
+ if (need_order) {
++ /*
++ * Ensures all memory accesses done in the work function are
++ * ordered before setting the WORK_DONE_BIT. Ensuring the thread
++ * which is going to executed the ordered work sees them.
++ * Pairs with the smp_rmb in run_ordered_work.
++ */
++ smp_mb__before_atomic();
+ set_bit(WORK_DONE_BIT, &work->flags);
+ run_ordered_work(wq, work);
+ } else {
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index a3b830b8410a8..a53ebc52bd51f 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -902,6 +902,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
+ spin_unlock(&cluster->refill_lock);
+
+ btrfs_clear_treelog_bg(block_group);
++ btrfs_clear_data_reloc_bg(block_group);
+
+ path = btrfs_alloc_path();
+ if (!path) {
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index c0cebcf745cef..ae06ad5593535 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -1017,6 +1017,13 @@ struct btrfs_fs_info {
+ spinlock_t treelog_bg_lock;
+ u64 treelog_bg;
+
++ /*
++ * Start of the dedicated data relocation block group, protected by
++ * relocation_bg_lock.
++ */
++ spinlock_t relocation_bg_lock;
++ u64 data_reloc_bg;
++
+ #ifdef CONFIG_BTRFS_FS_REF_VERIFY
+ spinlock_t ref_verify_lock;
+ struct rb_root block_tree;
+@@ -3842,6 +3849,11 @@ static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info)
+ return fs_info->zoned != 0;
+ }
+
++static inline bool btrfs_is_data_reloc_root(const struct btrfs_root *root)
++{
++ return root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID;
++}
++
+ /*
+ * We use page status Private2 to indicate there is an ordered extent with
+ * unfinished IO.
+diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c
+index 2059d1504149a..40c4d6ba3fb9a 100644
+--- a/fs/btrfs/delalloc-space.c
++++ b/fs/btrfs/delalloc-space.c
+@@ -143,10 +143,13 @@ int btrfs_check_data_free_space(struct btrfs_inode *inode,
+
+ /* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
+ ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
+- if (ret < 0)
++ if (ret < 0) {
+ btrfs_free_reserved_data_space_noquota(fs_info, len);
+- else
++ extent_changeset_free(*reserved);
++ *reserved = NULL;
++ } else {
+ ret = 0;
++ }
+ return ret;
+ }
+
+@@ -452,8 +455,11 @@ int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
+ if (ret < 0)
+ return ret;
+ ret = btrfs_delalloc_reserve_metadata(inode, len);
+- if (ret < 0)
++ if (ret < 0) {
+ btrfs_free_reserved_data_space(inode, *reserved, start, len);
++ extent_changeset_free(*reserved);
++ *reserved = NULL;
++ }
+ return ret;
+ }
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 355ea88d5c5f7..e1a262120e021 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -1500,7 +1500,7 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
+ goto fail;
+
+ if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
+- root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
++ !btrfs_is_data_reloc_root(root)) {
+ set_bit(BTRFS_ROOT_SHAREABLE, &root->state);
+ btrfs_check_and_init_root_item(&root->root_item);
+ }
+@@ -1731,6 +1731,14 @@ again:
+ }
+ return root;
+ fail:
++ /*
++ * If our caller provided us an anonymous device, then it's his
++ * responsability to free it in case we fail. So we have to set our
++ * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
++ * and once again by our caller.
++ */
++ if (anon_dev)
++ root->anon_dev = 0;
+ btrfs_put_root(root);
+ return ERR_PTR(ret);
+ }
+@@ -2883,6 +2891,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
+ spin_lock_init(&fs_info->buffer_lock);
+ spin_lock_init(&fs_info->unused_bgs_lock);
+ spin_lock_init(&fs_info->treelog_bg_lock);
++ spin_lock_init(&fs_info->relocation_bg_lock);
+ rwlock_init(&fs_info->tree_mod_log_lock);
+ mutex_init(&fs_info->unused_bg_unpin_mutex);
+ mutex_init(&fs_info->reclaim_bgs_lock);
+@@ -3228,12 +3237,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
+ mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
+ btrfs_init_btree_inode(fs_info);
+
+- invalidate_bdev(fs_devices->latest_bdev);
++ invalidate_bdev(fs_devices->latest_dev->bdev);
+
+ /*
+ * Read super block and check the signature bytes only
+ */
+- disk_super = btrfs_read_dev_super(fs_devices->latest_bdev);
++ disk_super = btrfs_read_dev_super(fs_devices->latest_dev->bdev);
+ if (IS_ERR(disk_super)) {
+ err = PTR_ERR(disk_super);
+ goto fail_alloc;
+@@ -3465,7 +3474,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
+ * below in btrfs_init_dev_replace().
+ */
+ btrfs_free_extra_devids(fs_devices);
+- if (!fs_devices->latest_bdev) {
++ if (!fs_devices->latest_dev->bdev) {
+ btrfs_err(fs_info, "failed to read devices");
+ goto fail_tree_roots;
+ }
+@@ -3556,7 +3565,8 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
+ goto fail_sysfs;
+ }
+
+- if (!sb_rdonly(sb) && !btrfs_check_rw_degradable(fs_info, NULL)) {
++ if (!sb_rdonly(sb) && fs_info->fs_devices->missing_devices &&
++ !btrfs_check_rw_degradable(fs_info, NULL)) {
+ btrfs_warn(fs_info,
+ "writable mount is not allowed due to too many missing devices");
+ goto fail_sysfs;
+@@ -3968,11 +3978,23 @@ static void btrfs_end_empty_barrier(struct bio *bio)
+ */
+ static void write_dev_flush(struct btrfs_device *device)
+ {
+- struct request_queue *q = bdev_get_queue(device->bdev);
+ struct bio *bio = device->flush_bio;
+
++#ifndef CONFIG_BTRFS_FS_CHECK_INTEGRITY
++ /*
++ * When a disk has write caching disabled, we skip submission of a bio
++ * with flush and sync requests before writing the superblock, since
++ * it's not needed. However when the integrity checker is enabled, this
++ * results in reports that there are metadata blocks referred by a
++ * superblock that were not properly flushed. So don't skip the bio
++ * submission only when the integrity checker is enabled for the sake
++ * of simplicity, since this is a debug tool and not meant for use in
++ * non-debug builds.
++ */
++ struct request_queue *q = bdev_get_queue(device->bdev);
+ if (!test_bit(QUEUE_FLAG_WC, &q->queue_flags))
+ return;
++#endif
+
+ bio_reset(bio);
+ bio->bi_end_io = btrfs_end_empty_barrier;
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index 0ab456cb4bf80..87c23c5c0f26d 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2376,7 +2376,7 @@ int btrfs_cross_ref_exist(struct btrfs_root *root, u64 objectid, u64 offset,
+
+ out:
+ btrfs_free_path(path);
+- if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
++ if (btrfs_is_data_reloc_root(root))
+ WARN_ON(ret > 0);
+ return ret;
+ }
+@@ -3495,6 +3495,9 @@ struct find_free_extent_ctl {
+ /* Allocation is called for tree-log */
+ bool for_treelog;
+
++ /* Allocation is called for data relocation */
++ bool for_data_reloc;
++
+ /* RAID index, converted from flags */
+ int index;
+
+@@ -3756,6 +3759,7 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
+ u64 avail;
+ u64 bytenr = block_group->start;
+ u64 log_bytenr;
++ u64 data_reloc_bytenr;
+ int ret = 0;
+ bool skip;
+
+@@ -3773,13 +3777,31 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
+ if (skip)
+ return 1;
+
++ /*
++ * Do not allow non-relocation blocks in the dedicated relocation block
++ * group, and vice versa.
++ */
++ spin_lock(&fs_info->relocation_bg_lock);
++ data_reloc_bytenr = fs_info->data_reloc_bg;
++ if (data_reloc_bytenr &&
++ ((ffe_ctl->for_data_reloc && bytenr != data_reloc_bytenr) ||
++ (!ffe_ctl->for_data_reloc && bytenr == data_reloc_bytenr)))
++ skip = true;
++ spin_unlock(&fs_info->relocation_bg_lock);
++ if (skip)
++ return 1;
++
+ spin_lock(&space_info->lock);
+ spin_lock(&block_group->lock);
+ spin_lock(&fs_info->treelog_bg_lock);
++ spin_lock(&fs_info->relocation_bg_lock);
+
+ ASSERT(!ffe_ctl->for_treelog ||
+ block_group->start == fs_info->treelog_bg ||
+ fs_info->treelog_bg == 0);
++ ASSERT(!ffe_ctl->for_data_reloc ||
++ block_group->start == fs_info->data_reloc_bg ||
++ fs_info->data_reloc_bg == 0);
+
+ if (block_group->ro) {
+ ret = 1;
+@@ -3796,6 +3818,16 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
+ goto out;
+ }
+
++ /*
++ * Do not allow currently used block group to be the data relocation
++ * dedicated block group.
++ */
++ if (ffe_ctl->for_data_reloc && !fs_info->data_reloc_bg &&
++ (block_group->used || block_group->reserved)) {
++ ret = 1;
++ goto out;
++ }
++
+ avail = block_group->length - block_group->alloc_offset;
+ if (avail < num_bytes) {
+ if (ffe_ctl->max_extent_size < avail) {
+@@ -3813,6 +3845,9 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
+ if (ffe_ctl->for_treelog && !fs_info->treelog_bg)
+ fs_info->treelog_bg = block_group->start;
+
++ if (ffe_ctl->for_data_reloc && !fs_info->data_reloc_bg)
++ fs_info->data_reloc_bg = block_group->start;
++
+ ffe_ctl->found_offset = start + block_group->alloc_offset;
+ block_group->alloc_offset += num_bytes;
+ spin_lock(&ctl->tree_lock);
+@@ -3829,6 +3864,9 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
+ out:
+ if (ret && ffe_ctl->for_treelog)
+ fs_info->treelog_bg = 0;
++ if (ret && ffe_ctl->for_data_reloc)
++ fs_info->data_reloc_bg = 0;
++ spin_unlock(&fs_info->relocation_bg_lock);
+ spin_unlock(&fs_info->treelog_bg_lock);
+ spin_unlock(&block_group->lock);
+ spin_unlock(&space_info->lock);
+@@ -4085,6 +4123,12 @@ static int prepare_allocation(struct btrfs_fs_info *fs_info,
+ ffe_ctl->hint_byte = fs_info->treelog_bg;
+ spin_unlock(&fs_info->treelog_bg_lock);
+ }
++ if (ffe_ctl->for_data_reloc) {
++ spin_lock(&fs_info->relocation_bg_lock);
++ if (fs_info->data_reloc_bg)
++ ffe_ctl->hint_byte = fs_info->data_reloc_bg;
++ spin_unlock(&fs_info->relocation_bg_lock);
++ }
+ return 0;
+ default:
+ BUG();
+@@ -4129,6 +4173,8 @@ static noinline int find_free_extent(struct btrfs_root *root,
+ struct btrfs_space_info *space_info;
+ bool full_search = false;
+ bool for_treelog = (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID);
++ bool for_data_reloc = (btrfs_is_data_reloc_root(root) &&
++ flags & BTRFS_BLOCK_GROUP_DATA);
+
+ WARN_ON(num_bytes < fs_info->sectorsize);
+
+@@ -4143,6 +4189,7 @@ static noinline int find_free_extent(struct btrfs_root *root,
+ ffe_ctl.found_offset = 0;
+ ffe_ctl.hint_byte = hint_byte_orig;
+ ffe_ctl.for_treelog = for_treelog;
++ ffe_ctl.for_data_reloc = for_data_reloc;
+ ffe_ctl.policy = BTRFS_EXTENT_ALLOC_CLUSTERED;
+
+ /* For clustered allocation */
+@@ -4220,6 +4267,8 @@ search:
+ if (unlikely(block_group->ro)) {
+ if (for_treelog)
+ btrfs_clear_treelog_bg(block_group);
++ if (ffe_ctl.for_data_reloc)
++ btrfs_clear_data_reloc_bg(block_group);
+ continue;
+ }
+
+@@ -4408,6 +4457,7 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes,
+ u64 flags;
+ int ret;
+ bool for_treelog = (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID);
++ bool for_data_reloc = (btrfs_is_data_reloc_root(root) && is_data);
+
+ flags = get_alloc_profile_by_root(root, is_data);
+ again:
+@@ -4431,8 +4481,8 @@ again:
+
+ sinfo = btrfs_find_space_info(fs_info, flags);
+ btrfs_err(fs_info,
+- "allocation failed flags %llu, wanted %llu tree-log %d",
+- flags, num_bytes, for_treelog);
++ "allocation failed flags %llu, wanted %llu tree-log %d, relocation: %d",
++ flags, num_bytes, for_treelog, for_data_reloc);
+ if (sinfo)
+ btrfs_dump_space_info(fs_info, sinfo,
+ num_bytes, 1);
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index aaddd72253481..250fd3c146ac9 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -3327,7 +3327,7 @@ static int alloc_new_bio(struct btrfs_inode *inode,
+ if (wbc) {
+ struct block_device *bdev;
+
+- bdev = fs_info->fs_devices->latest_bdev;
++ bdev = fs_info->fs_devices->latest_dev->bdev;
+ bio_set_dev(bio, bdev);
+ wbc_init_bio(wbc, bio);
+ }
+@@ -4284,6 +4284,12 @@ static void set_btree_ioerr(struct page *page, struct extent_buffer *eb)
+ if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags))
+ return;
+
++ /*
++ * A read may stumble upon this buffer later, make sure that it gets an
++ * error and knows there was an error.
++ */
++ clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
++
+ /*
+ * If we error out, we should add back the dirty_metadata_bytes
+ * to make it consistent.
+@@ -5120,6 +5126,9 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
+ int extent_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+ {
++ struct inode *inode = mapping->host;
++ const bool data_reloc = btrfs_is_data_reloc_root(BTRFS_I(inode)->root);
++ const bool zoned = btrfs_is_zoned(BTRFS_I(inode)->root->fs_info);
+ int ret = 0;
+ struct extent_page_data epd = {
+ .bio_ctrl = { 0 },
+@@ -5127,7 +5136,15 @@ int extent_writepages(struct address_space *mapping,
+ .sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ };
+
++ /*
++ * Allow only a single thread to do the reloc work in zoned mode to
++ * protect the write pointer updates.
++ */
++ if (data_reloc && zoned)
++ btrfs_inode_lock(inode, 0);
+ ret = extent_write_cache_pages(mapping, wbc, &epd);
++ if (data_reloc && zoned)
++ btrfs_inode_unlock(inode, 0);
+ ASSERT(ret <= 0);
+ if (ret < 0) {
+ end_write_bio(&epd, ret);
+@@ -6530,6 +6547,14 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
+ if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
+ return 0;
+
++ /*
++ * We could have had EXTENT_BUFFER_UPTODATE cleared by the write
++ * operation, which could potentially still be in flight. In this case
++ * we simply want to return an error.
++ */
++ if (unlikely(test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)))
++ return -EIO;
++
+ if (eb->fs_info->sectorsize < PAGE_SIZE)
+ return read_extent_buffer_subpage(eb, wait, mirror_num);
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 7c096ab9bb5eb..4af74b62e7d97 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -1151,7 +1151,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ * fails during the stage where it updates the bytenr of file extent
+ * items.
+ */
+- if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
++ if (btrfs_is_data_reloc_root(root))
+ min_alloc_size = num_bytes;
+ else
+ min_alloc_size = fs_info->sectorsize;
+@@ -1187,8 +1187,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ if (ret)
+ goto out_drop_extent_cache;
+
+- if (root->root_key.objectid ==
+- BTRFS_DATA_RELOC_TREE_OBJECTID) {
++ if (btrfs_is_data_reloc_root(root)) {
+ ret = btrfs_reloc_clone_csums(inode, start,
+ cur_alloc_size);
+ /*
+@@ -1504,8 +1503,7 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
+ int *page_started, unsigned long *nr_written)
+ {
+ const bool is_space_ino = btrfs_is_free_space_inode(inode);
+- const bool is_reloc_ino = (inode->root->root_key.objectid ==
+- BTRFS_DATA_RELOC_TREE_OBJECTID);
++ const bool is_reloc_ino = btrfs_is_data_reloc_root(inode->root);
+ const u64 range_bytes = end + 1 - start;
+ struct extent_io_tree *io_tree = &inode->io_tree;
+ u64 range_start = start;
+@@ -1867,8 +1865,7 @@ out_check:
+ btrfs_dec_nocow_writers(fs_info, disk_bytenr);
+ nocow = false;
+
+- if (root->root_key.objectid ==
+- BTRFS_DATA_RELOC_TREE_OBJECTID)
++ if (btrfs_is_data_reloc_root(root))
+ /*
+ * Error handled later, as we must prevent
+ * extent_clear_unlock_delalloc() in error handler
+@@ -1948,7 +1945,15 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
+ const bool zoned = btrfs_is_zoned(inode->root->fs_info);
+
+ if (should_nocow(inode, start, end)) {
+- ASSERT(!zoned);
++ /*
++ * Normally on a zoned device we're only doing COW writes, but
++ * in case of relocation on a zoned filesystem we have taken
++ * precaution, that we're only writing sequentially. It's safe
++ * to use run_delalloc_nocow() here, like for regular
++ * preallocated inodes.
++ */
++ ASSERT(!zoned ||
++ (zoned && btrfs_is_data_reloc_root(inode->root)));
+ ret = run_delalloc_nocow(inode, locked_page, start, end,
+ page_started, nr_written);
+ } else if (!inode_can_compress(inode) ||
+@@ -2207,7 +2212,7 @@ void btrfs_clear_delalloc_extent(struct inode *vfs_inode,
+ if (btrfs_is_testing(fs_info))
+ return;
+
+- if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID &&
++ if (!btrfs_is_data_reloc_root(root) &&
+ do_list && !(state->state & EXTENT_NORESERVE) &&
+ (*bits & EXTENT_CLEAR_DATA_RESV))
+ btrfs_free_reserved_data_space_noquota(fs_info, len);
+@@ -2532,7 +2537,7 @@ blk_status_t btrfs_submit_data_bio(struct inode *inode, struct bio *bio,
+ goto mapit;
+ } else if (async && !skip_sum) {
+ /* csum items have already been cloned */
+- if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
++ if (btrfs_is_data_reloc_root(root))
+ goto mapit;
+ /* we're doing a write, do the async checksumming */
+ ret = btrfs_wq_submit_bio(inode, bio, mirror_num, bio_flags,
+@@ -3304,7 +3309,7 @@ unsigned int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
+ u64 file_offset = pg_off + page_offset(page);
+ int ret;
+
+- if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
++ if (btrfs_is_data_reloc_root(root) &&
+ test_range_bit(io_tree, file_offset,
+ file_offset + sectorsize - 1,
+ EXTENT_NODATASUM, 1, NULL)) {
+@@ -4005,7 +4010,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
+ * without delay
+ */
+ if (!btrfs_is_free_space_inode(inode)
+- && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
++ && !btrfs_is_data_reloc_root(root)
+ && !test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags)) {
+ btrfs_update_root_times(trans, root);
+
+@@ -7962,7 +7967,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
+ iomap->type = IOMAP_MAPPED;
+ }
+ iomap->offset = start;
+- iomap->bdev = fs_info->fs_devices->latest_bdev;
++ iomap->bdev = fs_info->fs_devices->latest_dev->bdev;
+ iomap->length = len;
+
+ if (write && btrfs_use_zone_append(BTRFS_I(inode), em->block_start))
+diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
+index 3dbe6eb5fda75..295bbc13ace6a 100644
+--- a/fs/btrfs/lzo.c
++++ b/fs/btrfs/lzo.c
+@@ -357,9 +357,10 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
+ ASSERT(cur_in / sectorsize ==
+ (cur_in + LZO_LEN - 1) / sectorsize);
+ cur_page = cb->compressed_pages[cur_in / PAGE_SIZE];
+- kaddr = kmap(cur_page);
+ ASSERT(cur_page);
++ kaddr = kmap(cur_page);
+ seg_len = read_compress_length(kaddr + offset_in_page(cur_in));
++ kunmap(cur_page);
+ cur_in += LZO_LEN;
+
+ /* Copy the compressed segment payload into workspace */
+diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
+index 9b0814318e726..c71e49782e86d 100644
+--- a/fs/btrfs/reflink.c
++++ b/fs/btrfs/reflink.c
+@@ -649,7 +649,7 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
+ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
+ struct inode *dst, u64 dst_loff)
+ {
+- int ret;
++ int ret = 0;
+ u64 i, tail_len, chunk_count;
+ struct btrfs_root *root_dst = BTRFS_I(dst)->root;
+
+diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
+index 914d403b4415d..d81bee621d373 100644
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -2852,31 +2852,6 @@ static noinline_for_stack int prealloc_file_extent_cluster(
+ if (ret)
+ return ret;
+
+- /*
+- * On a zoned filesystem, we cannot preallocate the file region.
+- * Instead, we dirty and fiemap_write the region.
+- */
+- if (btrfs_is_zoned(inode->root->fs_info)) {
+- struct btrfs_root *root = inode->root;
+- struct btrfs_trans_handle *trans;
+-
+- end = cluster->end - offset + 1;
+- trans = btrfs_start_transaction(root, 1);
+- if (IS_ERR(trans))
+- return PTR_ERR(trans);
+-
+- inode->vfs_inode.i_ctime = current_time(&inode->vfs_inode);
+- i_size_write(&inode->vfs_inode, end);
+- ret = btrfs_update_inode(trans, root, inode);
+- if (ret) {
+- btrfs_abort_transaction(trans, ret);
+- btrfs_end_transaction(trans);
+- return ret;
+- }
+-
+- return btrfs_end_transaction(trans);
+- }
+-
+ btrfs_inode_lock(&inode->vfs_inode, 0);
+ for (nr = 0; nr < cluster->nr; nr++) {
+ start = cluster->boundary[nr] - offset;
+@@ -3084,7 +3059,6 @@ release_page:
+ static int relocate_file_extent_cluster(struct inode *inode,
+ struct file_extent_cluster *cluster)
+ {
+- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ u64 offset = BTRFS_I(inode)->index_cnt;
+ unsigned long index;
+ unsigned long last_index;
+@@ -3114,8 +3088,6 @@ static int relocate_file_extent_cluster(struct inode *inode,
+ for (index = (cluster->start - offset) >> PAGE_SHIFT;
+ index <= last_index && !ret; index++)
+ ret = relocate_one_page(inode, ra, cluster, &cluster_nr, index);
+- if (btrfs_is_zoned(fs_info) && !ret)
+- ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
+ if (ret == 0)
+ WARN_ON(cluster_nr != cluster->nr);
+ out:
+@@ -3770,12 +3742,8 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path;
+ struct btrfs_inode_item *item;
+ struct extent_buffer *leaf;
+- u64 flags = BTRFS_INODE_NOCOMPRESS | BTRFS_INODE_PREALLOC;
+ int ret;
+
+- if (btrfs_is_zoned(trans->fs_info))
+- flags &= ~BTRFS_INODE_PREALLOC;
+-
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+@@ -3790,7 +3758,8 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
+ btrfs_set_inode_generation(leaf, item, 1);
+ btrfs_set_inode_size(leaf, item, 0);
+ btrfs_set_inode_mode(leaf, item, S_IFREG | 0600);
+- btrfs_set_inode_flags(leaf, item, flags);
++ btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS |
++ BTRFS_INODE_PREALLOC);
+ btrfs_mark_buffer_dirty(leaf);
+ out:
+ btrfs_free_path(path);
+@@ -4386,8 +4355,7 @@ int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+ if (!rc)
+ return 0;
+
+- BUG_ON(rc->stage == UPDATE_DATA_PTRS &&
+- root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
++ BUG_ON(rc->stage == UPDATE_DATA_PTRS && btrfs_is_data_reloc_root(root));
+
+ level = btrfs_header_level(buf);
+ if (btrfs_header_generation(buf) <=
+diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
+index 702dc5441f039..db37a37996497 100644
+--- a/fs/btrfs/root-tree.c
++++ b/fs/btrfs/root-tree.c
+@@ -336,7 +336,8 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
+ key.offset = ref_id;
+ again:
+ ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
+- BUG_ON(ret < 0);
++ if (ret < 0)
++ goto out;
+ if (ret == 0) {
+ leaf = path->nodes[0];
+ ref = btrfs_item_ptr(leaf, path->slots[0],
+diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
+index 088641ba7a8e6..62f4bafbe54bb 100644
+--- a/fs/btrfs/scrub.c
++++ b/fs/btrfs/scrub.c
+@@ -73,8 +73,8 @@ struct scrub_page {
+ u64 physical_for_dev_replace;
+ atomic_t refs;
+ u8 mirror_num;
+- int have_csum:1;
+- int io_error:1;
++ unsigned int have_csum:1;
++ unsigned int io_error:1;
+ u8 csum[BTRFS_CSUM_SIZE];
+
+ struct scrub_recover *recover;
+diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
+index 537d90bf5d844..7f91d62c2225a 100644
+--- a/fs/btrfs/super.c
++++ b/fs/btrfs/super.c
+@@ -1705,7 +1705,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
+ goto error_close_devices;
+ }
+
+- bdev = fs_devices->latest_bdev;
++ bdev = fs_devices->latest_dev->bdev;
+ s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
+ fs_info);
+ if (IS_ERR(s)) {
+@@ -2463,30 +2463,16 @@ static int btrfs_unfreeze(struct super_block *sb)
+ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
+ {
+ struct btrfs_fs_info *fs_info = btrfs_sb(root->d_sb);
+- struct btrfs_device *dev, *first_dev = NULL;
+
+ /*
+- * Lightweight locking of the devices. We should not need
+- * device_list_mutex here as we only read the device data and the list
+- * is protected by RCU. Even if a device is deleted during the list
+- * traversals, we'll get valid data, the freeing callback will wait at
+- * least until the rcu_read_unlock.
++ * There should be always a valid pointer in latest_dev, it may be stale
++ * for a short moment in case it's being deleted but still valid until
++ * the end of RCU grace period.
+ */
+ rcu_read_lock();
+- list_for_each_entry_rcu(dev, &fs_info->fs_devices->devices, dev_list) {
+- if (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state))
+- continue;
+- if (!dev->name)
+- continue;
+- if (!first_dev || dev->devid < first_dev->devid)
+- first_dev = dev;
+- }
+-
+- if (first_dev)
+- seq_escape(m, rcu_str_deref(first_dev->name), " \t\n\\");
+- else
+- WARN_ON(1);
++ seq_escape(m, rcu_str_deref(fs_info->fs_devices->latest_dev->name), " \t\n\\");
+ rcu_read_unlock();
++
+ return 0;
+ }
+
+diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
+index b415c5ec03ea0..b79da8917cbfa 100644
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -1153,6 +1153,7 @@ again:
+ parent_objectid, victim_name,
+ victim_name_len);
+ if (ret < 0) {
++ kfree(victim_name);
+ return ret;
+ } else if (!ret) {
+ ret = -ENOENT;
+@@ -2500,7 +2501,9 @@ again:
+ else {
+ ret = find_dir_range(log, path, dirid, key_type,
+ &range_start, &range_end);
+- if (ret != 0)
++ if (ret < 0)
++ goto out;
++ else if (ret > 0)
+ break;
+ }
+
+@@ -2877,6 +2880,8 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
+ path->nodes[*level]->len);
+ if (ret)
+ return ret;
++ btrfs_redirty_list_add(trans->transaction,
++ next);
+ } else {
+ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+ clear_extent_buffer_dirty(next);
+@@ -2957,6 +2962,7 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
+ next->start, next->len);
+ if (ret)
+ goto out;
++ btrfs_redirty_list_add(trans->transaction, next);
+ } else {
+ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+ clear_extent_buffer_dirty(next);
+@@ -3410,8 +3416,6 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
+ EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
+ extent_io_tree_release(&log->log_csum_range);
+
+- if (trans && log->node)
+- btrfs_redirty_list_add(trans->transaction, log->node);
+ btrfs_put_root(log);
+ }
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 2ec3b8ac8fa35..c34efdc1ecddb 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -14,6 +14,7 @@
+ #include <linux/semaphore.h>
+ #include <linux/uuid.h>
+ #include <linux/list_sort.h>
++#include <linux/namei.h>
+ #include "misc.h"
+ #include "ctree.h"
+ #include "extent_map.h"
+@@ -1091,7 +1092,7 @@ void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices)
+ list_for_each_entry(seed_dev, &fs_devices->seed_list, seed_list)
+ __btrfs_free_extra_devids(seed_dev, &latest_dev);
+
+- fs_devices->latest_bdev = latest_dev->bdev;
++ fs_devices->latest_dev = latest_dev;
+
+ mutex_unlock(&uuid_mutex);
+ }
+@@ -1122,8 +1123,10 @@ static void btrfs_close_one_device(struct btrfs_device *device)
+ if (device->devid == BTRFS_DEV_REPLACE_DEVID)
+ clear_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
+
+- if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
++ if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) {
++ clear_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
+ fs_devices->missing_devices--;
++ }
+
+ btrfs_close_bdev(device);
+ if (device->bdev) {
+@@ -1222,7 +1225,7 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
+ return -EINVAL;
+
+ fs_devices->opened = 1;
+- fs_devices->latest_bdev = latest_dev->bdev;
++ fs_devices->latest_dev = latest_dev;
+ fs_devices->total_rw_bytes = 0;
+ fs_devices->chunk_alloc_policy = BTRFS_CHUNK_ALLOC_REGULAR;
+ fs_devices->read_policy = BTRFS_READ_POLICY_PID;
+@@ -1363,8 +1366,10 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags,
+
+ bytenr_orig = btrfs_sb_offset(0);
+ ret = btrfs_sb_log_location_bdev(bdev, 0, READ, &bytenr);
+- if (ret)
+- return ERR_PTR(ret);
++ if (ret) {
++ device = ERR_PTR(ret);
++ goto error_bdev_put;
++ }
+
+ disk_super = btrfs_read_disk_super(bdev, bytenr, bytenr_orig);
+ if (IS_ERR(disk_super)) {
+@@ -1882,18 +1887,22 @@ out:
+ /*
+ * Function to update ctime/mtime for a given device path.
+ * Mainly used for ctime/mtime based probe like libblkid.
++ *
++ * We don't care about errors here, this is just to be kind to userspace.
+ */
+-static void update_dev_time(struct block_device *bdev)
++static void update_dev_time(const char *device_path)
+ {
+- struct inode *inode = bdev->bd_inode;
++ struct path path;
+ struct timespec64 now;
++ int ret;
+
+- /* Shouldn't happen but just in case. */
+- if (!inode)
++ ret = kern_path(device_path, LOOKUP_FOLLOW, &path);
++ if (ret)
+ return;
+
+- now = current_time(inode);
+- generic_update_time(inode, &now, S_MTIME | S_CTIME);
++ now = current_time(d_inode(path.dentry));
++ inode_update_time(d_inode(path.dentry), &now, S_MTIME | S_CTIME);
++ path_put(&path);
+ }
+
+ static int btrfs_rm_dev_item(struct btrfs_device *device)
+@@ -1986,7 +1995,7 @@ static struct btrfs_device * btrfs_find_next_active_device(
+ }
+
+ /*
+- * Helper function to check if the given device is part of s_bdev / latest_bdev
++ * Helper function to check if the given device is part of s_bdev / latest_dev
+ * and replace it with the provided or the next active device, in the context
+ * where this function called, there should be always be another device (or
+ * this_dev) which is active.
+@@ -2005,8 +2014,8 @@ void __cold btrfs_assign_next_active_device(struct btrfs_device *device,
+ (fs_info->sb->s_bdev == device->bdev))
+ fs_info->sb->s_bdev = next_device->bdev;
+
+- if (fs_info->fs_devices->latest_bdev == device->bdev)
+- fs_info->fs_devices->latest_bdev = next_device->bdev;
++ if (fs_info->fs_devices->latest_dev->bdev == device->bdev)
++ fs_info->fs_devices->latest_dev = next_device;
+ }
+
+ /*
+@@ -2069,7 +2078,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+ btrfs_kobject_uevent(bdev, KOBJ_CHANGE);
+
+ /* Update ctime/mtime for device path for libblkid */
+- update_dev_time(bdev);
++ update_dev_time(device_path);
+ }
+
+ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+@@ -2081,8 +2090,11 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+ u64 num_devices;
+ int ret = 0;
+
+- mutex_lock(&uuid_mutex);
+-
++ /*
++ * The device list in fs_devices is accessed without locks (neither
++ * uuid_mutex nor device_list_mutex) as it won't change on a mounted
++ * filesystem and another device rm cannot run.
++ */
+ num_devices = btrfs_num_devices(fs_info);
+
+ ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1);
+@@ -2126,11 +2138,9 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+ mutex_unlock(&fs_info->chunk_mutex);
+ }
+
+- mutex_unlock(&uuid_mutex);
+ ret = btrfs_shrink_device(device, 0);
+ if (!ret)
+ btrfs_reada_remove_dev(device);
+- mutex_lock(&uuid_mutex);
+ if (ret)
+ goto error_undo;
+
+@@ -2217,7 +2227,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+ }
+
+ out:
+- mutex_unlock(&uuid_mutex);
+ return ret;
+
+ error_undo:
+@@ -2305,13 +2314,6 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
+
+ mutex_unlock(&fs_devices->device_list_mutex);
+
+- /*
+- * The update_dev_time() with in btrfs_scratch_superblocks()
+- * may lead to a call to btrfs_show_devname() which will try
+- * to hold device_list_mutex. And here this device
+- * is already out of device list, so we don't have to hold
+- * the device_list_mutex lock.
+- */
+ btrfs_scratch_superblocks(tgtdev->fs_info, tgtdev->bdev,
+ tgtdev->name->str);
+
+@@ -2627,6 +2629,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
+ btrfs_abort_transaction(trans, ret);
+ goto error_trans;
+ }
++ btrfs_assign_next_active_device(fs_info->fs_devices->latest_dev,
++ device);
+ }
+
+ device->fs_devices = fs_devices;
+@@ -2733,7 +2737,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
+ btrfs_forget_devices(device_path);
+
+ /* Update ctime/mtime for blkid or udev */
+- update_dev_time(bdev);
++ update_dev_time(device_path);
+
+ return ret;
+
+@@ -7481,6 +7485,19 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
+ */
+ fs_info->fs_devices->total_rw_bytes = 0;
+
++ /*
++ * Lockdep complains about possible circular locking dependency between
++ * a disk's open_mutex (struct gendisk.open_mutex), the rw semaphores
++ * used for freeze procection of a fs (struct super_block.s_writers),
++ * which we take when starting a transaction, and extent buffers of the
++ * chunk tree if we call read_one_dev() while holding a lock on an
++ * extent buffer of the chunk tree. Since we are mounting the filesystem
++ * and at this point there can't be any concurrent task modifying the
++ * chunk tree, to keep it simple, just skip locking on the chunk tree.
++ */
++ ASSERT(!test_bit(BTRFS_FS_OPEN, &fs_info->flags));
++ path->skip_locking = 1;
++
+ /*
+ * Read all device items, and then all the chunk items. All
+ * device items are found before any chunk item (their object id
+@@ -7506,10 +7523,6 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
+ goto error;
+ break;
+ }
+- /*
+- * The nodes on level 1 are not locked but we don't need to do
+- * that during mount time as nothing else can access the tree
+- */
+ node = path->nodes[1];
+ if (node) {
+ if (last_ra_node != node->start) {
+@@ -7537,7 +7550,6 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
+ * requirement for chunk allocation, see the comment on
+ * top of btrfs_chunk_alloc() for details.
+ */
+- ASSERT(!test_bit(BTRFS_FS_OPEN, &fs_info->flags));
+ chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
+ ret = read_one_chunk(&found_key, leaf, chunk);
+ if (ret)
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index 2183361db614d..4db10d071d67f 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -246,7 +246,11 @@ struct btrfs_fs_devices {
+ /* Highest generation number of seen devices */
+ u64 latest_generation;
+
+- struct block_device *latest_bdev;
++ /*
++ * The mount device or a device with highest generation after removal
++ * or replace.
++ */
++ struct btrfs_device *latest_dev;
+
+ /* all of the devices in the FS, protected by a mutex
+ * so we can safely walk it to write out the supers without
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 47af1ab3bf120..5672c24a2d582 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -1304,6 +1304,17 @@ bool btrfs_use_zone_append(struct btrfs_inode *inode, u64 start)
+ if (!is_data_inode(&inode->vfs_inode))
+ return false;
+
++ /*
++ * Using REQ_OP_ZONE_APPNED for relocation can break assumptions on the
++ * extent layout the relocation code has.
++ * Furthermore we have set aside own block-group from which only the
++ * relocation "process" can allocate and make sure only one process at a
++ * time can add pages to an extent that gets relocated, so it's safe to
++ * use regular REQ_OP_WRITE for this special case.
++ */
++ if (btrfs_is_data_reloc_root(inode->root))
++ return false;
++
+ cache = btrfs_lookup_block_group(fs_info, start);
+ ASSERT(cache);
+ if (!cache)
+@@ -1530,3 +1541,13 @@ struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
+
+ return device;
+ }
++
++void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg)
++{
++ struct btrfs_fs_info *fs_info = bg->fs_info;
++
++ spin_lock(&fs_info->relocation_bg_lock);
++ if (fs_info->data_reloc_bg == bg->start)
++ fs_info->data_reloc_bg = 0;
++ spin_unlock(&fs_info->relocation_bg_lock);
++}
+diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
+index 4b299705bb12b..70b3be517599f 100644
+--- a/fs/btrfs/zoned.h
++++ b/fs/btrfs/zoned.h
+@@ -66,6 +66,7 @@ int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
+ u64 physical_start, u64 physical_pos);
+ struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
+ u64 logical, u64 length);
++void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg);
+ #else /* CONFIG_BLK_DEV_ZONED */
+ static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
+ struct blk_zone *zone)
+@@ -199,6 +200,8 @@ static inline struct btrfs_device *btrfs_zoned_get_device(
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
++static inline void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg) { }
++
+ #endif
+
+ static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)
+diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
+index 8f537f1d9d1d3..8be4da2e2b826 100644
+--- a/fs/ceph/caps.c
++++ b/fs/ceph/caps.c
+@@ -4349,7 +4349,7 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
+ {
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(ci->vfs_inode.i_sb);
+ int bits = (fmode << 1) | 1;
+- bool is_opened = false;
++ bool already_opened = false;
+ int i;
+
+ if (count == 1)
+@@ -4357,19 +4357,19 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
+
+ spin_lock(&ci->i_ceph_lock);
+ for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
+- if (bits & (1 << i))
+- ci->i_nr_by_mode[i] += count;
+-
+ /*
+- * If any of the mode ref is larger than 1,
++ * If any of the mode ref is larger than 0,
+ * that means it has been already opened by
+ * others. Just skip checking the PIN ref.
+ */
+- if (i && ci->i_nr_by_mode[i] > 1)
+- is_opened = true;
++ if (i && ci->i_nr_by_mode[i])
++ already_opened = true;
++
++ if (bits & (1 << i))
++ ci->i_nr_by_mode[i] += count;
+ }
+
+- if (!is_opened)
++ if (!already_opened)
+ percpu_counter_inc(&mdsc->metric.opened_inodes);
+ spin_unlock(&ci->i_ceph_lock);
+ }
+diff --git a/fs/ceph/file.c b/fs/ceph/file.c
+index e61018d9764ee..e873c2ba7a7ff 100644
+--- a/fs/ceph/file.c
++++ b/fs/ceph/file.c
+@@ -603,13 +603,25 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
+ in.cap.realm = cpu_to_le64(ci->i_snap_realm->ino);
+ in.cap.flags = CEPH_CAP_FLAG_AUTH;
+ in.ctime = in.mtime = in.atime = iinfo.btime;
+- in.mode = cpu_to_le32((u32)mode);
+ in.truncate_seq = cpu_to_le32(1);
+ in.truncate_size = cpu_to_le64(-1ULL);
+ in.xattr_version = cpu_to_le64(1);
+ in.uid = cpu_to_le32(from_kuid(&init_user_ns, current_fsuid()));
+- in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_mode & S_ISGID ?
+- dir->i_gid : current_fsgid()));
++ if (dir->i_mode & S_ISGID) {
++ in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_gid));
++
++ /* Directories always inherit the setgid bit. */
++ if (S_ISDIR(mode))
++ mode |= S_ISGID;
++ else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
++ !in_group_p(dir->i_gid) &&
++ !capable_wrt_inode_uidgid(&init_user_ns, dir, CAP_FSETID))
++ mode &= ~S_ISGID;
++ } else {
++ in.gid = cpu_to_le32(from_kgid(&init_user_ns, current_fsgid()));
++ }
++ in.mode = cpu_to_le32((u32)mode);
++
+ in.nlink = cpu_to_le32(1);
+ in.max_size = cpu_to_le64(lo->stripe_unit);
+
+diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
+index d64413adc0fd2..e9409c460acd0 100644
+--- a/fs/ceph/mds_client.c
++++ b/fs/ceph/mds_client.c
+@@ -3772,7 +3772,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap,
+ struct ceph_pagelist *pagelist = recon_state->pagelist;
+ struct dentry *dentry;
+ char *path;
+- int pathlen, err;
++ int pathlen = 0, err;
+ u64 pathbase;
+ u64 snap_follows;
+
+@@ -3792,7 +3792,6 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap,
+ }
+ } else {
+ path = NULL;
+- pathlen = 0;
+ pathbase = 0;
+ }
+
+diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
+index 61d67cbcb3671..30387733765d5 100644
+--- a/fs/ceph/mdsmap.c
++++ b/fs/ceph/mdsmap.c
+@@ -263,10 +263,6 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end, bool msgr2)
+ goto nomem;
+ for (j = 0; j < num_export_targets; j++) {
+ target = ceph_decode_32(&pexport_targets);
+- if (target >= m->possible_max_rank) {
+- err = -EIO;
+- goto corrupt;
+- }
+ info->export_targets[j] = target;
+ }
+ } else {
+diff --git a/fs/ceph/super.c b/fs/ceph/super.c
+index fd8742bae8471..202ddde3d62ad 100644
+--- a/fs/ceph/super.c
++++ b/fs/ceph/super.c
+@@ -52,8 +52,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
+ struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
+ struct ceph_mon_client *monc = &fsc->client->monc;
+ struct ceph_statfs st;
+- u64 fsid;
+- int err;
++ int i, err;
+ u64 data_pool;
+
+ if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) {
+@@ -99,12 +98,14 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
+ buf->f_namelen = NAME_MAX;
+
+ /* Must convert the fsid, for consistent values across arches */
++ buf->f_fsid.val[0] = 0;
+ mutex_lock(&monc->mutex);
+- fsid = le64_to_cpu(*(__le64 *)(&monc->monmap->fsid)) ^
+- le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1));
++ for (i = 0 ; i < sizeof(monc->monmap->fsid) / sizeof(__le32) ; ++i)
++ buf->f_fsid.val[0] ^= le32_to_cpu(((__le32 *)&monc->monmap->fsid)[i]);
+ mutex_unlock(&monc->mutex);
+
+- buf->f_fsid = u64_to_fsid(fsid);
++ /* fold the fs_cluster_id into the upper bits */
++ buf->f_fsid.val[1] = monc->fs_cluster_id;
+
+ return 0;
+ }
+diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
+index de2c12bcfa4bc..905a901f7f80b 100644
+--- a/fs/cifs/cifs_debug.c
++++ b/fs/cifs/cifs_debug.c
+@@ -358,6 +358,8 @@ skip_rdma:
+ seq_printf(m, " signed");
+ if (server->posix_ext_supported)
+ seq_printf(m, " posix");
++ if (server->nosharesock)
++ seq_printf(m, " nosharesock");
+
+ if (server->rdma)
+ seq_printf(m, "\nRDMA ");
+diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
+index e916470468ea9..3e5b8e177cfa7 100644
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -74,7 +74,8 @@
+ #define SMB_ECHO_INTERVAL_MAX 600
+ #define SMB_ECHO_INTERVAL_DEFAULT 60
+
+-/* dns resolution interval in seconds */
++/* dns resolution intervals in seconds */
++#define SMB_DNS_RESOLVE_INTERVAL_MIN 120
+ #define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
+
+ /* maximum number of PDUs in one compound */
+@@ -591,6 +592,7 @@ struct TCP_Server_Info {
+ struct list_head pending_mid_q;
+ bool noblocksnd; /* use blocking sendmsg */
+ bool noautotune; /* do not autotune send buf sizes */
++ bool nosharesock;
+ bool tcp_nodelay;
+ unsigned int credits; /* send no more requests at once */
+ unsigned int max_credits; /* can override large 32000 default at mnt */
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index c3b94c1e45913..439f02f1886c1 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -115,7 +115,7 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
+ * To make sure we don't use the cached entry, retry 1s
+ * after expiry.
+ */
+- ttl = (expiry - now + 1);
++ ttl = max_t(unsigned long, expiry - now, SMB_DNS_RESOLVE_INTERVAL_MIN) + 1;
+ }
+ rc = !rc ? -1 : 0;
+
+@@ -794,7 +794,6 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
+ */
+ }
+
+- kfree(server->hostname);
+ kfree(server);
+
+ length = atomic_dec_return(&tcpSesAllocCount);
+@@ -1221,6 +1220,10 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
+ if (ctx->nosharesock)
+ return 0;
+
++ /* this server does not share socket */
++ if (server->nosharesock)
++ return 0;
++
+ /* If multidialect negotiation see if existing sessions match one */
+ if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
+ if (server->vals->protocol_id < SMB30_PROT_ID)
+@@ -1235,6 +1238,9 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
+ if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
+ return 0;
+
++ if (strcasecmp(server->hostname, ctx->server_hostname))
++ return 0;
++
+ if (!match_address(server, addr,
+ (struct sockaddr *)&ctx->srcaddr))
+ return 0;
+@@ -1336,6 +1342,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
+ kfree(server->session_key.response);
+ server->session_key.response = NULL;
+ server->session_key.len = 0;
++ kfree(server->hostname);
+
+ task = xchg(&server->tsk, NULL);
+ if (task)
+@@ -1361,14 +1368,18 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
+ goto out_err;
+ }
+
++ tcp_ses->hostname = kstrdup(ctx->server_hostname, GFP_KERNEL);
++ if (!tcp_ses->hostname) {
++ rc = -ENOMEM;
++ goto out_err;
++ }
++
++ if (ctx->nosharesock)
++ tcp_ses->nosharesock = true;
++
+ tcp_ses->ops = ctx->ops;
+ tcp_ses->vals = ctx->vals;
+ cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
+- tcp_ses->hostname = extract_hostname(ctx->UNC);
+- if (IS_ERR(tcp_ses->hostname)) {
+- rc = PTR_ERR(tcp_ses->hostname);
+- goto out_err_crypto_release;
+- }
+
+ tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId);
+ tcp_ses->noblockcnt = ctx->rootfs;
+@@ -1497,8 +1508,7 @@ out_err_crypto_release:
+
+ out_err:
+ if (tcp_ses) {
+- if (!IS_ERR(tcp_ses->hostname))
+- kfree(tcp_ses->hostname);
++ kfree(tcp_ses->hostname);
+ if (tcp_ses->ssocket)
+ sock_release(tcp_ses->ssocket);
+ kfree(tcp_ses);
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index 13f3182cf7969..82bbaf8e92b79 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -2692,12 +2692,23 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
+ tcon = tlink_tcon(smbfile->tlink);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ server = tcon->ses->server;
+- if (server->ops->flush)
+- rc = server->ops->flush(xid, tcon, &smbfile->fid);
+- else
++ if (server->ops->flush == NULL) {
+ rc = -ENOSYS;
++ goto strict_fsync_exit;
++ }
++
++ if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
++ smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
++ if (smbfile) {
++ rc = server->ops->flush(xid, tcon, &smbfile->fid);
++ cifsFileInfo_put(smbfile);
++ } else
++ cifs_dbg(FYI, "ignore fsync for file not open for write\n");
++ } else
++ rc = server->ops->flush(xid, tcon, &smbfile->fid);
+ }
+
++strict_fsync_exit:
+ free_xid(xid);
+ return rc;
+ }
+@@ -2709,6 +2720,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ struct cifsFileInfo *smbfile = file->private_data;
++ struct inode *inode = file_inode(file);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+
+ rc = file_write_and_wait_range(file, start, end);
+@@ -2725,12 +2737,23 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ tcon = tlink_tcon(smbfile->tlink);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ server = tcon->ses->server;
+- if (server->ops->flush)
+- rc = server->ops->flush(xid, tcon, &smbfile->fid);
+- else
++ if (server->ops->flush == NULL) {
+ rc = -ENOSYS;
++ goto fsync_exit;
++ }
++
++ if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
++ smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
++ if (smbfile) {
++ rc = server->ops->flush(xid, tcon, &smbfile->fid);
++ cifsFileInfo_put(smbfile);
++ } else
++ cifs_dbg(FYI, "ignore fsync for file not open for write\n");
++ } else
++ rc = server->ops->flush(xid, tcon, &smbfile->fid);
+ }
+
++fsync_exit:
+ free_xid(xid);
+ return rc;
+ }
+diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c
+index 3109def8e1998..0a2542286552f 100644
+--- a/fs/cifs/fs_context.c
++++ b/fs/cifs/fs_context.c
+@@ -307,6 +307,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
+ new_ctx->nodename = NULL;
+ new_ctx->username = NULL;
+ new_ctx->password = NULL;
++ new_ctx->server_hostname = NULL;
+ new_ctx->domainname = NULL;
+ new_ctx->UNC = NULL;
+ new_ctx->source = NULL;
+@@ -318,6 +319,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
+ DUP_CTX_STR(mount_options);
+ DUP_CTX_STR(username);
+ DUP_CTX_STR(password);
++ DUP_CTX_STR(server_hostname);
+ DUP_CTX_STR(UNC);
+ DUP_CTX_STR(source);
+ DUP_CTX_STR(domainname);
+@@ -429,6 +431,42 @@ out:
+ return rc;
+ }
+
++/*
++ * Remove duplicate path delimiters. Windows is supposed to do that
++ * but there are some bugs that prevent rename from working if there are
++ * multiple delimiters.
++ *
++ * Returns a sanitized duplicate of @path. The caller is responsible for
++ * cleaning up the original.
++ */
++#define IS_DELIM(c) ((c) == '/' || (c) == '\\')
++static char *sanitize_path(char *path)
++{
++ char *cursor1 = path, *cursor2 = path;
++
++ /* skip all prepended delimiters */
++ while (IS_DELIM(*cursor1))
++ cursor1++;
++
++ /* copy the first letter */
++ *cursor2 = *cursor1;
++
++ /* copy the remainder... */
++ while (*(cursor1++)) {
++ /* ... skipping all duplicated delimiters */
++ if (IS_DELIM(*cursor1) && IS_DELIM(*cursor2))
++ continue;
++ *(++cursor2) = *cursor1;
++ }
++
++ /* if the last character is a delimiter, skip it */
++ if (IS_DELIM(*(cursor2 - 1)))
++ cursor2--;
++
++ *(cursor2) = '\0';
++ return kstrdup(path, GFP_KERNEL);
++}
++
+ /*
+ * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
+ * fields with the result. Returns 0 on success and an error otherwise
+@@ -456,6 +494,12 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
+ if (!pos)
+ return -EINVAL;
+
++ /* record the server hostname */
++ kfree(ctx->server_hostname);
++ ctx->server_hostname = kstrndup(devname + 2, pos - devname - 2, GFP_KERNEL);
++ if (!ctx->server_hostname)
++ return -ENOMEM;
++
+ /* skip past delimiter */
+ ++pos;
+
+@@ -482,7 +526,7 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
+ if (!*pos)
+ return 0;
+
+- ctx->prepath = kstrdup(pos, GFP_KERNEL);
++ ctx->prepath = sanitize_path(pos);
+ if (!ctx->prepath)
+ return -ENOMEM;
+
+@@ -1496,6 +1540,8 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
+ ctx->username = NULL;
+ kfree_sensitive(ctx->password);
+ ctx->password = NULL;
++ kfree(ctx->server_hostname);
++ ctx->server_hostname = NULL;
+ kfree(ctx->UNC);
+ ctx->UNC = NULL;
+ kfree(ctx->source);
+diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h
+index a42ba71d7a81f..29601a4eb4116 100644
+--- a/fs/cifs/fs_context.h
++++ b/fs/cifs/fs_context.h
+@@ -166,6 +166,7 @@ struct smb3_fs_context {
+ char *password;
+ char *domainname;
+ char *source;
++ char *server_hostname;
+ char *UNC;
+ char *nodename;
+ char *iocharset; /* local code page for mapping to and from Unicode */
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 3fa965eb3336d..cb25ef0cdf1f3 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -549,8 +549,9 @@ int __init fscrypt_init_keyring(void);
+ struct fscrypt_mode {
+ const char *friendly_name;
+ const char *cipher_str;
+- int keysize;
+- int ivsize;
++ int keysize; /* key size in bytes */
++ int security_strength; /* security strength in bytes */
++ int ivsize; /* IV size in bytes */
+ int logged_impl_name;
+ enum blk_crypto_mode_num blk_crypto_mode;
+ };
+diff --git a/fs/crypto/hkdf.c b/fs/crypto/hkdf.c
+index e0ec210555053..7607d18b35fc0 100644
+--- a/fs/crypto/hkdf.c
++++ b/fs/crypto/hkdf.c
+@@ -16,9 +16,14 @@
+
+ /*
+ * HKDF supports any unkeyed cryptographic hash algorithm, but fscrypt uses
+- * SHA-512 because it is reasonably secure and efficient; and since it produces
+- * a 64-byte digest, deriving an AES-256-XTS key preserves all 64 bytes of
+- * entropy from the master key and requires only one iteration of HKDF-Expand.
++ * SHA-512 because it is well-established, secure, and reasonably efficient.
++ *
++ * HKDF-SHA256 was also considered, as its 256-bit security strength would be
++ * sufficient here. A 512-bit security strength is "nice to have", though.
++ * Also, on 64-bit CPUs, SHA-512 is usually just as fast as SHA-256. In the
++ * common case of deriving an AES-256-XTS key (512 bits), that can result in
++ * HKDF-SHA512 being much faster than HKDF-SHA256, as the longer digest size of
++ * SHA-512 causes HKDF-Expand to only need to do one iteration rather than two.
+ */
+ #define HKDF_HMAC_ALG "hmac(sha512)"
+ #define HKDF_HASHLEN SHA512_DIGEST_SIZE
+diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
+index bca9c6658a7c5..89cd533a88bff 100644
+--- a/fs/crypto/keysetup.c
++++ b/fs/crypto/keysetup.c
+@@ -19,6 +19,7 @@ struct fscrypt_mode fscrypt_modes[] = {
+ .friendly_name = "AES-256-XTS",
+ .cipher_str = "xts(aes)",
+ .keysize = 64,
++ .security_strength = 32,
+ .ivsize = 16,
+ .blk_crypto_mode = BLK_ENCRYPTION_MODE_AES_256_XTS,
+ },
+@@ -26,12 +27,14 @@ struct fscrypt_mode fscrypt_modes[] = {
+ .friendly_name = "AES-256-CTS-CBC",
+ .cipher_str = "cts(cbc(aes))",
+ .keysize = 32,
++ .security_strength = 32,
+ .ivsize = 16,
+ },
+ [FSCRYPT_MODE_AES_128_CBC] = {
+ .friendly_name = "AES-128-CBC-ESSIV",
+ .cipher_str = "essiv(cbc(aes),sha256)",
+ .keysize = 16,
++ .security_strength = 16,
+ .ivsize = 16,
+ .blk_crypto_mode = BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV,
+ },
+@@ -39,12 +42,14 @@ struct fscrypt_mode fscrypt_modes[] = {
+ .friendly_name = "AES-128-CTS-CBC",
+ .cipher_str = "cts(cbc(aes))",
+ .keysize = 16,
++ .security_strength = 16,
+ .ivsize = 16,
+ },
+ [FSCRYPT_MODE_ADIANTUM] = {
+ .friendly_name = "Adiantum",
+ .cipher_str = "adiantum(xchacha12,aes)",
+ .keysize = 32,
++ .security_strength = 32,
+ .ivsize = 32,
+ .blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM,
+ },
+@@ -357,6 +362,45 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
+ return 0;
+ }
+
++/*
++ * Check whether the size of the given master key (@mk) is appropriate for the
++ * encryption settings which a particular file will use (@ci).
++ *
++ * If the file uses a v1 encryption policy, then the master key must be at least
++ * as long as the derived key, as this is a requirement of the v1 KDF.
++ *
++ * Otherwise, the KDF can accept any size key, so we enforce a slightly looser
++ * requirement: we require that the size of the master key be at least the
++ * maximum security strength of any algorithm whose key will be derived from it
++ * (but in practice we only need to consider @ci->ci_mode, since any other
++ * possible subkeys such as DIRHASH and INODE_HASH will never increase the
++ * required key size over @ci->ci_mode). This allows AES-256-XTS keys to be
++ * derived from a 256-bit master key, which is cryptographically sufficient,
++ * rather than requiring a 512-bit master key which is unnecessarily long. (We
++ * still allow 512-bit master keys if the user chooses to use them, though.)
++ */
++static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk,
++ const struct fscrypt_info *ci)
++{
++ unsigned int min_keysize;
++
++ if (ci->ci_policy.version == FSCRYPT_POLICY_V1)
++ min_keysize = ci->ci_mode->keysize;
++ else
++ min_keysize = ci->ci_mode->security_strength;
++
++ if (mk->mk_secret.size < min_keysize) {
++ fscrypt_warn(NULL,
++ "key with %s %*phN is too short (got %u bytes, need %u+ bytes)",
++ master_key_spec_type(&mk->mk_spec),
++ master_key_spec_len(&mk->mk_spec),
++ (u8 *)&mk->mk_spec.u,
++ mk->mk_secret.size, min_keysize);
++ return false;
++ }
++ return true;
++}
++
+ /*
+ * Find the master key, then set up the inode's actual encryption key.
+ *
+@@ -422,18 +466,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
+ goto out_release_key;
+ }
+
+- /*
+- * Require that the master key be at least as long as the derived key.
+- * Otherwise, the derived key cannot possibly contain as much entropy as
+- * that required by the encryption mode it will be used for. For v1
+- * policies it's also required for the KDF to work at all.
+- */
+- if (mk->mk_secret.size < ci->ci_mode->keysize) {
+- fscrypt_warn(NULL,
+- "key with %s %*phN is too short (got %u bytes, need %u+ bytes)",
+- master_key_spec_type(&mk_spec),
+- master_key_spec_len(&mk_spec), (u8 *)&mk_spec.u,
+- mk->mk_secret.size, ci->ci_mode->keysize);
++ if (!fscrypt_valid_master_key_size(mk, ci)) {
+ err = -ENOKEY;
+ goto out_release_key;
+ }
+diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
+index a5bc4b1b7813e..ad3f31380e6b2 100644
+--- a/fs/erofs/decompressor.c
++++ b/fs/erofs/decompressor.c
+@@ -233,7 +233,6 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
+ erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
+ ret, rq->inputsize, inputmargin, rq->outputsize);
+
+- WARN_ON(1);
+ print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
+ 16, 1, src + inputmargin, rq->inputsize, true);
+ print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
+diff --git a/fs/erofs/utils.c b/fs/erofs/utils.c
+index bd86067a63f7f..3ca703cd5b24a 100644
+--- a/fs/erofs/utils.c
++++ b/fs/erofs/utils.c
+@@ -141,7 +141,7 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
+ * however in order to avoid some race conditions, add a
+ * DBG_BUGON to observe this in advance.
+ */
+- DBG_BUGON(xa_erase(&sbi->managed_pslots, grp->index) != grp);
++ DBG_BUGON(__xa_erase(&sbi->managed_pslots, grp->index) != grp);
+
+ /* last refcount should be connected with its managed pslot. */
+ erofs_workgroup_unfreeze(grp, 0);
+@@ -156,15 +156,19 @@ static unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
+ unsigned int freed = 0;
+ unsigned long index;
+
++ xa_lock(&sbi->managed_pslots);
+ xa_for_each(&sbi->managed_pslots, index, grp) {
+ /* try to shrink each valid workgroup */
+ if (!erofs_try_to_release_workgroup(sbi, grp))
+ continue;
++ xa_unlock(&sbi->managed_pslots);
+
+ ++freed;
+ if (!--nr_shrink)
+- break;
++ return freed;
++ xa_lock(&sbi->managed_pslots);
+ }
++ xa_unlock(&sbi->managed_pslots);
+ return freed;
+ }
+
+diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
+index 11c7a1aaebade..eb51df4a9f770 100644
+--- a/fs/erofs/zdata.c
++++ b/fs/erofs/zdata.c
+@@ -373,8 +373,8 @@ static bool z_erofs_try_inplace_io(struct z_erofs_collector *clt,
+
+ /* callers must be with collection lock held */
+ static int z_erofs_attach_page(struct z_erofs_collector *clt,
+- struct page *page,
+- enum z_erofs_page_type type)
++ struct page *page, enum z_erofs_page_type type,
++ bool pvec_safereuse)
+ {
+ int ret;
+
+@@ -384,9 +384,9 @@ static int z_erofs_attach_page(struct z_erofs_collector *clt,
+ z_erofs_try_inplace_io(clt, page))
+ return 0;
+
+- ret = z_erofs_pagevec_enqueue(&clt->vector, page, type);
++ ret = z_erofs_pagevec_enqueue(&clt->vector, page, type,
++ pvec_safereuse);
+ clt->cl->vcnt += (unsigned int)ret;
+-
+ return ret ? 0 : -EAGAIN;
+ }
+
+@@ -729,7 +729,8 @@ hitted:
+ tight &= (clt->mode >= COLLECT_PRIMARY_FOLLOWED);
+
+ retry:
+- err = z_erofs_attach_page(clt, page, page_type);
++ err = z_erofs_attach_page(clt, page, page_type,
++ clt->mode >= COLLECT_PRIMARY_FOLLOWED);
+ /* should allocate an additional short-lived page for pagevec */
+ if (err == -EAGAIN) {
+ struct page *const newpage =
+@@ -737,7 +738,7 @@ retry:
+
+ set_page_private(newpage, Z_EROFS_SHORTLIVED_PAGE);
+ err = z_erofs_attach_page(clt, newpage,
+- Z_EROFS_PAGE_TYPE_EXCLUSIVE);
++ Z_EROFS_PAGE_TYPE_EXCLUSIVE, true);
+ if (!err)
+ goto retry;
+ }
+diff --git a/fs/erofs/zpvec.h b/fs/erofs/zpvec.h
+index dfd7fe0503bb1..b05464f4a8083 100644
+--- a/fs/erofs/zpvec.h
++++ b/fs/erofs/zpvec.h
+@@ -106,11 +106,18 @@ static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
+
+ static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
+ struct page *page,
+- enum z_erofs_page_type type)
++ enum z_erofs_page_type type,
++ bool pvec_safereuse)
+ {
+- if (!ctor->next && type)
+- if (ctor->index + 1 == ctor->nr)
++ if (!ctor->next) {
++ /* some pages cannot be reused as pvec safely without I/O */
++ if (type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && !pvec_safereuse)
++ type = Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED;
++
++ if (type != Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
++ ctor->index + 1 == ctor->nr)
+ return false;
++ }
+
+ if (ctor->index >= ctor->nr)
+ z_erofs_pagevec_ctor_pagedown(ctor, false);
+diff --git a/fs/exec.c b/fs/exec.c
+index a098c133d8d74..ac7b51b51f38a 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1852,7 +1852,7 @@ out:
+ * SIGSEGV.
+ */
+ if (bprm->point_of_no_return && !fatal_signal_pending(current))
+- force_sigsegv(SIGSEGV);
++ force_fatal_sig(SIGSEGV);
+
+ out_unmark:
+ current->fs->in_exec = 0;
+diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
+index ca37d43443612..1c7aa1ea4724c 100644
+--- a/fs/exfat/inode.c
++++ b/fs/exfat/inode.c
+@@ -604,7 +604,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
+ exfat_save_attr(inode, info->attr);
+
+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) &
+- ~(sbi->cluster_size - 1)) >> inode->i_blkbits;
++ ~((loff_t)sbi->cluster_size - 1)) >> inode->i_blkbits;
+ inode->i_mtime = info->mtime;
+ inode->i_ctime = info->mtime;
+ ei->i_crtime = info->crtime;
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 0e02571f2f828..01c00ae8e06d6 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -4977,36 +4977,6 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ return ext4_fill_es_cache_info(inode, start_blk, len_blks, fieinfo);
+ }
+
+-/*
+- * ext4_access_path:
+- * Function to access the path buffer for marking it dirty.
+- * It also checks if there are sufficient credits left in the journal handle
+- * to update path.
+- */
+-static int
+-ext4_access_path(handle_t *handle, struct inode *inode,
+- struct ext4_ext_path *path)
+-{
+- int credits, err;
+-
+- if (!ext4_handle_valid(handle))
+- return 0;
+-
+- /*
+- * Check if need to extend journal credits
+- * 3 for leaf, sb, and inode plus 2 (bmap and group
+- * descriptor) for each block group; assume two block
+- * groups
+- */
+- credits = ext4_writepage_trans_blocks(inode);
+- err = ext4_datasem_ensure_credits(handle, inode, 7, credits, 0);
+- if (err < 0)
+- return err;
+-
+- err = ext4_ext_get_access(handle, inode, path);
+- return err;
+-}
+-
+ /*
+ * ext4_ext_shift_path_extents:
+ * Shift the extents of a path structure lying between path[depth].p_ext
+@@ -5021,6 +4991,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
+ int depth, err = 0;
+ struct ext4_extent *ex_start, *ex_last;
+ bool update = false;
++ int credits, restart_credits;
+ depth = path->p_depth;
+
+ while (depth >= 0) {
+@@ -5030,13 +5001,26 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
+ return -EFSCORRUPTED;
+
+ ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
++ /* leaf + sb + inode */
++ credits = 3;
++ if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr)) {
++ update = true;
++ /* extent tree + sb + inode */
++ credits = depth + 2;
++ }
+
+- err = ext4_access_path(handle, inode, path + depth);
+- if (err)
++ restart_credits = ext4_writepage_trans_blocks(inode);
++ err = ext4_datasem_ensure_credits(handle, inode, credits,
++ restart_credits, 0);
++ if (err) {
++ if (err > 0)
++ err = -EAGAIN;
+ goto out;
++ }
+
+- if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr))
+- update = true;
++ err = ext4_ext_get_access(handle, inode, path + depth);
++ if (err)
++ goto out;
+
+ while (ex_start <= ex_last) {
+ if (SHIFT == SHIFT_LEFT) {
+@@ -5067,7 +5051,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
+ }
+
+ /* Update index too */
+- err = ext4_access_path(handle, inode, path + depth);
++ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+
+@@ -5106,6 +5090,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ int ret = 0, depth;
+ struct ext4_extent *extent;
+ ext4_lblk_t stop, *iterator, ex_start, ex_end;
++ ext4_lblk_t tmp = EXT_MAX_BLOCKS;
+
+ /* Let path point to the last extent */
+ path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
+@@ -5159,11 +5144,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ * till we reach stop. In case of right shift, iterator points to stop
+ * and it is decreased till we reach start.
+ */
++again:
+ if (SHIFT == SHIFT_LEFT)
+ iterator = &start;
+ else
+ iterator = &stop;
+
++ if (tmp != EXT_MAX_BLOCKS)
++ *iterator = tmp;
++
+ /*
+ * Its safe to start updating extents. Start and stop are unsigned, so
+ * in case of right shift if extent with 0 block is reached, iterator
+@@ -5192,6 +5181,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ }
+ }
+
++ tmp = *iterator;
+ if (SHIFT == SHIFT_LEFT) {
+ extent = EXT_LAST_EXTENT(path[depth].p_hdr);
+ *iterator = le32_to_cpu(extent->ee_block) +
+@@ -5210,6 +5200,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
+ }
+ ret = ext4_ext_shift_path_extents(path, shift, inode,
+ handle, SHIFT);
++ /* iterator can be NULL which means we should break */
++ if (ret == -EAGAIN)
++ goto again;
+ if (ret)
+ break;
+ }
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 0f06305167d5a..9097fccdc6889 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -1711,16 +1711,13 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
+ }
+
+ /*
+- * the buffer head associated with a delayed and not unwritten
+- * block found in the extent status cache must contain an
+- * invalid block number and have its BH_New and BH_Delay bits
+- * set, reflecting the state assigned when the block was
+- * initially delayed allocated
++ * Delayed extent could be allocated by fallocate.
++ * So we need to check it.
+ */
+- if (ext4_es_is_delonly(&es)) {
+- BUG_ON(bh->b_blocknr != invalid_block);
+- BUG_ON(!buffer_new(bh));
+- BUG_ON(!buffer_delay(bh));
++ if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) {
++ map_bh(bh, inode->i_sb, invalid_block);
++ set_buffer_new(bh);
++ set_buffer_delay(bh);
+ return 0;
+ }
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 88d5d274a8684..8a67e5f3f5763 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -3263,9 +3263,9 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
+ struct super_block *sb = elr->lr_super;
+ ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+ ext4_group_t group = elr->lr_next_group;
+- unsigned long timeout = 0;
+ unsigned int prefetch_ios = 0;
+ int ret = 0;
++ u64 start_time;
+
+ if (elr->lr_mode == EXT4_LI_MODE_PREFETCH_BBITMAP) {
+ elr->lr_next_group = ext4_mb_prefetch(sb, group,
+@@ -3302,14 +3302,13 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
+ ret = 1;
+
+ if (!ret) {
+- timeout = jiffies;
++ start_time = ktime_get_real_ns();
+ ret = ext4_init_inode_table(sb, group,
+ elr->lr_timeout ? 0 : 1);
+ trace_ext4_lazy_itable_init(sb, group);
+ if (elr->lr_timeout == 0) {
+- timeout = (jiffies - timeout) *
+- EXT4_SB(elr->lr_super)->s_li_wait_mult;
+- elr->lr_timeout = timeout;
++ elr->lr_timeout = nsecs_to_jiffies((ktime_get_real_ns() - start_time) *
++ EXT4_SB(elr->lr_super)->s_li_wait_mult);
+ }
+ elr->lr_next_sched = jiffies + elr->lr_timeout;
+ elr->lr_next_group = group + 1;
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index 83e9bc0f91ffd..7b02827242312 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -1162,7 +1162,8 @@ static bool __need_flush_quota(struct f2fs_sb_info *sbi)
+ if (!is_journalled_quota(sbi))
+ return false;
+
+- down_write(&sbi->quota_sem);
++ if (!down_write_trylock(&sbi->quota_sem))
++ return true;
+ if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) {
+ ret = false;
+ } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {
+diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
+index c1bf9ad4c2207..9b663eaf48057 100644
+--- a/fs/f2fs/compress.c
++++ b/fs/f2fs/compress.c
+@@ -1530,6 +1530,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
+ if (cluster_may_compress(cc)) {
+ err = f2fs_compress_pages(cc);
+ if (err == -EAGAIN) {
++ add_compr_block_stat(cc->inode, cc->cluster_size);
+ goto write;
+ } else if (err) {
+ f2fs_put_rpages_wbc(cc, wbc, true, 1);
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index b339ae89c1ad1..c242274e3479b 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -4152,8 +4152,7 @@ static inline bool f2fs_disable_compressed_file(struct inode *inode)
+
+ if (!f2fs_compressed_file(inode))
+ return true;
+- if (S_ISREG(inode->i_mode) &&
+- (get_dirty_pages(inode) || atomic_read(&fi->i_compr_blocks)))
++ if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
+ return false;
+
+ fi->i_flags &= ~F2FS_COMPR_FL;
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index 9141147b5bb00..1213f15ffd68c 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -527,7 +527,7 @@ make_now:
+ inode->i_op = &f2fs_dir_inode_operations;
+ inode->i_fop = &f2fs_dir_operations;
+ inode->i_mapping->a_ops = &f2fs_dblock_aops;
+- inode_nohighmem(inode);
++ mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+ } else if (S_ISLNK(inode->i_mode)) {
+ if (file_is_encrypt(inode))
+ inode->i_op = &f2fs_encrypted_symlink_inode_operations;
+diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
+index 9c528e583c9d5..ae0838001480a 100644
+--- a/fs/f2fs/namei.c
++++ b/fs/f2fs/namei.c
+@@ -757,7 +757,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
+ inode->i_op = &f2fs_dir_inode_operations;
+ inode->i_fop = &f2fs_dir_operations;
+ inode->i_mapping->a_ops = &f2fs_dblock_aops;
+- inode_nohighmem(inode);
++ mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+
+ set_inode_flag(inode, FI_INC_LINK);
+ f2fs_lock_op(sbi);
+diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
+index e863136081b47..556fcd8457f3f 100644
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1443,6 +1443,7 @@ page_hit:
+ nid, nid_of_node(page), ino_of_node(page),
+ ofs_of_node(page), cpver_of_node(page),
+ next_blkaddr_of_node(page));
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ err = -EINVAL;
+ out_err:
+ ClearPageUptodate(page);
+diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
+index a135d22474154..d716553bdc025 100644
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -561,7 +561,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
+ goto do_sync;
+
+ /* checkpoint is the only way to shrink partial cached entries */
+- if (f2fs_available_free_memory(sbi, NAT_ENTRIES) ||
++ if (f2fs_available_free_memory(sbi, NAT_ENTRIES) &&
+ f2fs_available_free_memory(sbi, INO_ENTRIES))
+ return;
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 78ebc306ee2b5..8795a5a8d4e89 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1292,7 +1292,7 @@ default_check:
+ /* Not pass down write hints if the number of active logs is lesser
+ * than NR_CURSEG_PERSIST_TYPE.
+ */
+- if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE)
++ if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_PERSIST_TYPE)
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+
+ if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
+@@ -3487,7 +3487,7 @@ skip_cross:
+ NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
+ f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
+ cp_payload, nat_bits_blocks);
+- return -EFSCORRUPTED;
++ return 1;
+ }
+
+ if (unlikely(f2fs_cp_error(sbi))) {
+@@ -4352,6 +4352,8 @@ free_node_inode:
+ free_stats:
+ f2fs_destroy_stats(sbi);
+ free_nm:
++ /* stop discard thread before destroying node manager */
++ f2fs_stop_discard_thread(sbi);
+ f2fs_destroy_node_manager(sbi);
+ free_sm:
+ f2fs_destroy_segment_manager(sbi);
+diff --git a/fs/file.c b/fs/file.c
+index 8627dacfc4246..ad4a8bf3cf109 100644
+--- a/fs/file.c
++++ b/fs/file.c
+@@ -858,6 +858,10 @@ loop:
+ file = NULL;
+ else if (!get_file_rcu_many(file, refs))
+ goto loop;
++ else if (files_lookup_fd_raw(files, fd) != file) {
++ fput_many(file, refs);
++ goto loop;
++ }
+ }
+ rcu_read_unlock();
+
+diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
+index dde341a6388a1..a9d21b33da9c4 100644
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -852,6 +852,12 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
+ if (!(buf->flags & PIPE_BUF_FLAG_LRU))
+ lru_cache_add(newpage);
+
++ /*
++ * Release while we have extra ref on stolen page. Otherwise
++ * anon_pipe_buf_release() might think the page can be reused.
++ */
++ pipe_buf_release(cs->pipe, buf);
++
+ err = 0;
+ spin_lock(&cs->req->waitq.lock);
+ if (test_bit(FR_ABORTED, &cs->req->flags))
+@@ -2031,8 +2037,12 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
+
+ pipe_lock(pipe);
+ out_free:
+- for (idx = 0; idx < nbuf; idx++)
+- pipe_buf_release(pipe, &bufs[idx]);
++ for (idx = 0; idx < nbuf; idx++) {
++ struct pipe_buffer *buf = &bufs[idx];
++
++ if (buf->ops)
++ pipe_buf_release(pipe, buf);
++ }
+ pipe_unlock(pipe);
+
+ kvfree(bufs);
+diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
+index d9b977c0f38dc..80a2181b402b2 100644
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -738,11 +738,19 @@ static int fuse_symlink(struct user_namespace *mnt_userns, struct inode *dir,
+ return create_new_entry(fm, &args, dir, entry, S_IFLNK);
+ }
+
++void fuse_flush_time_update(struct inode *inode)
++{
++ int err = sync_inode_metadata(inode, 1);
++
++ mapping_set_error(inode->i_mapping, err);
++}
++
+ void fuse_update_ctime(struct inode *inode)
+ {
+ if (!IS_NOCMTIME(inode)) {
+ inode->i_ctime = current_time(inode);
+ mark_inode_dirty_sync(inode);
++ fuse_flush_time_update(inode);
+ }
+ }
+
+@@ -1071,7 +1079,7 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
+ if (!parent)
+ return -ENOENT;
+
+- inode_lock(parent);
++ inode_lock_nested(parent, I_MUTEX_PARENT);
+ if (!S_ISDIR(parent->i_mode))
+ goto unlock;
+
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index 11404f8c21c75..5c5ed58d91a73 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -1848,6 +1848,17 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc)
+ struct fuse_file *ff;
+ int err;
+
++ /*
++ * Inode is always written before the last reference is dropped and
++ * hence this should not be reached from reclaim.
++ *
++ * Writing back the inode from reclaim can deadlock if the request
++ * processing itself needs an allocation. Allocations triggering
++ * reclaim while serving a request can't be prevented, because it can
++ * involve any number of unrelated userspace processes.
++ */
++ WARN_ON(wbc->for_reclaim);
++
+ ff = __fuse_write_file_get(fi);
+ err = fuse_flush_times(inode, ff);
+ if (ff)
+@@ -3002,6 +3013,8 @@ out:
+ if (lock_inode)
+ inode_unlock(inode);
+
++ fuse_flush_time_update(inode);
++
+ return err;
+ }
+
+@@ -3111,6 +3124,8 @@ out:
+ inode_unlock(inode_out);
+ file_accessed(file_in);
+
++ fuse_flush_time_update(inode_out);
++
+ return err;
+ }
+
+diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
+index f55f9f94b1a4f..a59e36c7deaea 100644
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -1148,6 +1148,7 @@ int fuse_allow_current_process(struct fuse_conn *fc);
+
+ u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
+
++void fuse_flush_time_update(struct inode *inode);
+ void fuse_update_ctime(struct inode *inode);
+
+ int fuse_update_attributes(struct inode *inode, struct file *file);
+diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
+index 12d49a1914e84..2f999d38c9b4a 100644
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -118,6 +118,9 @@ static void fuse_evict_inode(struct inode *inode)
+ {
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
++ /* Will write inode on close/munmap and in all other dirtiers */
++ WARN_ON(inode->i_state & I_DIRTY_INODE);
++
+ truncate_inode_pages_final(&inode->i_data);
+ clear_inode(inode);
+ if (inode->i_sb->s_flags & SB_ACTIVE) {
+diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
+index 5414c2c335809..fba32141a651b 100644
+--- a/fs/gfs2/bmap.c
++++ b/fs/gfs2/bmap.c
+@@ -940,7 +940,7 @@ do_alloc:
+ else if (height == ip->i_height)
+ ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
+ else
+- iomap->length = size - pos;
++ iomap->length = size - iomap->offset;
+ } else if (flags & IOMAP_WRITE) {
+ u64 alloc_size;
+
+diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
+index e0eaa9cf9fb6f..02cd0ae98208d 100644
+--- a/fs/gfs2/glock.c
++++ b/fs/gfs2/glock.c
+@@ -1893,10 +1893,10 @@ static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
+ do {
+ rhashtable_walk_start(&iter);
+
+- while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl))
+- if (gl->gl_name.ln_sbd == sdp &&
+- lockref_get_not_dead(&gl->gl_lockref))
++ while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl)) {
++ if (gl->gl_name.ln_sbd == sdp)
+ examiner(gl);
++ }
+
+ rhashtable_walk_stop(&iter);
+ } while (cond_resched(), gl == ERR_PTR(-EAGAIN));
+@@ -1919,7 +1919,7 @@ bool gfs2_queue_delete_work(struct gfs2_glock *gl, unsigned long delay)
+
+ void gfs2_cancel_delete_work(struct gfs2_glock *gl)
+ {
+- if (cancel_delayed_work_sync(&gl->gl_delete)) {
++ if (cancel_delayed_work(&gl->gl_delete)) {
+ clear_bit(GLF_PENDING_DELETE, &gl->gl_flags);
+ gfs2_glock_put(gl);
+ }
+@@ -1938,7 +1938,6 @@ static void flush_delete_work(struct gfs2_glock *gl)
+ &gl->gl_delete, 0);
+ }
+ }
+- gfs2_glock_queue_work(gl, 0);
+ }
+
+ void gfs2_flush_delete_work(struct gfs2_sbd *sdp)
+@@ -1955,10 +1954,10 @@ void gfs2_flush_delete_work(struct gfs2_sbd *sdp)
+
+ static void thaw_glock(struct gfs2_glock *gl)
+ {
+- if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags)) {
+- gfs2_glock_put(gl);
++ if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
++ return;
++ if (!lockref_get_not_dead(&gl->gl_lockref))
+ return;
+- }
+ set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
+ gfs2_glock_queue_work(gl, 0);
+ }
+@@ -1974,9 +1973,12 @@ static void clear_glock(struct gfs2_glock *gl)
+ gfs2_glock_remove_from_lru(gl);
+
+ spin_lock(&gl->gl_lockref.lock);
+- if (gl->gl_state != LM_ST_UNLOCKED)
+- handle_callback(gl, LM_ST_UNLOCKED, 0, false);
+- __gfs2_glock_queue_work(gl, 0);
++ if (!__lockref_is_dead(&gl->gl_lockref)) {
++ gl->gl_lockref.count++;
++ if (gl->gl_state != LM_ST_UNLOCKED)
++ handle_callback(gl, LM_ST_UNLOCKED, 0, false);
++ __gfs2_glock_queue_work(gl, 0);
++ }
+ spin_unlock(&gl->gl_lockref.lock);
+ }
+
+diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
+index 6e00d15ef0a82..cc51b5f5f52d8 100644
+--- a/fs/gfs2/super.c
++++ b/fs/gfs2/super.c
+@@ -1402,13 +1402,6 @@ out:
+ gfs2_ordered_del_inode(ip);
+ clear_inode(inode);
+ gfs2_dir_hash_inval(ip);
+- if (ip->i_gl) {
+- glock_clear_object(ip->i_gl, ip);
+- wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
+- gfs2_glock_add_to_lru(ip->i_gl);
+- gfs2_glock_put_eventually(ip->i_gl);
+- ip->i_gl = NULL;
+- }
+ if (gfs2_holder_initialized(&ip->i_iopen_gh)) {
+ struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
+
+@@ -1421,6 +1414,13 @@ out:
+ gfs2_holder_uninit(&ip->i_iopen_gh);
+ gfs2_glock_put_eventually(gl);
+ }
++ if (ip->i_gl) {
++ glock_clear_object(ip->i_gl, ip);
++ wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
++ gfs2_glock_add_to_lru(ip->i_gl);
++ gfs2_glock_put_eventually(ip->i_gl);
++ ip->i_gl = NULL;
++ }
+ }
+
+ static struct inode *gfs2_alloc_inode(struct super_block *sb)
+diff --git a/fs/inode.c b/fs/inode.c
+index ed0cab8a32db1..9abc88d7959cb 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -1782,12 +1782,13 @@ EXPORT_SYMBOL(generic_update_time);
+ * This does the actual work of updating an inodes time or version. Must have
+ * had called mnt_want_write() before calling this.
+ */
+-static int update_time(struct inode *inode, struct timespec64 *time, int flags)
++int inode_update_time(struct inode *inode, struct timespec64 *time, int flags)
+ {
+ if (inode->i_op->update_time)
+ return inode->i_op->update_time(inode, time, flags);
+ return generic_update_time(inode, time, flags);
+ }
++EXPORT_SYMBOL(inode_update_time);
+
+ /**
+ * atime_needs_update - update the access time
+@@ -1857,7 +1858,7 @@ void touch_atime(const struct path *path)
+ * of the fs read only, e.g. subvolumes in Btrfs.
+ */
+ now = current_time(inode);
+- update_time(inode, &now, S_ATIME);
++ inode_update_time(inode, &now, S_ATIME);
+ __mnt_drop_write(mnt);
+ skip_update:
+ sb_end_write(inode->i_sb);
+@@ -2002,7 +2003,7 @@ int file_update_time(struct file *file)
+ if (__mnt_want_write_file(file))
+ return 0;
+
+- ret = update_time(inode, &now, sync_it);
++ ret = inode_update_time(inode, &now, sync_it);
+ __mnt_drop_write_file(file);
+
+ return ret;
+diff --git a/fs/io-wq.c b/fs/io-wq.c
+index 422a7ed6a9bdb..01d4e3ff3170d 100644
+--- a/fs/io-wq.c
++++ b/fs/io-wq.c
+@@ -140,6 +140,8 @@ static void io_wqe_dec_running(struct io_worker *worker);
+ static bool io_acct_cancel_pending_work(struct io_wqe *wqe,
+ struct io_wqe_acct *acct,
+ struct io_cb_cancel_data *match);
++static void create_worker_cb(struct callback_head *cb);
++static void io_wq_cancel_tw_create(struct io_wq *wq);
+
+ static bool io_worker_get(struct io_worker *worker)
+ {
+@@ -174,9 +176,44 @@ static void io_worker_ref_put(struct io_wq *wq)
+ complete(&wq->worker_done);
+ }
+
++static void io_worker_cancel_cb(struct io_worker *worker)
++{
++ struct io_wqe_acct *acct = io_wqe_get_acct(worker);
++ struct io_wqe *wqe = worker->wqe;
++ struct io_wq *wq = wqe->wq;
++
++ atomic_dec(&acct->nr_running);
++ raw_spin_lock(&worker->wqe->lock);
++ acct->nr_workers--;
++ raw_spin_unlock(&worker->wqe->lock);
++ io_worker_ref_put(wq);
++ clear_bit_unlock(0, &worker->create_state);
++ io_worker_release(worker);
++}
++
++static bool io_task_worker_match(struct callback_head *cb, void *data)
++{
++ struct io_worker *worker;
++
++ if (cb->func != create_worker_cb)
++ return false;
++ worker = container_of(cb, struct io_worker, create_work);
++ return worker == data;
++}
++
+ static void io_worker_exit(struct io_worker *worker)
+ {
+ struct io_wqe *wqe = worker->wqe;
++ struct io_wq *wq = wqe->wq;
++
++ while (1) {
++ struct callback_head *cb = task_work_cancel_match(wq->task,
++ io_task_worker_match, worker);
++
++ if (!cb)
++ break;
++ io_worker_cancel_cb(worker);
++ }
+
+ if (refcount_dec_and_test(&worker->ref))
+ complete(&worker->ref_done);
+@@ -321,10 +358,22 @@ static bool io_queue_worker_create(struct io_worker *worker,
+ test_and_set_bit_lock(0, &worker->create_state))
+ goto fail_release;
+
++ atomic_inc(&wq->worker_refs);
+ init_task_work(&worker->create_work, func);
+ worker->create_index = acct->index;
+- if (!task_work_add(wq->task, &worker->create_work, TWA_SIGNAL))
++ if (!task_work_add(wq->task, &worker->create_work, TWA_SIGNAL)) {
++ /*
++ * EXIT may have been set after checking it above, check after
++ * adding the task_work and remove any creation item if it is
++ * now set. wq exit does that too, but we can have added this
++ * work item after we canceled in io_wq_exit_workers().
++ */
++ if (test_bit(IO_WQ_BIT_EXIT, &wq->state))
++ io_wq_cancel_tw_create(wq);
++ io_worker_ref_put(wq);
+ return true;
++ }
++ io_worker_ref_put(wq);
+ clear_bit_unlock(0, &worker->create_state);
+ fail_release:
+ io_worker_release(worker);
+@@ -346,7 +395,9 @@ static void io_wqe_dec_running(struct io_worker *worker)
+ if (atomic_dec_and_test(&acct->nr_running) && io_acct_run_queue(acct)) {
+ atomic_inc(&acct->nr_running);
+ atomic_inc(&wqe->wq->worker_refs);
++ raw_spin_unlock(&wqe->lock);
+ io_queue_worker_create(worker, acct, create_worker_cb);
++ raw_spin_lock(&wqe->lock);
+ }
+ }
+
+@@ -385,9 +436,10 @@ static inline unsigned int io_get_work_hash(struct io_wq_work *work)
+ return work->flags >> IO_WQ_HASH_SHIFT;
+ }
+
+-static void io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
++static bool io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
+ {
+ struct io_wq *wq = wqe->wq;
++ bool ret = false;
+
+ spin_lock_irq(&wq->hash->wait.lock);
+ if (list_empty(&wqe->wait.entry)) {
+@@ -395,9 +447,11 @@ static void io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
+ if (!test_bit(hash, &wq->hash->map)) {
+ __set_current_state(TASK_RUNNING);
+ list_del_init(&wqe->wait.entry);
++ ret = true;
+ }
+ }
+ spin_unlock_irq(&wq->hash->wait.lock);
++ return ret;
+ }
+
+ static struct io_wq_work *io_get_next_work(struct io_wqe_acct *acct,
+@@ -437,14 +491,21 @@ static struct io_wq_work *io_get_next_work(struct io_wqe_acct *acct,
+ }
+
+ if (stall_hash != -1U) {
++ bool unstalled;
++
+ /*
+ * Set this before dropping the lock to avoid racing with new
+ * work being added and clearing the stalled bit.
+ */
+ set_bit(IO_ACCT_STALLED_BIT, &acct->flags);
+ raw_spin_unlock(&wqe->lock);
+- io_wait_on_hash(wqe, stall_hash);
++ unstalled = io_wait_on_hash(wqe, stall_hash);
+ raw_spin_lock(&wqe->lock);
++ if (unstalled) {
++ clear_bit(IO_ACCT_STALLED_BIT, &acct->flags);
++ if (wq_has_sleeper(&wqe->wq->hash->wait))
++ wake_up(&wqe->wq->hash->wait);
++ }
+ }
+
+ return NULL;
+@@ -526,8 +587,11 @@ get_next:
+ io_wqe_enqueue(wqe, linked);
+
+ if (hash != -1U && !next_hashed) {
++ /* serialize hash clear with wake_up() */
++ spin_lock_irq(&wq->hash->wait.lock);
+ clear_bit(hash, &wq->hash->map);
+ clear_bit(IO_ACCT_STALLED_BIT, &acct->flags);
++ spin_unlock_irq(&wq->hash->wait.lock);
+ if (wq_has_sleeper(&wq->hash->wait))
+ wake_up(&wq->hash->wait);
+ raw_spin_lock(&wqe->lock);
+@@ -660,6 +724,13 @@ static bool io_wq_work_match_all(struct io_wq_work *work, void *data)
+
+ static inline bool io_should_retry_thread(long err)
+ {
++ /*
++ * Prevent perpetual task_work retry, if the task (or its group) is
++ * exiting.
++ */
++ if (fatal_signal_pending(current))
++ return false;
++
+ switch (err) {
+ case -EAGAIN:
+ case -ERESTARTSYS:
+@@ -716,11 +787,8 @@ static void io_workqueue_create(struct work_struct *work)
+ struct io_worker *worker = container_of(work, struct io_worker, work);
+ struct io_wqe_acct *acct = io_wqe_get_acct(worker);
+
+- if (!io_queue_worker_create(worker, acct, create_worker_cont)) {
+- clear_bit_unlock(0, &worker->create_state);
+- io_worker_release(worker);
++ if (!io_queue_worker_create(worker, acct, create_worker_cont))
+ kfree(worker);
+- }
+ }
+
+ static bool create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
+@@ -1140,28 +1208,26 @@ void io_wq_exit_start(struct io_wq *wq)
+ set_bit(IO_WQ_BIT_EXIT, &wq->state);
+ }
+
+-static void io_wq_exit_workers(struct io_wq *wq)
++static void io_wq_cancel_tw_create(struct io_wq *wq)
+ {
+ struct callback_head *cb;
+- int node;
+-
+- if (!wq->task)
+- return;
+
+ while ((cb = task_work_cancel_match(wq->task, io_task_work_match, wq)) != NULL) {
+ struct io_worker *worker;
+- struct io_wqe_acct *acct;
+
+ worker = container_of(cb, struct io_worker, create_work);
+- acct = io_wqe_get_acct(worker);
+- atomic_dec(&acct->nr_running);
+- raw_spin_lock(&worker->wqe->lock);
+- acct->nr_workers--;
+- raw_spin_unlock(&worker->wqe->lock);
+- io_worker_ref_put(wq);
+- clear_bit_unlock(0, &worker->create_state);
+- io_worker_release(worker);
++ io_worker_cancel_cb(worker);
+ }
++}
++
++static void io_wq_exit_workers(struct io_wq *wq)
++{
++ int node;
++
++ if (!wq->task)
++ return;
++
++ io_wq_cancel_tw_create(wq);
+
+ rcu_read_lock();
+ for_each_node(node) {
+@@ -1278,7 +1344,9 @@ int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask)
+ */
+ int io_wq_max_workers(struct io_wq *wq, int *new_count)
+ {
+- int i, node, prev = 0;
++ int prev[IO_WQ_ACCT_NR];
++ bool first_node = true;
++ int i, node;
+
+ BUILD_BUG_ON((int) IO_WQ_ACCT_BOUND != (int) IO_WQ_BOUND);
+ BUILD_BUG_ON((int) IO_WQ_ACCT_UNBOUND != (int) IO_WQ_UNBOUND);
+@@ -1289,6 +1357,9 @@ int io_wq_max_workers(struct io_wq *wq, int *new_count)
+ new_count[i] = task_rlimit(current, RLIMIT_NPROC);
+ }
+
++ for (i = 0; i < IO_WQ_ACCT_NR; i++)
++ prev[i] = 0;
++
+ rcu_read_lock();
+ for_each_node(node) {
+ struct io_wqe *wqe = wq->wqes[node];
+@@ -1297,14 +1368,19 @@ int io_wq_max_workers(struct io_wq *wq, int *new_count)
+ raw_spin_lock(&wqe->lock);
+ for (i = 0; i < IO_WQ_ACCT_NR; i++) {
+ acct = &wqe->acct[i];
+- prev = max_t(int, acct->max_workers, prev);
++ if (first_node)
++ prev[i] = max_t(int, acct->max_workers, prev[i]);
+ if (new_count[i])
+ acct->max_workers = new_count[i];
+- new_count[i] = prev;
+ }
+ raw_spin_unlock(&wqe->lock);
++ first_node = false;
+ }
+ rcu_read_unlock();
++
++ for (i = 0; i < IO_WQ_ACCT_NR; i++)
++ new_count[i] = prev[i];
++
+ return 0;
+ }
+
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index bc18af5e0a934..e9b06e339c4b0 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -1204,6 +1204,7 @@ static void io_refs_resurrect(struct percpu_ref *ref, struct completion *compl)
+
+ static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
+ bool cancel_all)
++ __must_hold(&req->ctx->timeout_lock)
+ {
+ struct io_kiocb *req;
+
+@@ -1219,6 +1220,44 @@ static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
+ return false;
+ }
+
++static bool io_match_linked(struct io_kiocb *head)
++{
++ struct io_kiocb *req;
++
++ io_for_each_link(req, head) {
++ if (req->flags & REQ_F_INFLIGHT)
++ return true;
++ }
++ return false;
++}
++
++/*
++ * As io_match_task() but protected against racing with linked timeouts.
++ * User must not hold timeout_lock.
++ */
++static bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
++ bool cancel_all)
++{
++ bool matched;
++
++ if (task && head->task != task)
++ return false;
++ if (cancel_all)
++ return true;
++
++ if (head->flags & REQ_F_LINK_TIMEOUT) {
++ struct io_ring_ctx *ctx = head->ctx;
++
++ /* protect against races with linked timeouts */
++ spin_lock_irq(&ctx->timeout_lock);
++ matched = io_match_linked(head);
++ spin_unlock_irq(&ctx->timeout_lock);
++ } else {
++ matched = io_match_linked(head);
++ }
++ return matched;
++}
++
+ static inline void req_set_fail(struct io_kiocb *req)
+ {
+ req->flags |= REQ_F_FAIL;
+@@ -1430,10 +1469,10 @@ static void io_prep_async_link(struct io_kiocb *req)
+ if (req->flags & REQ_F_LINK_TIMEOUT) {
+ struct io_ring_ctx *ctx = req->ctx;
+
+- spin_lock(&ctx->completion_lock);
++ spin_lock_irq(&ctx->timeout_lock);
+ io_for_each_link(cur, req)
+ io_prep_async_work(cur);
+- spin_unlock(&ctx->completion_lock);
++ spin_unlock_irq(&ctx->timeout_lock);
+ } else {
+ io_for_each_link(cur, req)
+ io_prep_async_work(cur);
+@@ -4304,6 +4343,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx, struct io_buffer *buf,
+ kfree(nxt);
+ if (++i == nbufs)
+ return i;
++ cond_resched();
+ }
+ i++;
+ kfree(buf);
+@@ -5702,7 +5742,7 @@ static bool io_poll_remove_all(struct io_ring_ctx *ctx, struct task_struct *tsk,
+
+ list = &ctx->cancel_hash[i];
+ hlist_for_each_entry_safe(req, tmp, list, hash_node) {
+- if (io_match_task(req, tsk, cancel_all))
++ if (io_match_task_safe(req, tsk, cancel_all))
+ posted += io_poll_remove_one(req);
+ }
+ }
+@@ -6884,10 +6924,11 @@ static inline struct file *io_file_get(struct io_ring_ctx *ctx,
+ static void io_req_task_link_timeout(struct io_kiocb *req, bool *locked)
+ {
+ struct io_kiocb *prev = req->timeout.prev;
+- int ret;
++ int ret = -ENOENT;
+
+ if (prev) {
+- ret = io_try_cancel_userdata(req, prev->user_data);
++ if (!(req->task->flags & PF_EXITING))
++ ret = io_try_cancel_userdata(req, prev->user_data);
+ io_req_complete_post(req, ret ?: -ETIME, 0);
+ io_put_req(prev);
+ } else {
+@@ -9209,10 +9250,8 @@ static void io_destroy_buffers(struct io_ring_ctx *ctx)
+ struct io_buffer *buf;
+ unsigned long index;
+
+- xa_for_each(&ctx->io_buffers, index, buf) {
++ xa_for_each(&ctx->io_buffers, index, buf)
+ __io_remove_buffers(ctx, buf, index, -1U);
+- cond_resched();
+- }
+ }
+
+ static void io_req_cache_free(struct list_head *list)
+@@ -9517,19 +9556,8 @@ static bool io_cancel_task_cb(struct io_wq_work *work, void *data)
+ {
+ struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+ struct io_task_cancel *cancel = data;
+- bool ret;
+-
+- if (!cancel->all && (req->flags & REQ_F_LINK_TIMEOUT)) {
+- struct io_ring_ctx *ctx = req->ctx;
+
+- /* protect against races with linked timeouts */
+- spin_lock(&ctx->completion_lock);
+- ret = io_match_task(req, cancel->task, cancel->all);
+- spin_unlock(&ctx->completion_lock);
+- } else {
+- ret = io_match_task(req, cancel->task, cancel->all);
+- }
+- return ret;
++ return io_match_task_safe(req, cancel->task, cancel->all);
+ }
+
+ static bool io_cancel_defer_files(struct io_ring_ctx *ctx,
+@@ -9540,7 +9568,7 @@ static bool io_cancel_defer_files(struct io_ring_ctx *ctx,
+
+ spin_lock(&ctx->completion_lock);
+ list_for_each_entry_reverse(de, &ctx->defer_list, list) {
+- if (io_match_task(de->req, task, cancel_all)) {
++ if (io_match_task_safe(de->req, task, cancel_all)) {
+ list_cut_position(&list, &ctx->defer_list, &de->list);
+ break;
+ }
+@@ -9747,7 +9775,7 @@ static void io_uring_drop_tctx_refs(struct task_struct *task)
+
+ /*
+ * Find any io_uring ctx that this task has registered or done IO on, and cancel
+- * requests. @sqd should be not-null IIF it's an SQPOLL thread cancellation.
++ * requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
+ */
+ static void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
+ {
+@@ -9788,8 +9816,10 @@ static void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
+ cancel_all);
+ }
+
+- prepare_to_wait(&tctx->wait, &wait, TASK_UNINTERRUPTIBLE);
++ prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
++ io_run_task_work();
+ io_uring_drop_tctx_refs(current);
++
+ /*
+ * If we've seen completions, retry without waiting. This
+ * avoids a race where a completion comes in before we did
+@@ -10684,7 +10714,9 @@ static int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
+
+ BUILD_BUG_ON(sizeof(new_count) != sizeof(ctx->iowq_limits));
+
+- memcpy(ctx->iowq_limits, new_count, sizeof(new_count));
++ for (i = 0; i < ARRAY_SIZE(new_count); i++)
++ if (new_count[i])
++ ctx->iowq_limits[i] = new_count[i];
+ ctx->iowq_limits_set = true;
+
+ ret = -EINVAL;
+diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
+index 9cc5798423d12..97119ec3b8503 100644
+--- a/fs/iomap/buffered-io.c
++++ b/fs/iomap/buffered-io.c
+@@ -256,8 +256,13 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter,
+ unsigned poff, plen;
+ sector_t sector;
+
+- if (iomap->type == IOMAP_INLINE)
+- return min(iomap_read_inline_data(iter, page), length);
++ if (iomap->type == IOMAP_INLINE) {
++ loff_t ret = iomap_read_inline_data(iter, page);
++
++ if (ret < 0)
++ return ret;
++ return 0;
++ }
+
+ /* zero post-eof blocks as the page may be mapped */
+ iop = iomap_page_create(iter->inode, page);
+@@ -370,6 +375,8 @@ static loff_t iomap_readahead_iter(const struct iomap_iter *iter,
+ ctx->cur_page_in_bio = false;
+ }
+ ret = iomap_readpage_iter(iter, ctx, done);
++ if (ret <= 0)
++ return ret;
+ }
+
+ return done;
+diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
+index 678e2c51b855c..0c6eacfcbeef1 100644
+--- a/fs/isofs/inode.c
++++ b/fs/isofs/inode.c
+@@ -1322,6 +1322,8 @@ static int isofs_read_inode(struct inode *inode, int relocated)
+
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ de_len = *(unsigned char *) de;
++ if (de_len < sizeof(struct iso_directory_record))
++ goto fail;
+
+ if (offset + de_len > bufsize) {
+ int frag1 = bufsize - offset;
+diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
+index 5d7d7170c03c0..aa4ff7bcaff23 100644
+--- a/fs/jfs/jfs_mount.c
++++ b/fs/jfs/jfs_mount.c
+@@ -81,14 +81,14 @@ int jfs_mount(struct super_block *sb)
+ * (initialize mount inode from the superblock)
+ */
+ if ((rc = chkSuper(sb))) {
+- goto errout20;
++ goto out;
+ }
+
+ ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
+ if (ipaimap == NULL) {
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
+ rc = -EIO;
+- goto errout20;
++ goto out;
+ }
+ sbi->ipaimap = ipaimap;
+
+@@ -99,7 +99,7 @@ int jfs_mount(struct super_block *sb)
+ */
+ if ((rc = diMount(ipaimap))) {
+ jfs_err("jfs_mount: diMount(ipaimap) failed w/rc = %d", rc);
+- goto errout21;
++ goto err_ipaimap;
+ }
+
+ /*
+@@ -108,7 +108,7 @@ int jfs_mount(struct super_block *sb)
+ ipbmap = diReadSpecial(sb, BMAP_I, 0);
+ if (ipbmap == NULL) {
+ rc = -EIO;
+- goto errout22;
++ goto err_umount_ipaimap;
+ }
+
+ jfs_info("jfs_mount: ipbmap:0x%p", ipbmap);
+@@ -120,7 +120,7 @@ int jfs_mount(struct super_block *sb)
+ */
+ if ((rc = dbMount(ipbmap))) {
+ jfs_err("jfs_mount: dbMount failed w/rc = %d", rc);
+- goto errout22;
++ goto err_ipbmap;
+ }
+
+ /*
+@@ -139,7 +139,7 @@ int jfs_mount(struct super_block *sb)
+ if (!ipaimap2) {
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
+ rc = -EIO;
+- goto errout35;
++ goto err_umount_ipbmap;
+ }
+ sbi->ipaimap2 = ipaimap2;
+
+@@ -151,7 +151,7 @@ int jfs_mount(struct super_block *sb)
+ if ((rc = diMount(ipaimap2))) {
+ jfs_err("jfs_mount: diMount(ipaimap2) failed, rc = %d",
+ rc);
+- goto errout35;
++ goto err_ipaimap2;
+ }
+ } else
+ /* Secondary aggregate inode table is not valid */
+@@ -168,7 +168,7 @@ int jfs_mount(struct super_block *sb)
+ jfs_err("jfs_mount: Failed to read FILESYSTEM_I");
+ /* open fileset secondary inode allocation map */
+ rc = -EIO;
+- goto errout40;
++ goto err_umount_ipaimap2;
+ }
+ jfs_info("jfs_mount: ipimap:0x%p", ipimap);
+
+@@ -178,41 +178,34 @@ int jfs_mount(struct super_block *sb)
+ /* initialize fileset inode allocation map */
+ if ((rc = diMount(ipimap))) {
+ jfs_err("jfs_mount: diMount failed w/rc = %d", rc);
+- goto errout41;
++ goto err_ipimap;
+ }
+
+- goto out;
++ return rc;
+
+ /*
+ * unwind on error
+ */
+- errout41: /* close fileset inode allocation map inode */
++err_ipimap:
++ /* close fileset inode allocation map inode */
+ diFreeSpecial(ipimap);
+-
+- errout40: /* fileset closed */
+-
++err_umount_ipaimap2:
+ /* close secondary aggregate inode allocation map */
+- if (ipaimap2) {
++ if (ipaimap2)
+ diUnmount(ipaimap2, 1);
++err_ipaimap2:
++ /* close aggregate inodes */
++ if (ipaimap2)
+ diFreeSpecial(ipaimap2);
+- }
+-
+- errout35:
+-
+- /* close aggregate block allocation map */
++err_umount_ipbmap: /* close aggregate block allocation map */
+ dbUnmount(ipbmap, 1);
++err_ipbmap: /* close aggregate inodes */
+ diFreeSpecial(ipbmap);
+-
+- errout22: /* close aggregate inode allocation map */
+-
++err_umount_ipaimap: /* close aggregate inode allocation map */
+ diUnmount(ipaimap, 1);
+-
+- errout21: /* close aggregate inodes */
++err_ipaimap: /* close aggregate inodes */
+ diFreeSpecial(ipaimap);
+- errout20: /* aggregate closed */
+-
+- out:
+-
++out:
+ if (rc)
+ jfs_err("Mount JFS Failure: %d", rc);
+
+diff --git a/fs/ksmbd/Kconfig b/fs/ksmbd/Kconfig
+index b83cbd756ae50..6af339cfdc041 100644
+--- a/fs/ksmbd/Kconfig
++++ b/fs/ksmbd/Kconfig
+@@ -19,6 +19,7 @@ config SMB_SERVER
+ select CRYPTO_GCM
+ select ASN1
+ select OID_REGISTRY
++ select CRC32
+ default n
+ help
+ Choose Y here if you want to allow SMB3 compliant clients
+diff --git a/fs/ksmbd/server.c b/fs/ksmbd/server.c
+index 2a2b2135bfded..36d368e59a640 100644
+--- a/fs/ksmbd/server.c
++++ b/fs/ksmbd/server.c
+@@ -632,5 +632,6 @@ MODULE_SOFTDEP("pre: sha512");
+ MODULE_SOFTDEP("pre: aead2");
+ MODULE_SOFTDEP("pre: ccm");
+ MODULE_SOFTDEP("pre: gcm");
++MODULE_SOFTDEP("pre: crc32");
+ module_init(ksmbd_server_init)
+ module_exit(ksmbd_server_exit)
+diff --git a/fs/ksmbd/smb2misc.c b/fs/ksmbd/smb2misc.c
+index 030ca57c37849..9f516f73bd1b6 100644
+--- a/fs/ksmbd/smb2misc.c
++++ b/fs/ksmbd/smb2misc.c
+@@ -358,12 +358,10 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
+ hdr = &pdu->hdr;
+ }
+
+- if (le32_to_cpu(hdr->NextCommand) > 0) {
++ if (le32_to_cpu(hdr->NextCommand) > 0)
+ len = le32_to_cpu(hdr->NextCommand);
+- } else if (work->next_smb2_rcv_hdr_off) {
++ else if (work->next_smb2_rcv_hdr_off)
+ len -= work->next_smb2_rcv_hdr_off;
+- len = round_up(len, 8);
+- }
+
+ if (check_smb2_hdr(hdr))
+ return 1;
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index 7e448df3f8474..ad0ea5d36f2ee 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -1700,8 +1700,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ negblob_off = le16_to_cpu(req->SecurityBufferOffset);
+ negblob_len = le16_to_cpu(req->SecurityBufferLength);
+ if (negblob_off < (offsetof(struct smb2_sess_setup_req, Buffer) - 4) ||
+- negblob_len < offsetof(struct negotiate_message, NegotiateFlags))
+- return -EINVAL;
++ negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) {
++ rc = -EINVAL;
++ goto out_err;
++ }
+
+ negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
+ negblob_off);
+@@ -4450,6 +4452,12 @@ static void get_file_stream_info(struct ksmbd_work *work,
+ &stat);
+ file_info = (struct smb2_file_stream_info *)rsp->Buffer;
+
++ buf_free_len =
++ smb2_calc_max_out_buf_len(work, 8,
++ le32_to_cpu(req->OutputBufferLength));
++ if (buf_free_len < 0)
++ goto out;
++
+ xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
+ if (xattr_list_len < 0) {
+ goto out;
+@@ -4458,12 +4466,6 @@ static void get_file_stream_info(struct ksmbd_work *work,
+ goto out;
+ }
+
+- buf_free_len =
+- smb2_calc_max_out_buf_len(work, 8,
+- le32_to_cpu(req->OutputBufferLength));
+- if (buf_free_len < 0)
+- goto out;
+-
+ while (idx < xattr_list_len) {
+ stream_name = xattr_list + idx;
+ streamlen = strlen(stream_name);
+@@ -4489,8 +4491,10 @@ static void get_file_stream_info(struct ksmbd_work *work,
+ ":%s", &stream_name[XATTR_NAME_STREAM_LEN]);
+
+ next = sizeof(struct smb2_file_stream_info) + streamlen * 2;
+- if (next > buf_free_len)
++ if (next > buf_free_len) {
++ kfree(stream_buf);
+ break;
++ }
+
+ file_info = (struct smb2_file_stream_info *)&rsp->Buffer[nbytes];
+ streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName,
+@@ -4507,6 +4511,7 @@ static void get_file_stream_info(struct ksmbd_work *work,
+ file_info->NextEntryOffset = cpu_to_le32(next);
+ }
+
++out:
+ if (!S_ISDIR(stat.mode) &&
+ buf_free_len >= sizeof(struct smb2_file_stream_info) + 7 * 2) {
+ file_info = (struct smb2_file_stream_info *)
+@@ -4515,14 +4520,13 @@ static void get_file_stream_info(struct ksmbd_work *work,
+ "::$DATA", 7, conn->local_nls, 0);
+ streamlen *= 2;
+ file_info->StreamNameLength = cpu_to_le32(streamlen);
+- file_info->StreamSize = 0;
+- file_info->StreamAllocationSize = 0;
++ file_info->StreamSize = cpu_to_le64(stat.size);
++ file_info->StreamAllocationSize = cpu_to_le64(stat.blocks << 9);
+ nbytes += sizeof(struct smb2_file_stream_info) + streamlen;
+ }
+
+ /* last entry offset should be 0 */
+ file_info->NextEntryOffset = 0;
+-out:
+ kvfree(xattr_list);
+
+ rsp->OutputBufferLength = cpu_to_le32(nbytes);
+@@ -4891,11 +4895,18 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
+ {
+ struct filesystem_vol_info *info;
+ size_t sz;
++ unsigned int serial_crc = 0;
+
+ info = (struct filesystem_vol_info *)(rsp->Buffer);
+ info->VolumeCreationTime = 0;
++ serial_crc = crc32_le(serial_crc, share->name,
++ strlen(share->name));
++ serial_crc = crc32_le(serial_crc, share->path,
++ strlen(share->path));
++ serial_crc = crc32_le(serial_crc, ksmbd_netbios_name(),
++ strlen(ksmbd_netbios_name()));
+ /* Taking dummy value of serial number*/
+- info->SerialNumber = cpu_to_le32(0xbc3ac512);
++ info->SerialNumber = cpu_to_le32(serial_crc);
+ len = smbConvertToUTF16((__le16 *)info->VolumeLabel,
+ share->name, PATH_MAX,
+ conn->local_nls, 0);
+@@ -5053,7 +5064,7 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
+ if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
+ PROTECTED_DACL_SECINFO |
+ UNPROTECTED_DACL_SECINFO)) {
+- pr_err("Unsupported addition info: 0x%x)\n",
++ ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n",
+ addition_info);
+
+ pntsd->revision = cpu_to_le16(1);
+@@ -7312,7 +7323,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn,
+ int ret = 0;
+ int dialect;
+
+- if (in_buf_len < sizeof(struct validate_negotiate_info_req) +
++ if (in_buf_len < offsetof(struct validate_negotiate_info_req, Dialects) +
+ le16_to_cpu(neg_req->DialectCount) * sizeof(__le16))
+ return -EINVAL;
+
+diff --git a/fs/netfs/read_helper.c b/fs/netfs/read_helper.c
+index 994ec22d40402..4b54529f8176b 100644
+--- a/fs/netfs/read_helper.c
++++ b/fs/netfs/read_helper.c
+@@ -354,16 +354,11 @@ static void netfs_rreq_write_to_cache_work(struct work_struct *work)
+ netfs_rreq_do_write_to_cache(rreq);
+ }
+
+-static void netfs_rreq_write_to_cache(struct netfs_read_request *rreq,
+- bool was_async)
++static void netfs_rreq_write_to_cache(struct netfs_read_request *rreq)
+ {
+- if (was_async) {
+- rreq->work.func = netfs_rreq_write_to_cache_work;
+- if (!queue_work(system_unbound_wq, &rreq->work))
+- BUG();
+- } else {
+- netfs_rreq_do_write_to_cache(rreq);
+- }
++ rreq->work.func = netfs_rreq_write_to_cache_work;
++ if (!queue_work(system_unbound_wq, &rreq->work))
++ BUG();
+ }
+
+ /*
+@@ -560,7 +555,7 @@ again:
+ wake_up_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS);
+
+ if (test_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags))
+- return netfs_rreq_write_to_cache(rreq, was_async);
++ return netfs_rreq_write_to_cache(rreq);
+
+ netfs_rreq_completed(rreq, was_async);
+ }
+diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
+index 1a6d2867fba4f..5b68c44848caf 100644
+--- a/fs/nfs/dir.c
++++ b/fs/nfs/dir.c
+@@ -1269,13 +1269,12 @@ static bool nfs_verifier_is_delegated(struct dentry *dentry)
+ static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf)
+ {
+ struct inode *inode = d_inode(dentry);
++ struct inode *dir = d_inode(dentry->d_parent);
+
+- if (!nfs_verifier_is_delegated(dentry) &&
+- !nfs_verify_change_attribute(d_inode(dentry->d_parent), verf))
+- goto out;
++ if (!nfs_verify_change_attribute(dir, verf))
++ return;
+ if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
+ nfs_set_verifier_delegated(&verf);
+-out:
+ dentry->d_time = verf;
+ }
+
+@@ -1413,7 +1412,7 @@ out_force:
+ static void nfs_mark_dir_for_revalidate(struct inode *inode)
+ {
+ spin_lock(&inode->i_lock);
+- nfs_set_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE);
++ nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE);
+ spin_unlock(&inode->i_lock);
+ }
+
+diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
+index 2e894fec036b0..3c0335c15a730 100644
+--- a/fs/nfs/direct.c
++++ b/fs/nfs/direct.c
+@@ -620,7 +620,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
+ nfs_unlock_and_release_request(req);
+ }
+
+- if (atomic_dec_and_test(&cinfo.mds->rpcs_out))
++ if (nfs_commit_end(cinfo.mds))
+ nfs_direct_write_complete(dreq);
+ }
+
+diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+index c9b61b818ec11..bfa7202ca7be1 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+@@ -378,10 +378,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
+ goto noconnect;
+
+ ds = mirror->mirror_ds->ds;
++ if (READ_ONCE(ds->ds_clp))
++ goto out;
+ /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
+ smp_rmb();
+- if (ds->ds_clp)
+- goto out;
+
+ /* FIXME: For now we assume the server sent only one version of NFS
+ * to use for the DS.
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index 853213b3a2095..f9d3ad3acf114 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -210,10 +210,15 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
+ flags &= ~NFS_INO_INVALID_XATTR;
+ if (flags & NFS_INO_INVALID_DATA)
+ nfs_fscache_invalidate(inode);
+- if (inode->i_mapping->nrpages == 0)
+- flags &= ~(NFS_INO_INVALID_DATA|NFS_INO_DATA_INVAL_DEFER);
+ flags &= ~(NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED);
++
+ nfsi->cache_validity |= flags;
++
++ if (inode->i_mapping->nrpages == 0)
++ nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA |
++ NFS_INO_DATA_INVAL_DEFER);
++ else if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
++ nfsi->cache_validity &= ~NFS_INO_DATA_INVAL_DEFER;
+ }
+ EXPORT_SYMBOL_GPL(nfs_set_cache_invalid);
+
+@@ -1777,8 +1782,10 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
+ NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
+ NFS_INO_INVALID_NLINK;
+ unsigned long cache_validity = NFS_I(inode)->cache_validity;
++ enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
+
+- if (!(cache_validity & NFS_INO_INVALID_CHANGE) &&
++ if (ctype != NFS4_CHANGE_TYPE_IS_UNDEFINED &&
++ !(cache_validity & NFS_INO_INVALID_CHANGE) &&
+ (cache_validity & check_valid) != 0 &&
+ (fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
+ nfs_inode_attrs_cmp_monotonic(fattr, inode) == 0)
+diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
+index e6eca1d7481b8..9274c9c5efea6 100644
+--- a/fs/nfs/nfs3xdr.c
++++ b/fs/nfs/nfs3xdr.c
+@@ -2227,7 +2227,7 @@ static int decode_fsinfo3resok(struct xdr_stream *xdr,
+
+ /* ignore properties */
+ result->lease_time = 0;
+- result->change_attr_type = NFS4_CHANGE_TYPE_IS_TIME_METADATA;
++ result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
+ return 0;
+ }
+
+diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
+index a24349512ffe9..9865b5c37d889 100644
+--- a/fs/nfs/nfs42proc.c
++++ b/fs/nfs/nfs42proc.c
+@@ -285,7 +285,9 @@ static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
+ loff_t newsize = pos + len;
+ loff_t end = newsize - 1;
+
+- truncate_pagecache_range(inode, pos, end);
++ WARN_ON_ONCE(invalidate_inode_pages2_range(inode->i_mapping,
++ pos >> PAGE_SHIFT, end >> PAGE_SHIFT));
++
+ spin_lock(&inode->i_lock);
+ if (newsize > i_size_read(inode))
+ i_size_write(inode, newsize);
+diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
+index c8bad735e4c19..271e5f92ed019 100644
+--- a/fs/nfs/nfs42xdr.c
++++ b/fs/nfs/nfs42xdr.c
+@@ -1434,8 +1434,7 @@ static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp,
+ status = decode_clone(xdr);
+ if (status)
+ goto out;
+- status = decode_getfattr(xdr, res->dst_fattr, res->server);
+-
++ decode_getfattr(xdr, res->dst_fattr, res->server);
+ out:
+ res->rpc_status = status;
+ return status;
+diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
+index 8d8aba305ecca..f331866dd4182 100644
+--- a/fs/nfs/nfs4idmap.c
++++ b/fs/nfs/nfs4idmap.c
+@@ -487,7 +487,7 @@ nfs_idmap_new(struct nfs_client *clp)
+ err_destroy_pipe:
+ rpc_destroy_pipe_data(idmap->idmap_pipe);
+ err:
+- get_user_ns(idmap->user_ns);
++ put_user_ns(idmap->user_ns);
+ kfree(idmap);
+ return error;
+ }
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index e1214bb6b7ee5..1f38f8cd8c3ce 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -1609,15 +1609,16 @@ static bool nfs_stateid_is_sequential(struct nfs4_state *state,
+ {
+ if (test_bit(NFS_OPEN_STATE, &state->flags)) {
+ /* The common case - we're updating to a new sequence number */
+- if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
+- nfs4_stateid_is_next(&state->open_stateid, stateid)) {
+- return true;
++ if (nfs4_stateid_match_other(stateid, &state->open_stateid)) {
++ if (nfs4_stateid_is_next(&state->open_stateid, stateid))
++ return true;
++ return false;
+ }
+- } else {
+- /* This is the first OPEN in this generation */
+- if (stateid->seqid == cpu_to_be32(1))
+- return true;
++ /* The server returned a new stateid */
+ }
++ /* This is the first OPEN in this generation */
++ if (stateid->seqid == cpu_to_be32(1))
++ return true;
+ return false;
+ }
+
+diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
+index d810ae674f4e8..a0f6ff094b3a4 100644
+--- a/fs/nfs/pnfs.h
++++ b/fs/nfs/pnfs.h
+@@ -517,7 +517,7 @@ pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
+ {
+ struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
+
+- if (!lseg || !fl_cinfo->ops->mark_request_commit)
++ if (!lseg || !fl_cinfo->ops || !fl_cinfo->ops->mark_request_commit)
+ return false;
+ fl_cinfo->ops->mark_request_commit(req, lseg, cinfo, ds_commit_idx);
+ return true;
+diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
+index cf19914fec817..316f68f96e573 100644
+--- a/fs/nfs/pnfs_nfs.c
++++ b/fs/nfs/pnfs_nfs.c
+@@ -468,7 +468,6 @@ pnfs_bucket_alloc_ds_commits(struct list_head *list,
+ goto out_error;
+ data->ds_commit_index = i;
+ list_add_tail(&data->list, list);
+- atomic_inc(&cinfo->mds->rpcs_out);
+ nreq++;
+ }
+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
+@@ -520,7 +519,6 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
+ data->ds_commit_index = -1;
+ list_splice_init(mds_pages, &data->pages);
+ list_add_tail(&data->list, &list);
+- atomic_inc(&cinfo->mds->rpcs_out);
+ nreq++;
+ }
+
+@@ -895,7 +893,7 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
+ }
+
+ smp_wmb();
+- ds->ds_clp = clp;
++ WRITE_ONCE(ds->ds_clp, clp);
+ dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
+ out:
+ return status;
+@@ -973,7 +971,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
+ }
+
+ smp_wmb();
+- ds->ds_clp = clp;
++ WRITE_ONCE(ds->ds_clp, clp);
+ dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
+ out:
+ return status;
+diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
+index ea19dbf123014..ecc4e717808c4 100644
+--- a/fs/nfs/proc.c
++++ b/fs/nfs/proc.c
+@@ -91,7 +91,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ info->dtpref = fsinfo.tsize;
+ info->maxfilesize = 0x7FFFFFFF;
+ info->lease_time = 0;
+- info->change_attr_type = NFS4_CHANGE_TYPE_IS_TIME_METADATA;
++ info->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
+ return 0;
+ }
+
+diff --git a/fs/nfs/write.c b/fs/nfs/write.c
+index eae9bf1140417..7dce3e735fc53 100644
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -1038,25 +1038,11 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
+ struct nfs_page *req, *tmp;
+ int ret = 0;
+
+-restart:
+ list_for_each_entry_safe(req, tmp, src, wb_list) {
+ kref_get(&req->wb_kref);
+ if (!nfs_lock_request(req)) {
+- int status;
+-
+- /* Prevent deadlock with nfs_lock_and_join_requests */
+- if (!list_empty(dst)) {
+- nfs_release_request(req);
+- continue;
+- }
+- /* Ensure we make progress to prevent livelock */
+- mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
+- status = nfs_wait_on_request(req);
+ nfs_release_request(req);
+- mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
+- if (status < 0)
+- break;
+- goto restart;
++ continue;
+ }
+ nfs_request_remove_commit_list(req, cinfo);
+ clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
+@@ -1671,10 +1657,13 @@ static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
+ atomic_inc(&cinfo->rpcs_out);
+ }
+
+-static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
++bool nfs_commit_end(struct nfs_mds_commit_info *cinfo)
+ {
+- if (atomic_dec_and_test(&cinfo->rpcs_out))
++ if (atomic_dec_and_test(&cinfo->rpcs_out)) {
+ wake_up_var(&cinfo->rpcs_out);
++ return true;
++ }
++ return false;
+ }
+
+ void nfs_commitdata_release(struct nfs_commit_data *data)
+@@ -1774,6 +1763,7 @@ void nfs_init_commit(struct nfs_commit_data *data,
+ data->res.fattr = &data->fattr;
+ data->res.verf = &data->verf;
+ nfs_fattr_init(&data->fattr);
++ nfs_commit_begin(cinfo->mds);
+ }
+ EXPORT_SYMBOL_GPL(nfs_init_commit);
+
+@@ -1820,7 +1810,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
+
+ /* Set up the argument struct */
+ nfs_init_commit(data, head, NULL, cinfo);
+- atomic_inc(&cinfo->mds->rpcs_out);
+ if (NFS_SERVER(inode)->nfs_client->cl_minorversion)
+ task_flags = RPC_TASK_MOVEABLE;
+ return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode),
+@@ -1936,6 +1925,7 @@ static int __nfs_commit_inode(struct inode *inode, int how,
+ int may_wait = how & FLUSH_SYNC;
+ int ret, nscan;
+
++ how &= ~FLUSH_SYNC;
+ nfs_init_cinfo_from_inode(&cinfo, inode);
+ nfs_commit_begin(cinfo.mds);
+ for (;;) {
+diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
+index 6fedc49726bf7..c634483d85d2a 100644
+--- a/fs/nfsd/nfs4recover.c
++++ b/fs/nfsd/nfs4recover.c
+@@ -2156,6 +2156,7 @@ static struct notifier_block nfsd4_cld_block = {
+ int
+ register_cld_notifier(void)
+ {
++ WARN_ON(!nfsd_net_id);
+ return rpc_pipefs_notifier_register(&nfsd4_cld_block);
+ }
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 3f4027a5de883..61301affb4c1b 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -1207,6 +1207,11 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
+ return 0;
+ }
+
++static bool delegation_hashed(struct nfs4_delegation *dp)
++{
++ return !(list_empty(&dp->dl_perfile));
++}
++
+ static bool
+ unhash_delegation_locked(struct nfs4_delegation *dp)
+ {
+@@ -1214,7 +1219,7 @@ unhash_delegation_locked(struct nfs4_delegation *dp)
+
+ lockdep_assert_held(&state_lock);
+
+- if (list_empty(&dp->dl_perfile))
++ if (!delegation_hashed(dp))
+ return false;
+
+ dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
+@@ -4598,7 +4603,7 @@ static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
+ * queued for a lease break. Don't queue it again.
+ */
+ spin_lock(&state_lock);
+- if (dp->dl_time == 0) {
++ if (delegation_hashed(dp) && dp->dl_time == 0) {
+ dp->dl_time = ktime_get_boottime_seconds();
+ list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
+ }
+diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
+index cf030ebe28275..266d5152c3216 100644
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -288,11 +288,8 @@ nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen)
+ p = xdr_inline_decode(argp->xdr, count << 2);
+ if (!p)
+ return nfserr_bad_xdr;
+- i = 0;
+- while (i < count)
+- bmval[i++] = be32_to_cpup(p++);
+- while (i < bmlen)
+- bmval[i++] = 0;
++ for (i = 0; i < bmlen; i++)
++ bmval[i] = (i < count) ? be32_to_cpup(p++) : 0;
+
+ return nfs_ok;
+ }
+diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
+index 070e5dd03e26f..5ed04d6be9a59 100644
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -1521,12 +1521,9 @@ static int __init init_nfsd(void)
+ int retval;
+ printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
+
+- retval = register_cld_notifier();
+- if (retval)
+- return retval;
+ retval = nfsd4_init_slabs();
+ if (retval)
+- goto out_unregister_notifier;
++ return retval;
+ retval = nfsd4_init_pnfs();
+ if (retval)
+ goto out_free_slabs;
+@@ -1545,9 +1542,14 @@ static int __init init_nfsd(void)
+ goto out_free_exports;
+ retval = register_pernet_subsys(&nfsd_net_ops);
+ if (retval < 0)
++ goto out_free_filesystem;
++ retval = register_cld_notifier();
++ if (retval)
+ goto out_free_all;
+ return 0;
+ out_free_all:
++ unregister_pernet_subsys(&nfsd_net_ops);
++out_free_filesystem:
+ unregister_filesystem(&nfsd_fs_type);
+ out_free_exports:
+ remove_proc_entry("fs/nfs/exports", NULL);
+@@ -1561,13 +1563,12 @@ out_free_pnfs:
+ nfsd4_exit_pnfs();
+ out_free_slabs:
+ nfsd4_free_slabs();
+-out_unregister_notifier:
+- unregister_cld_notifier();
+ return retval;
+ }
+
+ static void __exit exit_nfsd(void)
+ {
++ unregister_cld_notifier();
+ unregister_pernet_subsys(&nfsd_net_ops);
+ nfsd_drc_slab_free();
+ remove_proc_entry("fs/nfs/exports", NULL);
+@@ -1577,7 +1578,6 @@ static void __exit exit_nfsd(void)
+ nfsd4_free_slabs();
+ nfsd4_exit_pnfs();
+ unregister_filesystem(&nfsd_fs_type);
+- unregister_cld_notifier();
+ }
+
+ MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
+diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
+index 54d7843c02114..fc5f780fa2355 100644
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -476,10 +476,11 @@ int ocfs2_truncate_file(struct inode *inode,
+ * greater than page size, so we have to truncate them
+ * anyway.
+ */
+- unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
+- truncate_inode_pages(inode->i_mapping, new_i_size);
+
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
++ unmap_mapping_range(inode->i_mapping,
++ new_i_size + PAGE_SIZE - 1, 0, 1);
++ truncate_inode_pages(inode->i_mapping, new_i_size);
+ status = ocfs2_truncate_inline(inode, di_bh, new_i_size,
+ i_size_read(inode), 1);
+ if (status)
+@@ -498,6 +499,9 @@ int ocfs2_truncate_file(struct inode *inode,
+ goto bail_unlock_sem;
+ }
+
++ unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
++ truncate_inode_pages(inode->i_mapping, new_i_size);
++
+ status = ocfs2_commit_truncate(osb, inode, di_bh);
+ if (status < 0) {
+ mlog_errno(status);
+diff --git a/fs/open.c b/fs/open.c
+index daa324606a41f..e0df1536eb69f 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -856,8 +856,20 @@ static int do_dentry_open(struct file *f,
+ * of THPs into the page cache will fail.
+ */
+ smp_mb();
+- if (filemap_nr_thps(inode->i_mapping))
+- truncate_pagecache(inode, 0);
++ if (filemap_nr_thps(inode->i_mapping)) {
++ struct address_space *mapping = inode->i_mapping;
++
++ filemap_invalidate_lock(inode->i_mapping);
++ /*
++ * unmap_mapping_range just need to be called once
++ * here, because the private pages is not need to be
++ * unmapped mapping (e.g. data segment of dynamic
++ * shared libraries here).
++ */
++ unmap_mapping_range(mapping, 0, 0, 0);
++ truncate_inode_pages(mapping, 0);
++ filemap_invalidate_unlock(inode->i_mapping);
++ }
+ }
+
+ return 0;
+diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c
+index fe484cf93e5cd..8bbe9486e3a62 100644
+--- a/fs/orangefs/dcache.c
++++ b/fs/orangefs/dcache.c
+@@ -26,8 +26,10 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
+ gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
+
+ new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
+- if (!new_op)
++ if (!new_op) {
++ ret = -ENOMEM;
+ goto out_put_parent;
++ }
+
+ new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
+ new_op->upcall.req.lookup.parent_refn = parent->refn;
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index 4e7d5bfa2949f..b193d08a3dc36 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -140,12 +140,14 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
+ int err;
+
+ err = ovl_real_fileattr_get(old, &oldfa);
+- if (err)
+- return err;
+-
+- err = ovl_real_fileattr_get(new, &newfa);
+- if (err)
++ if (err) {
++ /* Ntfs-3g returns -EINVAL for "no fileattr support" */
++ if (err == -ENOTTY || err == -EINVAL)
++ return 0;
++ pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
++ old, err);
+ return err;
++ }
+
+ /*
+ * We cannot set immutable and append-only flags on upper inode,
+@@ -159,6 +161,17 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
+ return err;
+ }
+
++ /* Don't bother copying flags if none are set */
++ if (!(oldfa.flags & OVL_COPY_FS_FLAGS_MASK))
++ return 0;
++
++ err = ovl_real_fileattr_get(new, &newfa);
++ if (err) {
++ pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
++ new, err);
++ return err;
++ }
++
+ BUILD_BUG_ON(OVL_COPY_FS_FLAGS_MASK & ~FS_COMMON_FL);
+ newfa.flags &= ~OVL_COPY_FS_FLAGS_MASK;
+ newfa.flags |= (oldfa.flags & OVL_COPY_FS_FLAGS_MASK);
+diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
+index 93c7c267de934..f18490813170a 100644
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -137,8 +137,7 @@ kill_whiteout:
+ goto out;
+ }
+
+-static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry,
+- umode_t mode)
++int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
+ {
+ int err;
+ struct dentry *d, *dentry = *newdentry;
+diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
+index c88ac571593dc..44fea16751f1d 100644
+--- a/fs/overlayfs/file.c
++++ b/fs/overlayfs/file.c
+@@ -17,6 +17,7 @@
+
+ struct ovl_aio_req {
+ struct kiocb iocb;
++ refcount_t ref;
+ struct kiocb *orig_iocb;
+ struct fd fd;
+ };
+@@ -252,6 +253,14 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
+ return flags;
+ }
+
++static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
++{
++ if (refcount_dec_and_test(&aio_req->ref)) {
++ fdput(aio_req->fd);
++ kmem_cache_free(ovl_aio_request_cachep, aio_req);
++ }
++}
++
+ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
+ {
+ struct kiocb *iocb = &aio_req->iocb;
+@@ -268,8 +277,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
+ }
+
+ orig_iocb->ki_pos = iocb->ki_pos;
+- fdput(aio_req->fd);
+- kmem_cache_free(ovl_aio_request_cachep, aio_req);
++ ovl_aio_put(aio_req);
+ }
+
+ static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2)
+@@ -319,7 +327,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+ aio_req->orig_iocb = iocb;
+ kiocb_clone(&aio_req->iocb, iocb, real.file);
+ aio_req->iocb.ki_complete = ovl_aio_rw_complete;
++ refcount_set(&aio_req->ref, 2);
+ ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
++ ovl_aio_put(aio_req);
+ if (ret != -EIOCBQUEUED)
+ ovl_aio_cleanup_handler(aio_req);
+ }
+@@ -390,7 +400,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+ kiocb_clone(&aio_req->iocb, iocb, real.file);
+ aio_req->iocb.ki_flags = ifl;
+ aio_req->iocb.ki_complete = ovl_aio_rw_complete;
++ refcount_set(&aio_req->ref, 2);
+ ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
++ ovl_aio_put(aio_req);
+ if (ret != -EIOCBQUEUED)
+ ovl_aio_cleanup_handler(aio_req);
+ }
+diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
+index 832b17589733a..1f36158c7dbe2 100644
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -610,7 +610,10 @@ int ovl_real_fileattr_get(struct path *realpath, struct fileattr *fa)
+ if (err)
+ return err;
+
+- return vfs_fileattr_get(realpath->dentry, fa);
++ err = vfs_fileattr_get(realpath->dentry, fa);
++ if (err == -ENOIOCTLCMD)
++ err = -ENOTTY;
++ return err;
+ }
+
+ int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa)
+diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
+index 3894f33479552..2cd5741c873b6 100644
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -570,6 +570,7 @@ struct ovl_cattr {
+
+ #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) })
+
++int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode);
+ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+ struct ovl_cattr *attr);
+ int ovl_cleanup(struct inode *dir, struct dentry *dentry);
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 178daa5e82c9d..265181c110ae2 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -787,10 +787,14 @@ retry:
+ goto retry;
+ }
+
+- work = ovl_create_real(dir, work, OVL_CATTR(attr.ia_mode));
+- err = PTR_ERR(work);
+- if (IS_ERR(work))
+- goto out_err;
++ err = ovl_mkdir_real(dir, &work, attr.ia_mode);
++ if (err)
++ goto out_dput;
++
++ /* Weird filesystem returning with hashed negative (kernfs)? */
++ err = -EINVAL;
++ if (d_really_is_negative(work))
++ goto out_dput;
+
+ /*
+ * Try to remove POSIX ACL xattrs from workdir. We are good if:
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 533d5836eb9a4..1f394095eb880 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -67,6 +67,7 @@
+ #include <linux/mm.h>
+ #include <linux/swap.h>
+ #include <linux/rcupdate.h>
++#include <linux/kallsyms.h>
+ #include <linux/stacktrace.h>
+ #include <linux/resource.h>
+ #include <linux/module.h>
+@@ -386,17 +387,19 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *task)
+ {
+ unsigned long wchan;
++ char symname[KSYM_NAME_LEN];
+
+- if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
+- wchan = get_wchan(task);
+- else
+- wchan = 0;
++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
++ goto print0;
+
+- if (wchan)
+- seq_printf(m, "%ps", (void *) wchan);
+- else
+- seq_putc(m, '0');
++ wchan = get_wchan(task);
++ if (wchan && !lookup_symbol_name(wchan, symname)) {
++ seq_puts(m, symname);
++ return 0;
++ }
+
++print0:
++ seq_putc(m, '0');
+ return 0;
+ }
+ #endif /* CONFIG_KALLSYMS */
+diff --git a/fs/proc/stat.c b/fs/proc/stat.c
+index 6561a06ef9059..4fb8729a68d4e 100644
+--- a/fs/proc/stat.c
++++ b/fs/proc/stat.c
+@@ -24,7 +24,7 @@
+
+ #ifdef arch_idle_time
+
+-static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
++u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
+ {
+ u64 idle;
+
+@@ -46,7 +46,7 @@ static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
+
+ #else
+
+-static u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
++u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
+ {
+ u64 idle, idle_usecs = -1ULL;
+
+diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
+index 5a1b228964fb7..deb99bc9b7e6b 100644
+--- a/fs/proc/uptime.c
++++ b/fs/proc/uptime.c
+@@ -12,18 +12,22 @@ static int uptime_proc_show(struct seq_file *m, void *v)
+ {
+ struct timespec64 uptime;
+ struct timespec64 idle;
+- u64 nsec;
++ u64 idle_nsec;
+ u32 rem;
+ int i;
+
+- nsec = 0;
+- for_each_possible_cpu(i)
+- nsec += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
++ idle_nsec = 0;
++ for_each_possible_cpu(i) {
++ struct kernel_cpustat kcs;
++
++ kcpustat_cpu_fetch(&kcs, i);
++ idle_nsec += get_idle_time(&kcs, i);
++ }
+
+ ktime_get_boottime_ts64(&uptime);
+ timens_add_boottime(&uptime);
+
+- idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
++ idle.tv_sec = div_u64_rem(idle_nsec, NSEC_PER_SEC, &rem);
+ idle.tv_nsec = rem;
+ seq_printf(m, "%lu.%02lu %lu.%02lu\n",
+ (unsigned long) uptime.tv_sec,
+diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
+index 9a15334da2086..e5730986758fa 100644
+--- a/fs/proc/vmcore.c
++++ b/fs/proc/vmcore.c
+@@ -124,9 +124,13 @@ ssize_t read_from_oldmem(char *buf, size_t count,
+ nr_bytes = count;
+
+ /* If pfn is not ram, return zeros for sparse dump files */
+- if (pfn_is_ram(pfn) == 0)
+- memset(buf, 0, nr_bytes);
+- else {
++ if (pfn_is_ram(pfn) == 0) {
++ tmp = 0;
++ if (!userbuf)
++ memset(buf, 0, nr_bytes);
++ else if (clear_user(buf, nr_bytes))
++ tmp = -EFAULT;
++ } else {
+ if (encrypted)
+ tmp = copy_oldmem_page_encrypted(pfn, buf,
+ nr_bytes,
+@@ -135,10 +139,10 @@ ssize_t read_from_oldmem(char *buf, size_t count,
+ else
+ tmp = copy_oldmem_page(pfn, buf, nr_bytes,
+ offset, userbuf);
+-
+- if (tmp < 0)
+- return tmp;
+ }
++ if (tmp < 0)
++ return tmp;
++
+ *ppos += nr_bytes;
+ count -= nr_bytes;
+ buf += nr_bytes;
+diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
+index 328da35da3908..8adabde685f13 100644
+--- a/fs/pstore/Kconfig
++++ b/fs/pstore/Kconfig
+@@ -173,7 +173,6 @@ config PSTORE_BLK
+ tristate "Log panic/oops to a block device"
+ depends on PSTORE
+ depends on BLOCK
+- depends on BROKEN
+ select PSTORE_ZONE
+ default n
+ help
+diff --git a/fs/pstore/blk.c b/fs/pstore/blk.c
+index 04ce58c939a0b..6093088de49fd 100644
+--- a/fs/pstore/blk.c
++++ b/fs/pstore/blk.c
+@@ -311,7 +311,7 @@ static int __init __best_effort_init(void)
+ if (ret)
+ kfree(best_effort_dev);
+ else
+- pr_info("attached %s (%zu) (no dedicated panic_write!)\n",
++ pr_info("attached %s (%lu) (no dedicated panic_write!)\n",
+ blkdev, best_effort_dev->zone.total_size);
+
+ return ret;
+diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
+index d3e995e1046fb..5f2405994280a 100644
+--- a/fs/quota/quota_tree.c
++++ b/fs/quota/quota_tree.c
+@@ -414,6 +414,7 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
+ quota_error(dquot->dq_sb, "Quota structure has offset to "
+ "other block (%u) than it should (%u)", blk,
+ (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
++ ret = -EIO;
+ goto out_buf;
+ }
+ ret = read_blk(info, blk, buf);
+@@ -479,6 +480,13 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
+ goto out_buf;
+ }
+ newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
++ if (newblk < QT_TREEOFF || newblk >= info->dqi_blocks) {
++ quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
++ newblk, info->dqi_blocks);
++ ret = -EUCLEAN;
++ goto out_buf;
++ }
++
+ if (depth == info->dqi_qtree_depth - 1) {
+ ret = free_dqentry(info, dquot, newblk);
+ newblk = 0;
+@@ -578,6 +586,13 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
+ blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+ if (!blk) /* No reference? */
+ goto out_buf;
++ if (blk < QT_TREEOFF || blk >= info->dqi_blocks) {
++ quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)",
++ blk, info->dqi_blocks);
++ ret = -EUCLEAN;
++ goto out_buf;
++ }
++
+ if (depth < info->dqi_qtree_depth - 1)
+ ret = find_tree_dqentry(info, dquot, blk, depth+1);
+ else
+diff --git a/fs/signalfd.c b/fs/signalfd.c
+index 040e1cf905282..65ce0e72e7b95 100644
+--- a/fs/signalfd.c
++++ b/fs/signalfd.c
+@@ -35,17 +35,7 @@
+
+ void signalfd_cleanup(struct sighand_struct *sighand)
+ {
+- wait_queue_head_t *wqh = &sighand->signalfd_wqh;
+- /*
+- * The lockless check can race with remove_wait_queue() in progress,
+- * but in this case its caller should run under rcu_read_lock() and
+- * sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return.
+- */
+- if (likely(!waitqueue_active(wqh)))
+- return;
+-
+- /* wait_queue_entry_t->func(POLLFREE) should do remove_wait_queue() */
+- wake_up_poll(wqh, EPOLLHUP | POLLFREE);
++ wake_up_pollfree(&sighand->signalfd_wqh);
+ }
+
+ struct signalfd_ctx {
+diff --git a/fs/smbfs_common/cifs_arc4.c b/fs/smbfs_common/cifs_arc4.c
+index 85ba15a60b13b..043e4cb839fa2 100644
+--- a/fs/smbfs_common/cifs_arc4.c
++++ b/fs/smbfs_common/cifs_arc4.c
+@@ -72,16 +72,3 @@ void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int l
+ ctx->y = y;
+ }
+ EXPORT_SYMBOL_GPL(cifs_arc4_crypt);
+-
+-static int __init
+-init_smbfs_common(void)
+-{
+- return 0;
+-}
+-static void __init
+-exit_smbfs_common(void)
+-{
+-}
+-
+-module_init(init_smbfs_common)
+-module_exit(exit_smbfs_common)
+diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
+index 1261e8b41edb4..3616839c5c4b6 100644
+--- a/fs/tracefs/inode.c
++++ b/fs/tracefs/inode.c
+@@ -161,6 +161,77 @@ struct tracefs_fs_info {
+ struct tracefs_mount_opts mount_opts;
+ };
+
++static void change_gid(struct dentry *dentry, kgid_t gid)
++{
++ if (!dentry->d_inode)
++ return;
++ dentry->d_inode->i_gid = gid;
++}
++
++/*
++ * Taken from d_walk, but without he need for handling renames.
++ * Nothing can be renamed while walking the list, as tracefs
++ * does not support renames. This is only called when mounting
++ * or remounting the file system, to set all the files to
++ * the given gid.
++ */
++static void set_gid(struct dentry *parent, kgid_t gid)
++{
++ struct dentry *this_parent;
++ struct list_head *next;
++
++ this_parent = parent;
++ spin_lock(&this_parent->d_lock);
++
++ change_gid(this_parent, gid);
++repeat:
++ next = this_parent->d_subdirs.next;
++resume:
++ while (next != &this_parent->d_subdirs) {
++ struct list_head *tmp = next;
++ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
++ next = tmp->next;
++
++ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
++
++ change_gid(dentry, gid);
++
++ if (!list_empty(&dentry->d_subdirs)) {
++ spin_unlock(&this_parent->d_lock);
++ spin_release(&dentry->d_lock.dep_map, _RET_IP_);
++ this_parent = dentry;
++ spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
++ goto repeat;
++ }
++ spin_unlock(&dentry->d_lock);
++ }
++ /*
++ * All done at this level ... ascend and resume the search.
++ */
++ rcu_read_lock();
++ascend:
++ if (this_parent != parent) {
++ struct dentry *child = this_parent;
++ this_parent = child->d_parent;
++
++ spin_unlock(&child->d_lock);
++ spin_lock(&this_parent->d_lock);
++
++ /* go into the first sibling still alive */
++ do {
++ next = child->d_child.next;
++ if (next == &this_parent->d_subdirs)
++ goto ascend;
++ child = list_entry(next, struct dentry, d_child);
++ } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
++ rcu_read_unlock();
++ goto resume;
++ }
++ rcu_read_unlock();
++ spin_unlock(&this_parent->d_lock);
++ return;
++}
++
+ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
+ {
+ substring_t args[MAX_OPT_ARGS];
+@@ -193,6 +264,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
+ if (!gid_valid(gid))
+ return -EINVAL;
+ opts->gid = gid;
++ set_gid(tracefs_mount->mnt_root, gid);
+ break;
+ case Opt_mode:
+ if (match_octal(&args[0], &option))
+@@ -414,6 +486,8 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
+ inode->i_mode = mode;
+ inode->i_fop = fops ? fops : &tracefs_file_operations;
+ inode->i_private = data;
++ inode->i_uid = d_inode(dentry->d_parent)->i_uid;
++ inode->i_gid = d_inode(dentry->d_parent)->i_gid;
+ d_instantiate(dentry, inode);
+ fsnotify_create(dentry->d_parent->d_inode, dentry);
+ return end_creating(dentry);
+@@ -432,9 +506,12 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent,
+ if (unlikely(!inode))
+ return failed_creating(dentry);
+
+- inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
++ /* Do not set bits for OTH */
++ inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
+ inode->i_op = ops;
+ inode->i_fop = &simple_dir_operations;
++ inode->i_uid = d_inode(dentry->d_parent)->i_uid;
++ inode->i_gid = d_inode(dentry->d_parent)->i_gid;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inc_nlink(inode);
+diff --git a/fs/udf/dir.c b/fs/udf/dir.c
+index 70abdfad2df17..42e3e551fa4c3 100644
+--- a/fs/udf/dir.c
++++ b/fs/udf/dir.c
+@@ -31,6 +31,7 @@
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+ #include <linux/bio.h>
++#include <linux/iversion.h>
+
+ #include "udf_i.h"
+ #include "udf_sb.h"
+@@ -43,7 +44,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
+ struct fileIdentDesc *fi = NULL;
+ struct fileIdentDesc cfi;
+ udf_pblk_t block, iblock;
+- loff_t nf_pos;
++ loff_t nf_pos, emit_pos = 0;
+ int flen;
+ unsigned char *fname = NULL, *copy_name = NULL;
+ unsigned char *nameptr;
+@@ -57,6 +58,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
+ int i, num, ret = 0;
+ struct extent_position epos = { NULL, 0, {0, 0} };
+ struct super_block *sb = dir->i_sb;
++ bool pos_valid = false;
+
+ if (ctx->pos == 0) {
+ if (!dir_emit_dot(file, ctx))
+@@ -67,6 +69,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
+ if (nf_pos >= size)
+ goto out;
+
++ /*
++ * Something changed since last readdir (either lseek was called or dir
++ * changed)? We need to verify the position correctly points at the
++ * beginning of some dir entry so that the directory parsing code does
++ * not get confused. Since UDF does not have any reliable way of
++ * identifying beginning of dir entry (names are under user control),
++ * we need to scan the directory from the beginning.
++ */
++ if (!inode_eq_iversion(dir, file->f_version)) {
++ emit_pos = nf_pos;
++ nf_pos = 0;
++ } else {
++ pos_valid = true;
++ }
++
+ fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ if (!fname) {
+ ret = -ENOMEM;
+@@ -122,13 +139,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
+
+ while (nf_pos < size) {
+ struct kernel_lb_addr tloc;
++ loff_t cur_pos = nf_pos;
+
+- ctx->pos = (nf_pos >> 2) + 1;
++ /* Update file position only if we got past the current one */
++ if (nf_pos >= emit_pos) {
++ ctx->pos = (nf_pos >> 2) + 1;
++ pos_valid = true;
++ }
+
+ fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
+ &elen, &offset);
+ if (!fi)
+ goto out;
++ /* Still not at offset where user asked us to read from? */
++ if (cur_pos < emit_pos)
++ continue;
+
+ liu = le16_to_cpu(cfi.lengthOfImpUse);
+ lfi = cfi.lengthFileIdent;
+@@ -186,8 +211,11 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
+ } /* end while */
+
+ ctx->pos = (nf_pos >> 2) + 1;
++ pos_valid = true;
+
+ out:
++ if (pos_valid)
++ file->f_version = inode_query_iversion(dir);
+ if (fibh.sbh != fibh.ebh)
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+diff --git a/fs/udf/namei.c b/fs/udf/namei.c
+index caeef08efed23..0ed4861b038f6 100644
+--- a/fs/udf/namei.c
++++ b/fs/udf/namei.c
+@@ -30,6 +30,7 @@
+ #include <linux/sched.h>
+ #include <linux/crc-itu-t.h>
+ #include <linux/exportfs.h>
++#include <linux/iversion.h>
+
+ static inline int udf_match(int len1, const unsigned char *name1, int len2,
+ const unsigned char *name2)
+@@ -134,6 +135,8 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
+ mark_buffer_dirty_inode(fibh->ebh, inode);
+ mark_buffer_dirty_inode(fibh->sbh, inode);
+ }
++ inode_inc_iversion(inode);
++
+ return 0;
+ }
+
+diff --git a/fs/udf/super.c b/fs/udf/super.c
+index b2d7c57d06881..aa2f6093d3f6f 100644
+--- a/fs/udf/super.c
++++ b/fs/udf/super.c
+@@ -57,6 +57,7 @@
+ #include <linux/crc-itu-t.h>
+ #include <linux/log2.h>
+ #include <asm/byteorder.h>
++#include <linux/iversion.h>
+
+ #include "udf_sb.h"
+ #include "udf_i.h"
+@@ -149,6 +150,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
+ init_rwsem(&ei->i_data_sem);
+ ei->cached_extent.lstart = -1;
+ spin_lock_init(&ei->i_extent_cache_lock);
++ inode_set_iversion(&ei->vfs_inode, 1);
+
+ return &ei->vfs_inode;
+ }
+diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
+index ddc346a9df9ba..807f33553a8eb 100644
+--- a/fs/zonefs/super.c
++++ b/fs/zonefs/super.c
+@@ -1787,5 +1787,6 @@ static void __exit zonefs_exit(void)
+ MODULE_AUTHOR("Damien Le Moal");
+ MODULE_DESCRIPTION("Zone file system for zoned block devices");
+ MODULE_LICENSE("GPL");
++MODULE_ALIAS_FS("zonefs");
+ module_init(zonefs_init);
+ module_exit(zonefs_exit);
+diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
+index f681bbdbc6982..36f7eb9d06639 100644
+--- a/include/drm/ttm/ttm_bo_api.h
++++ b/include/drm/ttm/ttm_bo_api.h
+@@ -594,8 +594,7 @@ vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
+
+ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
+ pgprot_t prot,
+- pgoff_t num_prefault,
+- pgoff_t fault_page_size);
++ pgoff_t num_prefault);
+
+ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf);
+
+diff --git a/include/linux/acpi.h b/include/linux/acpi.h
+index 974d497a897dc..6224b1e32681c 100644
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -976,6 +976,15 @@ static inline int acpi_get_local_address(acpi_handle handle, u32 *addr)
+ return -ENODEV;
+ }
+
++static inline int acpi_register_wakeup_handler(int wake_irq,
++ bool (*wakeup)(void *context), void *context)
++{
++ return -ENXIO;
++}
++
++static inline void acpi_unregister_wakeup_handler(
++ bool (*wakeup)(void *context), void *context) { }
++
+ #endif /* !CONFIG_ACPI */
+
+ #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index 12b9dbcc980ee..0a9fdcbbab83d 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -235,6 +235,14 @@ struct request {
+ void *end_io_data;
+ };
+
++static inline int blk_validate_block_size(unsigned int bsize)
++{
++ if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
++ return -EINVAL;
++
++ return 0;
++}
++
+ static inline bool blk_op_is_passthrough(unsigned int op)
+ {
+ op &= REQ_OP_MASK;
+@@ -1198,8 +1206,6 @@ struct blk_plug {
+ bool multiple_queues;
+ bool nowait;
+ };
+-#define BLK_MAX_REQUEST_COUNT 16
+-#define BLK_PLUG_FLUSH_SIZE (128 * 1024)
+
+ struct blk_plug_cb;
+ typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool);
+diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
+index 2746fd8042162..3536ab432b30c 100644
+--- a/include/linux/bpf-cgroup.h
++++ b/include/linux/bpf-cgroup.h
+@@ -517,6 +517,7 @@ static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map,
+
+ #define cgroup_bpf_enabled(atype) (0)
+ #define BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, atype, t_ctx) ({ 0; })
++#define BPF_CGROUP_RUN_SA_PROG(sk, uaddr, atype) ({ 0; })
+ #define BPF_CGROUP_PRE_CONNECT_ENABLED(sk) (0)
+ #define BPF_CGROUP_RUN_PROG_INET_INGRESS(sk,skb) ({ 0; })
+ #define BPF_CGROUP_RUN_PROG_INET_EGRESS(sk,skb) ({ 0; })
+diff --git a/include/linux/bpf.h b/include/linux/bpf.h
+index 3db6f6c95489e..6c4640526f741 100644
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -190,7 +190,7 @@ struct bpf_map {
+ atomic64_t usercnt;
+ struct work_struct work;
+ struct mutex freeze_mutex;
+- u64 writecnt; /* writable mmap cnt; protected by freeze_mutex */
++ atomic64_t writecnt;
+ };
+
+ static inline bool map_value_has_spin_lock(const struct bpf_map *map)
+@@ -723,6 +723,7 @@ int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr)
+ struct bpf_trampoline *bpf_trampoline_get(u64 key,
+ struct bpf_attach_target_info *tgt_info);
+ void bpf_trampoline_put(struct bpf_trampoline *tr);
++int arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs);
+ #define BPF_DISPATCHER_INIT(_name) { \
+ .mutex = __MUTEX_INITIALIZER(_name.mutex), \
+ .func = &_name##_func, \
+@@ -1320,28 +1321,16 @@ extern struct mutex bpf_stats_enabled_mutex;
+ * kprobes, tracepoints) to prevent deadlocks on map operations as any of
+ * these events can happen inside a region which holds a map bucket lock
+ * and can deadlock on it.
+- *
+- * Use the preemption safe inc/dec variants on RT because migrate disable
+- * is preemptible on RT and preemption in the middle of the RMW operation
+- * might lead to inconsistent state. Use the raw variants for non RT
+- * kernels as migrate_disable() maps to preempt_disable() so the slightly
+- * more expensive save operation can be avoided.
+ */
+ static inline void bpf_disable_instrumentation(void)
+ {
+ migrate_disable();
+- if (IS_ENABLED(CONFIG_PREEMPT_RT))
+- this_cpu_inc(bpf_prog_active);
+- else
+- __this_cpu_inc(bpf_prog_active);
++ this_cpu_inc(bpf_prog_active);
+ }
+
+ static inline void bpf_enable_instrumentation(void)
+ {
+- if (IS_ENABLED(CONFIG_PREEMPT_RT))
+- this_cpu_dec(bpf_prog_active);
+- else
+- __this_cpu_dec(bpf_prog_active);
++ this_cpu_dec(bpf_prog_active);
+ migrate_enable();
+ }
+
+@@ -1387,6 +1376,7 @@ void bpf_map_put(struct bpf_map *map);
+ void *bpf_map_area_alloc(u64 size, int numa_node);
+ void *bpf_map_area_mmapable_alloc(u64 size, int numa_node);
+ void bpf_map_area_free(void *base);
++bool bpf_map_write_active(const struct bpf_map *map);
+ void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr);
+ int generic_map_lookup_batch(struct bpf_map *map,
+ const union bpf_attr *attr,
+diff --git a/include/linux/cc_platform.h b/include/linux/cc_platform.h
+new file mode 100644
+index 0000000000000..a075b70b9a70c
+--- /dev/null
++++ b/include/linux/cc_platform.h
+@@ -0,0 +1,88 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Confidential Computing Platform Capability checks
++ *
++ * Copyright (C) 2021 Advanced Micro Devices, Inc.
++ *
++ * Author: Tom Lendacky <thomas.lendacky@amd.com>
++ */
++
++#ifndef _LINUX_CC_PLATFORM_H
++#define _LINUX_CC_PLATFORM_H
++
++#include <linux/types.h>
++#include <linux/stddef.h>
++
++/**
++ * enum cc_attr - Confidential computing attributes
++ *
++ * These attributes represent confidential computing features that are
++ * currently active.
++ */
++enum cc_attr {
++ /**
++ * @CC_ATTR_MEM_ENCRYPT: Memory encryption is active
++ *
++ * The platform/OS is running with active memory encryption. This
++ * includes running either as a bare-metal system or a hypervisor
++ * and actively using memory encryption or as a guest/virtual machine
++ * and actively using memory encryption.
++ *
++ * Examples include SME, SEV and SEV-ES.
++ */
++ CC_ATTR_MEM_ENCRYPT,
++
++ /**
++ * @CC_ATTR_HOST_MEM_ENCRYPT: Host memory encryption is active
++ *
++ * The platform/OS is running as a bare-metal system or a hypervisor
++ * and actively using memory encryption.
++ *
++ * Examples include SME.
++ */
++ CC_ATTR_HOST_MEM_ENCRYPT,
++
++ /**
++ * @CC_ATTR_GUEST_MEM_ENCRYPT: Guest memory encryption is active
++ *
++ * The platform/OS is running as a guest/virtual machine and actively
++ * using memory encryption.
++ *
++ * Examples include SEV and SEV-ES.
++ */
++ CC_ATTR_GUEST_MEM_ENCRYPT,
++
++ /**
++ * @CC_ATTR_GUEST_STATE_ENCRYPT: Guest state encryption is active
++ *
++ * The platform/OS is running as a guest/virtual machine and actively
++ * using memory encryption and register state encryption.
++ *
++ * Examples include SEV-ES.
++ */
++ CC_ATTR_GUEST_STATE_ENCRYPT,
++};
++
++#ifdef CONFIG_ARCH_HAS_CC_PLATFORM
++
++/**
++ * cc_platform_has() - Checks if the specified cc_attr attribute is active
++ * @attr: Confidential computing attribute to check
++ *
++ * The cc_platform_has() function will return an indicator as to whether the
++ * specified Confidential Computing attribute is currently active.
++ *
++ * Context: Any context
++ * Return:
++ * * TRUE - Specified Confidential Computing attribute is active
++ * * FALSE - Specified Confidential Computing attribute is not active
++ */
++bool cc_platform_has(enum cc_attr attr);
++
++#else /* !CONFIG_ARCH_HAS_CC_PLATFORM */
++
++static inline bool cc_platform_has(enum cc_attr attr) { return false; }
++
++#endif /* CONFIG_ARCH_HAS_CC_PLATFORM */
++
++#endif /* _LINUX_CC_PLATFORM_H */
+diff --git a/include/linux/console.h b/include/linux/console.h
+index 20874db50bc8a..a97f277cfdfa3 100644
+--- a/include/linux/console.h
++++ b/include/linux/console.h
+@@ -149,6 +149,8 @@ struct console {
+ short flags;
+ short index;
+ int cflag;
++ uint ispeed;
++ uint ospeed;
+ void *data;
+ struct console *next;
+ };
+diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
+index ff88bb3e44fca..66a1f495f01a6 100644
+--- a/include/linux/cpufreq.h
++++ b/include/linux/cpufreq.h
+@@ -1041,7 +1041,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
+ if (cpu == pcpu)
+ continue;
+
+- ret = parse_perf_domain(pcpu, list_name, cell_name);
++ ret = parse_perf_domain(cpu, list_name, cell_name);
+ if (ret < 0)
+ continue;
+
+diff --git a/include/linux/delay.h b/include/linux/delay.h
+index 1d0e2ce6b6d9f..e8607992c68a5 100644
+--- a/include/linux/delay.h
++++ b/include/linux/delay.h
+@@ -20,6 +20,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/sched.h>
+
+ extern unsigned long loops_per_jiffy;
+
+@@ -58,7 +59,18 @@ void calibrate_delay(void);
+ void __attribute__((weak)) calibration_delay_done(void);
+ void msleep(unsigned int msecs);
+ unsigned long msleep_interruptible(unsigned int msecs);
+-void usleep_range(unsigned long min, unsigned long max);
++void usleep_range_state(unsigned long min, unsigned long max,
++ unsigned int state);
++
++static inline void usleep_range(unsigned long min, unsigned long max)
++{
++ usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
++}
++
++static inline void usleep_idle_range(unsigned long min, unsigned long max)
++{
++ usleep_range_state(min, max, TASK_IDLE);
++}
+
+ static inline void ssleep(unsigned int seconds)
+ {
+diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
+index 8b32b4bdd5908..3ad636a13b8e9 100644
+--- a/include/linux/dma-buf.h
++++ b/include/linux/dma-buf.h
+@@ -433,7 +433,7 @@ struct dma_buf {
+ wait_queue_head_t *poll;
+
+ __poll_t active;
+- } cb_excl, cb_shared;
++ } cb_in, cb_out;
+ #ifdef CONFIG_DMABUF_SYSFS_STATS
+ /**
+ * @sysfs_entry:
+diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
+index e5c2c9e71bf10..9000f3ffce8b3 100644
+--- a/include/linux/dmaengine.h
++++ b/include/linux/dmaengine.h
+@@ -944,10 +944,8 @@ struct dma_device {
+ void (*device_issue_pending)(struct dma_chan *chan);
+ void (*device_release)(struct dma_device *dev);
+ /* debugfs support */
+-#ifdef CONFIG_DEBUG_FS
+ void (*dbg_summary_show)(struct seq_file *s, struct dma_device *dev);
+ struct dentry *dbg_dev_root;
+-#endif
+ };
+
+ static inline int dmaengine_slave_config(struct dma_chan *chan,
+diff --git a/include/linux/dsa/ocelot.h b/include/linux/dsa/ocelot.h
+index 8ae999f587c48..289064b51fa9a 100644
+--- a/include/linux/dsa/ocelot.h
++++ b/include/linux/dsa/ocelot.h
+@@ -12,6 +12,7 @@
+ struct ocelot_skb_cb {
+ struct sk_buff *clone;
+ unsigned int ptp_class; /* valid only for clones */
++ u32 tstamp_lo;
+ u8 ptp_cmd;
+ u8 ts_id;
+ };
+diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
+index 1e7bf78cb3829..aba348d58ff61 100644
+--- a/include/linux/ethtool_netlink.h
++++ b/include/linux/ethtool_netlink.h
+@@ -10,6 +10,9 @@
+ #define __ETHTOOL_LINK_MODE_MASK_NWORDS \
+ DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
+
++#define ETHTOOL_PAUSE_STAT_CNT (__ETHTOOL_A_PAUSE_STAT_CNT - \
++ ETHTOOL_A_PAUSE_STAT_TX_FRAMES)
++
+ enum ethtool_multicast_groups {
+ ETHNL_MCGRP_MONITOR,
+ };
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index ef03ff34234d8..1611dc9d44207 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -613,13 +613,14 @@ static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog,
+ if (static_branch_unlikely(&bpf_stats_enabled_key)) {
+ struct bpf_prog_stats *stats;
+ u64 start = sched_clock();
++ unsigned long flags;
+
+ ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
+ stats = this_cpu_ptr(prog->stats);
+- u64_stats_update_begin(&stats->syncp);
++ flags = u64_stats_update_begin_irqsave(&stats->syncp);
+ stats->cnt++;
+ stats->nsecs += sched_clock() - start;
+- u64_stats_update_end(&stats->syncp);
++ u64_stats_update_end_irqrestore(&stats->syncp, flags);
+ } else {
+ ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
+ }
+@@ -638,9 +639,6 @@ static __always_inline u32 bpf_prog_run(const struct bpf_prog *prog, const void
+ * This uses migrate_disable/enable() explicitly to document that the
+ * invocation of a BPF program does not require reentrancy protection
+ * against a BPF program which is invoked from a preempting task.
+- *
+- * For non RT enabled kernels migrate_disable/enable() maps to
+- * preempt_disable/enable(), i.e. it disables also preemption.
+ */
+ static inline u32 bpf_prog_run_pin_on_cpu(const struct bpf_prog *prog,
+ const void *ctx)
+diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h
+index c1be37437e778..0c70febd03e95 100644
+--- a/include/linux/fortify-string.h
++++ b/include/linux/fortify-string.h
+@@ -280,7 +280,10 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q)
+ if (p_size == (size_t)-1 && q_size == (size_t)-1)
+ return __underlying_strcpy(p, q);
+ size = strlen(q) + 1;
+- /* test here to use the more stringent object size */
++ /* Compile-time check for const size overflow. */
++ if (__builtin_constant_p(size) && p_size < size)
++ __write_overflow();
++ /* Run-time check for dynamic size overflow. */
+ if (p_size < size)
+ fortify_panic(__func__);
+ memcpy(p, q, size);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index e7a633353fd20..56eba723477e3 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2498,6 +2498,8 @@ enum file_time_flags {
+
+ extern bool atime_needs_update(const struct path *, struct inode *);
+ extern void touch_atime(const struct path *);
++int inode_update_time(struct inode *inode, struct timespec64 *time, int flags);
++
+ static inline void file_accessed(struct file *file)
+ {
+ if (!(file->f_flags & O_NOATIME))
+diff --git a/include/linux/hid.h b/include/linux/hid.h
+index 9e067f937dbc2..f453be385bd47 100644
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -840,6 +840,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev,
+ return hdev->ll_driver == driver;
+ }
+
++static inline bool hid_is_usb(struct hid_device *hdev)
++{
++ return hid_is_using_ll_driver(hdev, &usb_hid_driver);
++}
++
+ #define PM_HINT_FULLON 1<<5
+ #define PM_HINT_NORMAL 1<<1
+
+diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
+index 05e22770af517..b75395ec8d521 100644
+--- a/include/linux/ipc_namespace.h
++++ b/include/linux/ipc_namespace.h
+@@ -131,6 +131,16 @@ static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
+ return ns;
+ }
+
++static inline struct ipc_namespace *get_ipc_ns_not_zero(struct ipc_namespace *ns)
++{
++ if (ns) {
++ if (refcount_inc_not_zero(&ns->ns.count))
++ return ns;
++ }
++
++ return NULL;
++}
++
+ extern void put_ipc_ns(struct ipc_namespace *ns);
+ #else
+ static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
+@@ -147,6 +157,11 @@ static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
+ return ns;
+ }
+
++static inline struct ipc_namespace *get_ipc_ns_not_zero(struct ipc_namespace *ns)
++{
++ return ns;
++}
++
+ static inline void put_ipc_ns(struct ipc_namespace *ns)
+ {
+ }
+diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
+index 44ae1a7eb9e39..69ae6b2784645 100644
+--- a/include/linux/kernel_stat.h
++++ b/include/linux/kernel_stat.h
+@@ -102,6 +102,7 @@ extern void account_system_index_time(struct task_struct *, u64,
+ enum cpu_usage_stat);
+ extern void account_steal_time(u64);
+ extern void account_idle_time(u64);
++extern u64 get_idle_time(struct kernel_cpustat *kcs, int cpu);
+
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+ static inline void account_process_tick(struct task_struct *tsk, int user)
+diff --git a/include/linux/kfence.h b/include/linux/kfence.h
+index 3fe6dd8a18c19..4b5e3679a72c7 100644
+--- a/include/linux/kfence.h
++++ b/include/linux/kfence.h
+@@ -14,6 +14,9 @@
+
+ #ifdef CONFIG_KFENCE
+
++#include <linux/atomic.h>
++#include <linux/static_key.h>
++
+ /*
+ * We allocate an even number of pages, as it simplifies calculations to map
+ * address to metadata indices; effectively, the very first page serves as an
+@@ -22,13 +25,8 @@
+ #define KFENCE_POOL_SIZE ((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 * PAGE_SIZE)
+ extern char *__kfence_pool;
+
+-#ifdef CONFIG_KFENCE_STATIC_KEYS
+-#include <linux/static_key.h>
+ DECLARE_STATIC_KEY_FALSE(kfence_allocation_key);
+-#else
+-#include <linux/atomic.h>
+ extern atomic_t kfence_allocation_gate;
+-#endif
+
+ /**
+ * is_kfence_address() - check if an address belongs to KFENCE pool
+@@ -116,13 +114,16 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags);
+ */
+ static __always_inline void *kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags)
+ {
+-#ifdef CONFIG_KFENCE_STATIC_KEYS
+- if (static_branch_unlikely(&kfence_allocation_key))
++#if defined(CONFIG_KFENCE_STATIC_KEYS) || CONFIG_KFENCE_SAMPLE_INTERVAL == 0
++ if (!static_branch_unlikely(&kfence_allocation_key))
++ return NULL;
+ #else
+- if (unlikely(!atomic_read(&kfence_allocation_gate)))
++ if (!static_branch_likely(&kfence_allocation_key))
++ return NULL;
+ #endif
+- return __kfence_alloc(s, size, flags);
+- return NULL;
++ if (likely(atomic_read(&kfence_allocation_gate)))
++ return NULL;
++ return __kfence_alloc(s, size, flags);
+ }
+
+ /**
+diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
+index e4f3bfe087570..ef8c7accbc689 100644
+--- a/include/linux/kprobes.h
++++ b/include/linux/kprobes.h
+@@ -154,6 +154,8 @@ struct kretprobe {
+ struct kretprobe_holder *rph;
+ };
+
++#define KRETPROBE_MAX_DATA_SIZE 4096
++
+ struct kretprobe_instance {
+ union {
+ struct freelist_node freelist;
+diff --git a/include/linux/libata.h b/include/linux/libata.h
+index c0c64f03e1074..a64e12605d31d 100644
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -394,7 +394,7 @@ enum {
+ /* This should match the actual table size of
+ * ata_eh_cmd_timeout_table in libata-eh.c.
+ */
+- ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 6,
++ ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 7,
+
+ /* Horkage types. May be set by libata or controller on drives
+ (some horkage may be drive/controller pair dependent */
+diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
+index 2adeea44c0d53..61590c1f2d333 100644
+--- a/include/linux/lsm_hook_defs.h
++++ b/include/linux/lsm_hook_defs.h
+@@ -26,13 +26,13 @@
+ * #undef LSM_HOOK
+ * };
+ */
+-LSM_HOOK(int, 0, binder_set_context_mgr, struct task_struct *mgr)
+-LSM_HOOK(int, 0, binder_transaction, struct task_struct *from,
+- struct task_struct *to)
+-LSM_HOOK(int, 0, binder_transfer_binder, struct task_struct *from,
+- struct task_struct *to)
+-LSM_HOOK(int, 0, binder_transfer_file, struct task_struct *from,
+- struct task_struct *to, struct file *file)
++LSM_HOOK(int, 0, binder_set_context_mgr, const struct cred *mgr)
++LSM_HOOK(int, 0, binder_transaction, const struct cred *from,
++ const struct cred *to)
++LSM_HOOK(int, 0, binder_transfer_binder, const struct cred *from,
++ const struct cred *to)
++LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
++ const struct cred *to, struct file *file)
+ LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
+ unsigned int mode)
+ LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
+diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
+index 5c4c5c0602cb7..59024618554e2 100644
+--- a/include/linux/lsm_hooks.h
++++ b/include/linux/lsm_hooks.h
+@@ -1313,22 +1313,22 @@
+ *
+ * @binder_set_context_mgr:
+ * Check whether @mgr is allowed to be the binder context manager.
+- * @mgr contains the task_struct for the task being registered.
++ * @mgr contains the struct cred for the current binder process.
+ * Return 0 if permission is granted.
+ * @binder_transaction:
+ * Check whether @from is allowed to invoke a binder transaction call
+ * to @to.
+- * @from contains the task_struct for the sending task.
+- * @to contains the task_struct for the receiving task.
++ * @from contains the struct cred for the sending process.
++ * @to contains the struct cred for the receiving process.
+ * @binder_transfer_binder:
+ * Check whether @from is allowed to transfer a binder reference to @to.
+- * @from contains the task_struct for the sending task.
+- * @to contains the task_struct for the receiving task.
++ * @from contains the struct cred for the sending process.
++ * @to contains the struct cred for the receiving process.
+ * @binder_transfer_file:
+ * Check whether @from is allowed to transfer @file to @to.
+- * @from contains the task_struct for the sending task.
++ * @from contains the struct cred for the sending process.
+ * @file contains the struct file being transferred.
+- * @to contains the task_struct for the receiving task.
++ * @to contains the struct cred for the receiving process.
+ *
+ * @ptrace_access_check:
+ * Check permission before allowing the current process to trace the
+diff --git a/include/linux/mhi.h b/include/linux/mhi.h
+index 7239858790353..a5cc4cdf9cc86 100644
+--- a/include/linux/mhi.h
++++ b/include/linux/mhi.h
+@@ -663,6 +663,19 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl);
+ */
+ int mhi_pm_resume(struct mhi_controller *mhi_cntrl);
+
++/**
++ * mhi_pm_resume_force - Force resume MHI from suspended state
++ * @mhi_cntrl: MHI controller
++ *
++ * Resume the device irrespective of its MHI state. As per the MHI spec, devices
++ * has to be in M3 state during resume. But some devices seem to be in a
++ * different MHI state other than M3 but they continue working fine if allowed.
++ * This API is intented to be used for such devices.
++ *
++ * Return: 0 if the resume succeeds, a negative error code otherwise
++ */
++int mhi_pm_resume_force(struct mhi_controller *mhi_cntrl);
++
+ /**
+ * mhi_download_rddm_image - Download ramdump image from device for
+ * debugging purpose.
+diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h
+index 4ab5c1fc1270d..a09ed4c8361b6 100644
+--- a/include/linux/mlx5/eswitch.h
++++ b/include/linux/mlx5/eswitch.h
+@@ -136,13 +136,13 @@ u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
+ ESW_TUN_OPTS_SLOW_TABLE_GOTO_VPORT)
+ #define ESW_TUN_SLOW_TABLE_GOTO_VPORT_MARK ESW_TUN_OPTS_MASK
+
+-u8 mlx5_eswitch_mode(struct mlx5_core_dev *dev);
++u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev);
+ u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev);
+ struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw);
+
+ #else /* CONFIG_MLX5_ESWITCH */
+
+-static inline u8 mlx5_eswitch_mode(struct mlx5_core_dev *dev)
++static inline u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
+ {
+ return MLX5_ESWITCH_NONE;
+ }
+diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
+index 993204a6c1a13..25d775764a5ac 100644
+--- a/include/linux/mlx5/mlx5_ifc.h
++++ b/include/linux/mlx5/mlx5_ifc.h
+@@ -3309,8 +3309,8 @@ enum {
+ };
+
+ enum {
+- MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO = 0x1,
+- MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO = 0x2,
++ MLX5_TIRC_PACKET_MERGE_MASK_IPV4_LRO = BIT(0),
++ MLX5_TIRC_PACKET_MERGE_MASK_IPV6_LRO = BIT(1),
+ };
+
+ enum {
+@@ -3335,7 +3335,7 @@ struct mlx5_ifc_tirc_bits {
+
+ u8 reserved_at_80[0x4];
+ u8 lro_timeout_period_usecs[0x10];
+- u8 lro_enable_mask[0x4];
++ u8 packet_merge_mask[0x4];
+ u8 lro_max_ip_payload_size[0x8];
+
+ u8 reserved_at_a0[0x40];
+@@ -6369,7 +6369,7 @@ struct mlx5_ifc_modify_tir_bitmask_bits {
+ u8 reserved_at_3c[0x1];
+ u8 hash[0x1];
+ u8 reserved_at_3e[0x1];
+- u8 lro[0x1];
++ u8 packet_merge[0x1];
+ };
+
+ struct mlx5_ifc_modify_tir_out_bits {
+diff --git a/include/linux/msi.h b/include/linux/msi.h
+index 49cf6eb222e76..e616f94c7c585 100644
+--- a/include/linux/msi.h
++++ b/include/linux/msi.h
+@@ -148,7 +148,7 @@ struct msi_desc {
+ u8 is_msix : 1;
+ u8 multiple : 3;
+ u8 multi_cap : 3;
+- u8 maskbit : 1;
++ u8 can_mask : 1;
+ u8 is_64 : 1;
+ u8 is_virtual : 1;
+ u16 entry_nr;
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index d79163208dfdb..ce81cc96a98d9 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -4403,7 +4403,8 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
+ static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
+ {
+ spin_lock(&txq->_xmit_lock);
+- txq->xmit_lock_owner = cpu;
++ /* Pairs with READ_ONCE() in __dev_queue_xmit() */
++ WRITE_ONCE(txq->xmit_lock_owner, cpu);
+ }
+
+ static inline bool __netif_tx_acquire(struct netdev_queue *txq)
+@@ -4420,26 +4421,32 @@ static inline void __netif_tx_release(struct netdev_queue *txq)
+ static inline void __netif_tx_lock_bh(struct netdev_queue *txq)
+ {
+ spin_lock_bh(&txq->_xmit_lock);
+- txq->xmit_lock_owner = smp_processor_id();
++ /* Pairs with READ_ONCE() in __dev_queue_xmit() */
++ WRITE_ONCE(txq->xmit_lock_owner, smp_processor_id());
+ }
+
+ static inline bool __netif_tx_trylock(struct netdev_queue *txq)
+ {
+ bool ok = spin_trylock(&txq->_xmit_lock);
+- if (likely(ok))
+- txq->xmit_lock_owner = smp_processor_id();
++
++ if (likely(ok)) {
++ /* Pairs with READ_ONCE() in __dev_queue_xmit() */
++ WRITE_ONCE(txq->xmit_lock_owner, smp_processor_id());
++ }
+ return ok;
+ }
+
+ static inline void __netif_tx_unlock(struct netdev_queue *txq)
+ {
+- txq->xmit_lock_owner = -1;
++ /* Pairs with READ_ONCE() in __dev_queue_xmit() */
++ WRITE_ONCE(txq->xmit_lock_owner, -1);
+ spin_unlock(&txq->_xmit_lock);
+ }
+
+ static inline void __netif_tx_unlock_bh(struct netdev_queue *txq)
+ {
+- txq->xmit_lock_owner = -1;
++ /* Pairs with READ_ONCE() in __dev_queue_xmit() */
++ WRITE_ONCE(txq->xmit_lock_owner, -1);
+ spin_unlock_bh(&txq->_xmit_lock);
+ }
+
+diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
+index b9a8b925db430..4d95cc999d121 100644
+--- a/include/linux/nfs_fs.h
++++ b/include/linux/nfs_fs.h
+@@ -569,6 +569,7 @@ extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
+ extern int nfs_commit_inode(struct inode *, int);
+ extern struct nfs_commit_data *nfs_commitdata_alloc(bool never_fail);
+ extern void nfs_commit_free(struct nfs_commit_data *data);
++bool nfs_commit_end(struct nfs_mds_commit_info *cinfo);
+
+ static inline int
+ nfs_have_writebacks(struct inode *inode)
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index cd8aa6fce2041..152a4d74f87f0 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -233,6 +233,8 @@ enum pci_dev_flags {
+ PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
+ /* Don't use Relaxed Ordering for TLPs directed at this device */
+ PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
++ /* Device does honor MSI masking despite saying otherwise */
++ PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
+ };
+
+ enum pci_irq_reroute_variant {
+diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
+index 9837fb011f2fb..989aa30c598dc 100644
+--- a/include/linux/platform_data/ti-sysc.h
++++ b/include/linux/platform_data/ti-sysc.h
+@@ -50,6 +50,7 @@ struct sysc_regbits {
+ s8 emufree_shift;
+ };
+
++#define SYSC_QUIRK_REINIT_ON_CTX_LOST BIT(28)
+ #define SYSC_QUIRK_REINIT_ON_RESUME BIT(27)
+ #define SYSC_QUIRK_GPMC_DEBUG BIT(26)
+ #define SYSC_MODULE_QUIRK_ENA_RESETDONE BIT(25)
+diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
+index 222da43b7096d..eddd66d426caf 100644
+--- a/include/linux/pm_runtime.h
++++ b/include/linux/pm_runtime.h
+@@ -129,7 +129,7 @@ static inline bool pm_runtime_suspended(struct device *dev)
+ * pm_runtime_active - Check whether or not a device is runtime-active.
+ * @dev: Target device.
+ *
+- * Return %true if runtime PM is enabled for @dev and its runtime PM status is
++ * Return %true if runtime PM is disabled for @dev or its runtime PM status is
+ * %RPM_ACTIVE, or %false otherwise.
+ *
+ * Note that the return value of this function can only be trusted if it is
+diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
+index 00fef0064355f..5bbcd280bfd26 100644
+--- a/include/linux/posix-timers.h
++++ b/include/linux/posix-timers.h
+@@ -184,8 +184,10 @@ static inline void posix_cputimers_group_init(struct posix_cputimers *pct,
+ #endif
+
+ #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
++void clear_posix_cputimers_work(struct task_struct *p);
+ void posix_cputimers_init_work(void);
+ #else
++static inline void clear_posix_cputimers_work(struct task_struct *p) { }
+ static inline void posix_cputimers_init_work(void) { }
+ #endif
+
+diff --git a/include/linux/printk.h b/include/linux/printk.h
+index 85b656f82d752..9497f6b983399 100644
+--- a/include/linux/printk.h
++++ b/include/linux/printk.h
+@@ -198,6 +198,7 @@ void dump_stack_print_info(const char *log_lvl);
+ void show_regs_print_info(const char *log_lvl);
+ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
+ extern asmlinkage void dump_stack(void) __cold;
++void printk_trigger_flush(void);
+ #else
+ static inline __printf(1, 0)
+ int vprintk(const char *s, va_list args)
+@@ -274,6 +275,9 @@ static inline void dump_stack_lvl(const char *log_lvl)
+ static inline void dump_stack(void)
+ {
+ }
++static inline void printk_trigger_flush(void)
++{
++}
+ #endif
+
+ #ifdef CONFIG_SMP
+diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
+index d97dcd049f18f..a8dcf8a9ae885 100644
+--- a/include/linux/rpmsg.h
++++ b/include/linux/rpmsg.h
+@@ -231,7 +231,7 @@ static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+- return ERR_PTR(-ENXIO);
++ return NULL;
+ }
+
+ static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
+index e5f4ce622ee61..9a707b555b0a0 100644
+--- a/include/linux/sched/signal.h
++++ b/include/linux/sched/signal.h
+@@ -338,6 +338,8 @@ extern int kill_pid(struct pid *pid, int sig, int priv);
+ extern __must_check bool do_notify_parent(struct task_struct *, int);
+ extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent);
+ extern void force_sig(int);
++extern void force_fatal_sig(int);
++extern void force_exit_sig(int);
+ extern int send_sig(int, struct task_struct *, int);
+ extern int zap_other_threads(struct task_struct *p);
+ extern struct sigqueue *sigqueue_alloc(void);
+diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h
+index ef02be869cf28..058d7f371e25a 100644
+--- a/include/linux/sched/task.h
++++ b/include/linux/sched/task.h
+@@ -54,7 +54,8 @@ extern asmlinkage void schedule_tail(struct task_struct *prev);
+ extern void init_idle(struct task_struct *idle, int cpu);
+
+ extern int sched_fork(unsigned long clone_flags, struct task_struct *p);
+-extern void sched_post_fork(struct task_struct *p);
++extern void sched_post_fork(struct task_struct *p,
++ struct kernel_clone_args *kargs);
+ extern void sched_dead(struct task_struct *p);
+
+ void __noreturn do_task_dead(void);
+@@ -157,7 +158,7 @@ static inline struct vm_struct *task_stack_vm_area(const struct task_struct *t)
+ * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
+ * subscriptions and synchronises with wait4(). Also used in procfs. Also
+ * pins the final release of task.io_context. Also protects ->cpuset and
+- * ->cgroup.subsys[]. And ->vfork_done.
++ * ->cgroup.subsys[]. And ->vfork_done. And ->sysvshm.shm_clist.
+ *
+ * Nests both inside and outside of read_lock(&tasklist_lock).
+ * It must not be nested with write_lock_irq(&tasklist_lock),
+diff --git a/include/linux/sched/task_stack.h b/include/linux/sched/task_stack.h
+index 2413427e439c7..d10150587d819 100644
+--- a/include/linux/sched/task_stack.h
++++ b/include/linux/sched/task_stack.h
+@@ -25,7 +25,11 @@ static inline void *task_stack_page(const struct task_struct *task)
+
+ static inline unsigned long *end_of_stack(const struct task_struct *task)
+ {
++#ifdef CONFIG_STACK_GROWSUP
++ return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1;
++#else
+ return task->stack;
++#endif
+ }
+
+ #elif !defined(__HAVE_THREAD_FUNCTIONS)
+diff --git a/include/linux/security.h b/include/linux/security.h
+index 5b7288521300b..46a02ce34d00b 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -258,13 +258,13 @@ extern int security_init(void);
+ extern int early_security_init(void);
+
+ /* Security operations */
+-int security_binder_set_context_mgr(struct task_struct *mgr);
+-int security_binder_transaction(struct task_struct *from,
+- struct task_struct *to);
+-int security_binder_transfer_binder(struct task_struct *from,
+- struct task_struct *to);
+-int security_binder_transfer_file(struct task_struct *from,
+- struct task_struct *to, struct file *file);
++int security_binder_set_context_mgr(const struct cred *mgr);
++int security_binder_transaction(const struct cred *from,
++ const struct cred *to);
++int security_binder_transfer_binder(const struct cred *from,
++ const struct cred *to);
++int security_binder_transfer_file(const struct cred *from,
++ const struct cred *to, struct file *file);
+ int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
+ int security_ptrace_traceme(struct task_struct *parent);
+ int security_capget(struct task_struct *target,
+@@ -508,25 +508,25 @@ static inline int early_security_init(void)
+ return 0;
+ }
+
+-static inline int security_binder_set_context_mgr(struct task_struct *mgr)
++static inline int security_binder_set_context_mgr(const struct cred *mgr)
+ {
+ return 0;
+ }
+
+-static inline int security_binder_transaction(struct task_struct *from,
+- struct task_struct *to)
++static inline int security_binder_transaction(const struct cred *from,
++ const struct cred *to)
+ {
+ return 0;
+ }
+
+-static inline int security_binder_transfer_binder(struct task_struct *from,
+- struct task_struct *to)
++static inline int security_binder_transfer_binder(const struct cred *from,
++ const struct cred *to)
+ {
+ return 0;
+ }
+
+-static inline int security_binder_transfer_file(struct task_struct *from,
+- struct task_struct *to,
++static inline int security_binder_transfer_file(const struct cred *from,
++ const struct cred *to,
+ struct file *file)
+ {
+ return 0;
+@@ -1041,6 +1041,11 @@ static inline void security_transfer_creds(struct cred *new,
+ {
+ }
+
++static inline void security_cred_getsecid(const struct cred *c, u32 *secid)
++{
++ *secid = 0;
++}
++
+ static inline int security_kernel_act_as(struct cred *cred, u32 secid)
+ {
+ return 0;
+diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
+index dd99569595fd3..5733890df64f5 100644
+--- a/include/linux/seq_file.h
++++ b/include/linux/seq_file.h
+@@ -194,7 +194,7 @@ static const struct file_operations __name ## _fops = { \
+ #define DEFINE_PROC_SHOW_ATTRIBUTE(__name) \
+ static int __name ## _open(struct inode *inode, struct file *file) \
+ { \
+- return single_open(file, __name ## _show, inode->i_private); \
++ return single_open(file, __name ## _show, PDE_DATA(inode)); \
+ } \
+ \
+ static const struct proc_ops __name ## _proc_ops = { \
+diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h
+index 34cb28b8f16ca..a70b2bdbf4d96 100644
+--- a/include/linux/signal_types.h
++++ b/include/linux/signal_types.h
+@@ -70,6 +70,9 @@ struct ksignal {
+ int sig;
+ };
+
++/* Used to kill the race between sigaction and forced signals */
++#define SA_IMMUTABLE 0x00800000
++
+ #ifndef __ARCH_UAPI_SA_FLAGS
+ #ifdef SA_RESTORER
+ #define __ARCH_UAPI_SA_FLAGS SA_RESTORER
+diff --git a/include/linux/siphash.h b/include/linux/siphash.h
+index bf21591a9e5e6..0cda61855d907 100644
+--- a/include/linux/siphash.h
++++ b/include/linux/siphash.h
+@@ -27,9 +27,7 @@ static inline bool siphash_key_is_zero(const siphash_key_t *key)
+ }
+
+ u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
+-#endif
+
+ u64 siphash_1u64(const u64 a, const siphash_key_t *key);
+ u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
+@@ -82,10 +80,9 @@ static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
+ static inline u64 siphash(const void *data, size_t len,
+ const siphash_key_t *key)
+ {
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+- if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
++ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
++ !IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
+ return __siphash_unaligned(data, len, key);
+-#endif
+ return ___siphash_aligned(data, len, key);
+ }
+
+@@ -96,10 +93,8 @@ typedef struct {
+
+ u32 __hsiphash_aligned(const void *data, size_t len,
+ const hsiphash_key_t *key);
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u32 __hsiphash_unaligned(const void *data, size_t len,
+ const hsiphash_key_t *key);
+-#endif
+
+ u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
+ u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
+@@ -135,10 +130,9 @@ static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
+ static inline u32 hsiphash(const void *data, size_t len,
+ const hsiphash_key_t *key)
+ {
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+- if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
++ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
++ !IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
+ return __hsiphash_unaligned(data, len, key);
+-#endif
+ return ___hsiphash_aligned(data, len, key);
+ }
+
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 841e2f0f5240b..b8c273af2910c 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -1671,6 +1671,22 @@ static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
+ return 0;
+ }
+
++/* This variant of skb_unclone() makes sure skb->truesize is not changed */
++static inline int skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri)
++{
++ might_sleep_if(gfpflags_allow_blocking(pri));
++
++ if (skb_cloned(skb)) {
++ unsigned int save = skb->truesize;
++ int res;
++
++ res = pskb_expand_head(skb, 0, 0, pri);
++ skb->truesize = save;
++ return res;
++ }
++ return 0;
++}
++
+ /**
+ * skb_header_cloned - is the header a clone
+ * @skb: buffer to check
+diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
+index 1ce9a9eb223b6..b4256847c7079 100644
+--- a/include/linux/skmsg.h
++++ b/include/linux/skmsg.h
+@@ -509,8 +509,22 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock)
+
+ #if IS_ENABLED(CONFIG_NET_SOCK_MSG)
+
+-/* We only have one bit so far. */
+-#define BPF_F_PTR_MASK ~(BPF_F_INGRESS)
++#define BPF_F_STRPARSER (1UL << 1)
++
++/* We only have two bits so far. */
++#define BPF_F_PTR_MASK ~(BPF_F_INGRESS | BPF_F_STRPARSER)
++
++static inline bool skb_bpf_strparser(const struct sk_buff *skb)
++{
++ unsigned long sk_redir = skb->_sk_redir;
++
++ return sk_redir & BPF_F_STRPARSER;
++}
++
++static inline void skb_bpf_set_strparser(struct sk_buff *skb)
++{
++ skb->_sk_redir |= BPF_F_STRPARSER;
++}
+
+ static inline bool skb_bpf_ingress(const struct sk_buff *skb)
+ {
+diff --git a/include/linux/string.h b/include/linux/string.h
+index 5e96d656be7ae..d68097b4f600b 100644
+--- a/include/linux/string.h
++++ b/include/linux/string.h
+@@ -262,23 +262,8 @@ void __write_overflow(void) __compiletime_error("detected write beyond size of o
+ #include <linux/fortify-string.h>
+ #endif
+
+-/**
+- * memcpy_and_pad - Copy one buffer to another with padding
+- * @dest: Where to copy to
+- * @dest_len: The destination buffer size
+- * @src: Where to copy from
+- * @count: The number of bytes to copy
+- * @pad: Character to use for padding if space is left in destination.
+- */
+-static inline void memcpy_and_pad(void *dest, size_t dest_len,
+- const void *src, size_t count, int pad)
+-{
+- if (dest_len > count) {
+- memcpy(dest, src, count);
+- memset(dest + count, pad, dest_len - count);
+- } else
+- memcpy(dest, src, dest_len);
+-}
++void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
++ int pad);
+
+ /**
+ * str_has_prefix - Test if a string has a given prefix
+diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
+index 068e1982ad371..74bfdffaf7b0e 100644
+--- a/include/linux/surface_aggregator/controller.h
++++ b/include/linux/surface_aggregator/controller.h
+@@ -792,8 +792,8 @@ enum ssam_event_mask {
+ #define SSAM_EVENT_REGISTRY_KIP \
+ SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28)
+
+-#define SSAM_EVENT_REGISTRY_REG \
+- SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, 0x02, 0x01, 0x02)
++#define SSAM_EVENT_REGISTRY_REG(tid)\
++ SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02)
+
+ /**
+ * enum ssam_event_notifier_flags - Flags for event notifiers.
+diff --git a/include/linux/tpm.h b/include/linux/tpm.h
+index aa11fe323c56b..12d827734686d 100644
+--- a/include/linux/tpm.h
++++ b/include/linux/tpm.h
+@@ -269,6 +269,7 @@ enum tpm2_cc_attrs {
+ #define TPM_VID_INTEL 0x8086
+ #define TPM_VID_WINBOND 0x1050
+ #define TPM_VID_STM 0x104A
++#define TPM_VID_ATML 0x1114
+
+ enum tpm_chip_flags {
+ TPM_CHIP_FLAG_TPM2 = BIT(1),
+diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
+index 3e475eeb5a995..57113190448c6 100644
+--- a/include/linux/trace_events.h
++++ b/include/linux/trace_events.h
+@@ -673,7 +673,7 @@ struct trace_event_file {
+
+ #define PERF_MAX_TRACE_SIZE 2048
+
+-#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
++#define MAX_FILTER_STR_VAL 256U /* Should handle KSYM_SYMBOL_LEN */
+
+ enum event_trigger_type {
+ ETT_NONE = (0),
+diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
+index 2c1fc9212cf28..548a028f2dabb 100644
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -124,7 +124,6 @@ struct usb_hcd {
+ #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */
+ #define HCD_FLAG_DEAD 6 /* controller has died? */
+ #define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */
+-#define HCD_FLAG_DEFER_RH_REGISTER 8 /* Defer roothub registration */
+
+ /* The flags can be tested using these macros; they are likely to
+ * be slightly faster than test_bit().
+@@ -135,7 +134,6 @@ struct usb_hcd {
+ #define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
+ #define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
+ #define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
+-#define HCD_DEFER_RH_REGISTER(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEFER_RH_REGISTER))
+
+ /*
+ * Specifies if interfaces are authorized by default
+diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
+index b465f8f3e554f..04e87f4b9417c 100644
+--- a/include/linux/virtio_net.h
++++ b/include/linux/virtio_net.h
+@@ -120,10 +120,15 @@ retry:
+
+ if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+ u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
++ unsigned int nh_off = p_off;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+
++ /* UFO may not include transport header in gso_size. */
++ if (gso_type & SKB_GSO_UDP)
++ nh_off -= thlen;
++
+ /* Too small packets are not really GSO ones. */
+- if (skb->len - p_off > gso_size) {
++ if (skb->len - nh_off > gso_size) {
+ shinfo->gso_size = gso_size;
+ shinfo->gso_type = gso_type;
+
+diff --git a/include/linux/wait.h b/include/linux/wait.h
+index 93dab0e9580f8..d22cf2985b8fd 100644
+--- a/include/linux/wait.h
++++ b/include/linux/wait.h
+@@ -217,6 +217,7 @@ void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void
+ void __wake_up_locked_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void *key);
+ void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr);
+ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode);
++void __wake_up_pollfree(struct wait_queue_head *wq_head);
+
+ #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
+ #define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL)
+@@ -245,6 +246,31 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode);
+ #define wake_up_interruptible_sync_poll_locked(x, m) \
+ __wake_up_locked_sync_key((x), TASK_INTERRUPTIBLE, poll_to_key(m))
+
++/**
++ * wake_up_pollfree - signal that a polled waitqueue is going away
++ * @wq_head: the wait queue head
++ *
++ * In the very rare cases where a ->poll() implementation uses a waitqueue whose
++ * lifetime is tied to a task rather than to the 'struct file' being polled,
++ * this function must be called before the waitqueue is freed so that
++ * non-blocking polls (e.g. epoll) are notified that the queue is going away.
++ *
++ * The caller must also RCU-delay the freeing of the wait_queue_head, e.g. via
++ * an explicit synchronize_rcu() or call_rcu(), or via SLAB_TYPESAFE_BY_RCU.
++ */
++static inline void wake_up_pollfree(struct wait_queue_head *wq_head)
++{
++ /*
++ * For performance reasons, we don't always take the queue lock here.
++ * Therefore, we might race with someone removing the last entry from
++ * the queue, and proceed while they still hold the queue lock.
++ * However, rcu_read_lock() is required to be held in such cases, so we
++ * can safely proceed with an RCU-delayed free.
++ */
++ if (waitqueue_active(wq_head))
++ __wake_up_pollfree(wq_head);
++}
++
+ #define ___wait_cond_timeout(condition) \
+ ({ \
+ bool __cond = (condition); \
+diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
+index 12955cb460d23..3b5986cee0739 100644
+--- a/include/media/videobuf2-core.h
++++ b/include/media/videobuf2-core.h
+@@ -46,6 +46,7 @@ enum vb2_memory {
+
+ struct vb2_fileio_data;
+ struct vb2_threadio_data;
++struct vb2_buffer;
+
+ /**
+ * struct vb2_mem_ops - memory handling/memory allocator operations.
+@@ -53,10 +54,8 @@ struct vb2_threadio_data;
+ * return ERR_PTR() on failure or a pointer to allocator private,
+ * per-buffer data on success; the returned private structure
+ * will then be passed as @buf_priv argument to other ops in this
+- * structure. Additional gfp_flags to use when allocating the
+- * are also passed to this operation. These flags are from the
+- * gfp_flags field of vb2_queue. The size argument to this function
+- * shall be *page aligned*.
++ * structure. The size argument to this function shall be
++ * *page aligned*.
+ * @put: inform the allocator that the buffer will no longer be used;
+ * usually will result in the allocator freeing the buffer (if
+ * no other users of this buffer are present); the @buf_priv
+@@ -117,31 +116,33 @@ struct vb2_threadio_data;
+ * map_dmabuf, unmap_dmabuf.
+ */
+ struct vb2_mem_ops {
+- void *(*alloc)(struct device *dev, unsigned long attrs,
+- unsigned long size,
+- enum dma_data_direction dma_dir,
+- gfp_t gfp_flags);
++ void *(*alloc)(struct vb2_buffer *vb,
++ struct device *dev,
++ unsigned long size);
+ void (*put)(void *buf_priv);
+- struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags);
+-
+- void *(*get_userptr)(struct device *dev, unsigned long vaddr,
+- unsigned long size,
+- enum dma_data_direction dma_dir);
++ struct dma_buf *(*get_dmabuf)(struct vb2_buffer *vb,
++ void *buf_priv,
++ unsigned long flags);
++
++ void *(*get_userptr)(struct vb2_buffer *vb,
++ struct device *dev,
++ unsigned long vaddr,
++ unsigned long size);
+ void (*put_userptr)(void *buf_priv);
+
+ void (*prepare)(void *buf_priv);
+ void (*finish)(void *buf_priv);
+
+- void *(*attach_dmabuf)(struct device *dev,
++ void *(*attach_dmabuf)(struct vb2_buffer *vb,
++ struct device *dev,
+ struct dma_buf *dbuf,
+- unsigned long size,
+- enum dma_data_direction dma_dir);
++ unsigned long size);
+ void (*detach_dmabuf)(void *buf_priv);
+ int (*map_dmabuf)(void *buf_priv);
+ void (*unmap_dmabuf)(void *buf_priv);
+
+- void *(*vaddr)(void *buf_priv);
+- void *(*cookie)(void *buf_priv);
++ void *(*vaddr)(struct vb2_buffer *vb, void *buf_priv);
++ void *(*cookie)(struct vb2_buffer *vb, void *buf_priv);
+
+ unsigned int (*num_users)(void *buf_priv);
+
+diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h
+index e3e770f76f349..77c694a19149d 100644
+--- a/include/memory/renesas-rpc-if.h
++++ b/include/memory/renesas-rpc-if.h
+@@ -59,6 +59,7 @@ struct rpcif_op {
+
+ struct rpcif {
+ struct device *dev;
++ void __iomem *base;
+ void __iomem *dirmap;
+ struct regmap *regmap;
+ struct reset_control *rstc;
+diff --git a/include/net/bond_alb.h b/include/net/bond_alb.h
+index f6af76c87a6c3..191c36afa1f4a 100644
+--- a/include/net/bond_alb.h
++++ b/include/net/bond_alb.h
+@@ -126,7 +126,7 @@ struct tlb_slave_info {
+ struct alb_bond_info {
+ struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */
+ u32 unbalanced_load;
+- int tx_rebalance_counter;
++ atomic_t tx_rebalance_counter;
+ int lp_counter;
+ /* -------- rlb parameters -------- */
+ int rlb_enabled;
+diff --git a/include/net/dst_cache.h b/include/net/dst_cache.h
+index 67634675e9197..df6622a5fe98f 100644
+--- a/include/net/dst_cache.h
++++ b/include/net/dst_cache.h
+@@ -79,6 +79,17 @@ static inline void dst_cache_reset(struct dst_cache *dst_cache)
+ dst_cache->reset_ts = jiffies;
+ }
+
++/**
++ * dst_cache_reset_now - invalidate the cache contents immediately
++ * @dst_cache: the cache
++ *
++ * The caller must be sure there are no concurrent users, as this frees
++ * all dst_cache users immediately, rather than waiting for the next
++ * per-cpu usage like dst_cache_reset does. Most callers should use the
++ * higher speed lazily-freed dst_cache_reset function instead.
++ */
++void dst_cache_reset_now(struct dst_cache *dst_cache);
++
+ /**
+ * dst_cache_init - initialize the cache, allocating the required storage
+ * @dst_cache: the cache
+diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
+index 4b10676c69d19..bd07484ab9dd5 100644
+--- a/include/net/fib_rules.h
++++ b/include/net/fib_rules.h
+@@ -69,7 +69,7 @@ struct fib_rules_ops {
+ int (*action)(struct fib_rule *,
+ struct flowi *, int,
+ struct fib_lookup_arg *);
+- bool (*suppress)(struct fib_rule *,
++ bool (*suppress)(struct fib_rule *, int,
+ struct fib_lookup_arg *);
+ int (*match)(struct fib_rule *,
+ struct flowi *, int);
+@@ -218,7 +218,9 @@ INDIRECT_CALLABLE_DECLARE(int fib4_rule_action(struct fib_rule *rule,
+ struct fib_lookup_arg *arg));
+
+ INDIRECT_CALLABLE_DECLARE(bool fib6_rule_suppress(struct fib_rule *rule,
++ int flags,
+ struct fib_lookup_arg *arg));
+ INDIRECT_CALLABLE_DECLARE(bool fib4_rule_suppress(struct fib_rule *rule,
++ int flags,
+ struct fib_lookup_arg *arg));
+ #endif
+diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
+index b06c2d02ec84e..fa6a87246a7b8 100644
+--- a/include/net/inet_connection_sock.h
++++ b/include/net/inet_connection_sock.h
+@@ -289,7 +289,7 @@ static inline void inet_csk_prepare_for_destroy_sock(struct sock *sk)
+ {
+ /* The below has to be done to allow calling inet_csk_destroy_sock */
+ sock_set_flag(sk, SOCK_DEAD);
+- percpu_counter_inc(sk->sk_prot->orphan_count);
++ this_cpu_inc(*sk->sk_prot->orphan_count);
+ }
+
+ void inet_csk_destroy_sock(struct sock *sk);
+diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
+index c412dde4d67dc..83b8070d1cc93 100644
+--- a/include/net/ip6_fib.h
++++ b/include/net/ip6_fib.h
+@@ -485,6 +485,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
+ struct fib6_config *cfg, gfp_t gfp_flags,
+ struct netlink_ext_ack *extack);
+ void fib6_nh_release(struct fib6_nh *fib6_nh);
++void fib6_nh_release_dsts(struct fib6_nh *fib6_nh);
+
+ int call_fib6_entry_notifiers(struct net *net,
+ enum fib_event_type event_type,
+diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
+index ab5348e57db1a..3417ba2d27ad6 100644
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -438,7 +438,7 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ static inline int fib_num_tclassid_users(struct net *net)
+ {
+- return net->ipv4.fib_num_tclassid_users;
++ return atomic_read(&net->ipv4.fib_num_tclassid_users);
+ }
+ #else
+ static inline int fib_num_tclassid_users(struct net *net)
+diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h
+index afbce90c44808..45e0339be6fa4 100644
+--- a/include/net/ipv6_stubs.h
++++ b/include/net/ipv6_stubs.h
+@@ -47,6 +47,7 @@ struct ipv6_stub {
+ struct fib6_config *cfg, gfp_t gfp_flags,
+ struct netlink_ext_ack *extack);
+ void (*fib6_nh_release)(struct fib6_nh *fib6_nh);
++ void (*fib6_nh_release_dsts)(struct fib6_nh *fib6_nh);
+ void (*fib6_update_sernum)(struct net *net, struct fib6_info *rt);
+ int (*ip6_del_rt)(struct net *net, struct fib6_info *rt, bool skip_notify);
+ void (*fib6_rt_update)(struct net *net, struct fib6_info *rt,
+diff --git a/include/net/llc.h b/include/net/llc.h
+index df282d9b40170..9c10b121b49b0 100644
+--- a/include/net/llc.h
++++ b/include/net/llc.h
+@@ -72,7 +72,9 @@ struct llc_sap {
+ static inline
+ struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex)
+ {
+- return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES];
++ u32 bucket = hash_32(ifindex, LLC_SK_DEV_HASH_BITS);
++
++ return &sap->sk_dev_hash[bucket];
+ }
+
+ static inline
+diff --git a/include/net/neighbour.h b/include/net/neighbour.h
+index 22ced1381ede5..d5767e25509cc 100644
+--- a/include/net/neighbour.h
++++ b/include/net/neighbour.h
+@@ -253,6 +253,7 @@ static inline void *neighbour_priv(const struct neighbour *n)
+ #define NEIGH_UPDATE_F_OVERRIDE 0x00000001
+ #define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002
+ #define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004
++#define NEIGH_UPDATE_F_USE 0x10000000
+ #define NEIGH_UPDATE_F_EXT_LEARNED 0x20000000
+ #define NEIGH_UPDATE_F_ISROUTER 0x40000000
+ #define NEIGH_UPDATE_F_ADMIN 0x80000000
+@@ -504,10 +505,15 @@ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
+ {
+ const struct hh_cache *hh = &n->hh;
+
+- if ((n->nud_state & NUD_CONNECTED) && hh->hh_len && !skip_cache)
++ /* n->nud_state and hh->hh_len could be changed under us.
++ * neigh_hh_output() is taking care of the race later.
++ */
++ if (!skip_cache &&
++ (READ_ONCE(n->nud_state) & NUD_CONNECTED) &&
++ READ_ONCE(hh->hh_len))
+ return neigh_hh_output(hh, skb);
+- else
+- return n->output(n, skb);
++
++ return n->output(n, skb);
+ }
+
+ static inline struct neighbour *
+diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
+index cc663c68ddc4b..d24b0a34c8f0c 100644
+--- a/include/net/netfilter/nf_conntrack.h
++++ b/include/net/netfilter/nf_conntrack.h
+@@ -276,14 +276,14 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb)
+ /* jiffies until ct expires, 0 if already expired */
+ static inline unsigned long nf_ct_expires(const struct nf_conn *ct)
+ {
+- s32 timeout = ct->timeout - nfct_time_stamp;
++ s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
+
+ return timeout > 0 ? timeout : 0;
+ }
+
+ static inline bool nf_ct_is_expired(const struct nf_conn *ct)
+ {
+- return (__s32)(ct->timeout - nfct_time_stamp) <= 0;
++ return (__s32)(READ_ONCE(ct->timeout) - nfct_time_stamp) <= 0;
+ }
+
+ /* use after obtaining a reference count */
+@@ -302,7 +302,7 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
+ static inline void nf_ct_offload_timeout(struct nf_conn *ct)
+ {
+ if (nf_ct_expires(ct) < NF_CT_DAY / 2)
+- ct->timeout = nfct_time_stamp + NF_CT_DAY;
++ WRITE_ONCE(ct->timeout, nfct_time_stamp + NF_CT_DAY);
+ }
+
+ struct kernel_param;
+diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
+index 2f65701a43c95..6c5b2efc4f17d 100644
+--- a/include/net/netns/ipv4.h
++++ b/include/net/netns/ipv4.h
+@@ -65,7 +65,7 @@ struct netns_ipv4 {
+ bool fib_has_custom_local_routes;
+ bool fib_offload_disabled;
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+- int fib_num_tclassid_users;
++ atomic_t fib_num_tclassid_users;
+ #endif
+ struct hlist_head *fib_table_hash;
+ struct sock *fibnl;
+diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
+index a964daedc17b6..ea8595651c384 100644
+--- a/include/net/nfc/nci_core.h
++++ b/include/net/nfc/nci_core.h
+@@ -30,6 +30,7 @@ enum nci_flag {
+ NCI_UP,
+ NCI_DATA_EXCHANGE,
+ NCI_DATA_EXCHANGE_TO,
++ NCI_UNREG,
+ };
+
+ /* NCI device states */
+diff --git a/include/net/nl802154.h b/include/net/nl802154.h
+index ddcee128f5d9a..145acb8f25095 100644
+--- a/include/net/nl802154.h
++++ b/include/net/nl802154.h
+@@ -19,6 +19,8 @@
+ *
+ */
+
++#include <linux/types.h>
++
+ #define NL802154_GENL_NAME "nl802154"
+
+ enum nl802154_commands {
+@@ -150,10 +152,9 @@ enum nl802154_attrs {
+ };
+
+ enum nl802154_iftype {
+- /* for backwards compatibility TODO */
+- NL802154_IFTYPE_UNSPEC = -1,
++ NL802154_IFTYPE_UNSPEC = (~(__u32)0),
+
+- NL802154_IFTYPE_NODE,
++ NL802154_IFTYPE_NODE = 0,
+ NL802154_IFTYPE_MONITOR,
+ NL802154_IFTYPE_COORD,
+
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index c0069ac00e62d..8c2d611639fca 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -308,6 +308,8 @@ struct Qdisc_ops {
+ struct netlink_ext_ack *extack);
+ void (*attach)(struct Qdisc *sch);
+ int (*change_tx_queue_len)(struct Qdisc *, unsigned int);
++ void (*change_real_num_tx)(struct Qdisc *sch,
++ unsigned int new_real_tx);
+
+ int (*dump)(struct Qdisc *, struct sk_buff *);
+ int (*dump_stats)(struct Qdisc *, struct gnet_dump *);
+@@ -684,6 +686,8 @@ void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
+ void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
+
+ int dev_qdisc_change_tx_queue_len(struct net_device *dev);
++void dev_qdisc_change_real_num_tx(struct net_device *dev,
++ unsigned int new_real_tx);
+ void dev_init_scheduler(struct net_device *dev);
+ void dev_shutdown(struct net_device *dev);
+ void dev_activate(struct net_device *dev);
+diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
+index 69bab88ad66b1..189fdb9db1622 100644
+--- a/include/net/sctp/sctp.h
++++ b/include/net/sctp/sctp.h
+@@ -626,7 +626,8 @@ static inline __u32 sctp_min_frag_point(struct sctp_sock *sp, __u16 datasize)
+
+ static inline int sctp_transport_pl_hlen(struct sctp_transport *t)
+ {
+- return __sctp_mtu_payload(sctp_sk(t->asoc->base.sk), t, 0, 0);
++ return __sctp_mtu_payload(sctp_sk(t->asoc->base.sk), t, 0, 0) -
++ sizeof(struct sctphdr);
+ }
+
+ static inline void sctp_transport_pl_reset(struct sctp_transport *t)
+@@ -653,12 +654,10 @@ static inline void sctp_transport_pl_update(struct sctp_transport *t)
+ if (t->pl.state == SCTP_PL_DISABLED)
+ return;
+
+- if (del_timer(&t->probe_timer))
+- sctp_transport_put(t);
+-
+ t->pl.state = SCTP_PL_BASE;
+ t->pl.pmtu = SCTP_BASE_PLPMTU;
+ t->pl.probe_size = SCTP_BASE_PLPMTU;
++ sctp_transport_reset_probe_timer(t);
+ }
+
+ static inline bool sctp_transport_pl_enabled(struct sctp_transport *t)
+diff --git a/include/net/sock.h b/include/net/sock.h
+index 463f390d90b3e..7ac5075f9c18a 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -1237,7 +1237,7 @@ struct proto {
+ unsigned int useroffset; /* Usercopy region offset */
+ unsigned int usersize; /* Usercopy region size */
+
+- struct percpu_counter *orphan_count;
++ unsigned int __percpu *orphan_count;
+
+ struct request_sock_ops *rsk_prot;
+ struct timewait_sock_ops *twsk_prot;
+@@ -2400,19 +2400,22 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp,
+ * @sk: socket
+ *
+ * Use the per task page_frag instead of the per socket one for
+- * optimization when we know that we're in the normal context and owns
++ * optimization when we know that we're in process context and own
+ * everything that's associated with %current.
+ *
+- * gfpflags_allow_blocking() isn't enough here as direct reclaim may nest
+- * inside other socket operations and end up recursing into sk_page_frag()
+- * while it's already in use.
++ * Both direct reclaim and page faults can nest inside other
++ * socket operations and end up recursing into sk_page_frag()
++ * while it's already in use: explicitly avoid task page_frag
++ * usage if the caller is potentially doing any of them.
++ * This assumes that page fault handlers use the GFP_NOFS flags.
+ *
+ * Return: a per task page_frag if context allows that,
+ * otherwise a per socket one.
+ */
+ static inline struct page_frag *sk_page_frag(struct sock *sk)
+ {
+- if (gfpflags_normal_context(sk->sk_allocation))
++ if ((sk->sk_allocation & (__GFP_DIRECT_RECLAIM | __GFP_MEMALLOC | __GFP_FS)) ==
++ (__GFP_DIRECT_RECLAIM | __GFP_FS))
+ return &current->task_frag;
+
+ return &sk->sk_frag;
+diff --git a/include/net/strparser.h b/include/net/strparser.h
+index 1d20b98493a10..732b7097d78e4 100644
+--- a/include/net/strparser.h
++++ b/include/net/strparser.h
+@@ -54,10 +54,28 @@ struct strp_msg {
+ int offset;
+ };
+
++struct _strp_msg {
++ /* Internal cb structure. struct strp_msg must be first for passing
++ * to upper layer.
++ */
++ struct strp_msg strp;
++ int accum_len;
++};
++
++struct sk_skb_cb {
++#define SK_SKB_CB_PRIV_LEN 20
++ unsigned char data[SK_SKB_CB_PRIV_LEN];
++ struct _strp_msg strp;
++ /* temp_reg is a temporary register used for bpf_convert_data_end_access
++ * when dst_reg == src_reg.
++ */
++ u64 temp_reg;
++};
++
+ static inline struct strp_msg *strp_msg(struct sk_buff *skb)
+ {
+ return (struct strp_msg *)((void *)skb->cb +
+- offsetof(struct qdisc_skb_cb, data));
++ offsetof(struct sk_skb_cb, strp));
+ }
+
+ /* Structure for an attached lower socket */
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 60c384569e9cd..31d384c3778a1 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -48,7 +48,9 @@
+
+ extern struct inet_hashinfo tcp_hashinfo;
+
+-extern struct percpu_counter tcp_orphan_count;
++DECLARE_PER_CPU(unsigned int, tcp_orphan_count);
++int tcp_orphan_count_sum(void);
++
+ void tcp_time_wait(struct sock *sk, int state, int timeo);
+
+ #define MAX_TCP_HEADER L1_CACHE_ALIGN(128 + MAX_HEADER)
+@@ -290,19 +292,6 @@ static inline bool tcp_out_of_memory(struct sock *sk)
+
+ void sk_forced_mem_schedule(struct sock *sk, int size);
+
+-static inline bool tcp_too_many_orphans(struct sock *sk, int shift)
+-{
+- struct percpu_counter *ocp = sk->sk_prot->orphan_count;
+- int orphans = percpu_counter_read_positive(ocp);
+-
+- if (orphans << shift > sysctl_tcp_max_orphans) {
+- orphans = percpu_counter_sum_positive(ocp);
+- if (orphans << shift > sysctl_tcp_max_orphans)
+- return true;
+- }
+- return false;
+-}
+-
+ bool tcp_check_oom(struct sock *sk, int shift);
+
+
+diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
+index 4b50d9a3018a6..4ba642fc8a19a 100644
+--- a/include/rdma/ib_verbs.h
++++ b/include/rdma/ib_verbs.h
+@@ -4097,8 +4097,13 @@ static inline int ib_dma_map_sgtable_attrs(struct ib_device *dev,
+ enum dma_data_direction direction,
+ unsigned long dma_attrs)
+ {
++ int nents;
++
+ if (ib_uses_virt_dma(dev)) {
+- ib_dma_virt_map_sg(dev, sgt->sgl, sgt->orig_nents);
++ nents = ib_dma_virt_map_sg(dev, sgt->sgl, sgt->orig_nents);
++ if (!nents)
++ return -EIO;
++ sgt->nents = nents;
+ return 0;
+ }
+ return dma_map_sgtable(dev->dma_device, sgt, direction, dma_attrs);
+diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h
+index 2758d9df71ee9..c2a79aeee113c 100644
+--- a/include/rdma/rdma_netlink.h
++++ b/include/rdma/rdma_netlink.h
+@@ -30,7 +30,7 @@ enum rdma_nl_flags {
+ * constant as well and the compiler checks they are the same.
+ */
+ #define MODULE_ALIAS_RDMA_NETLINK(_index, _val) \
+- static inline void __chk_##_index(void) \
++ static inline void __maybe_unused __chk_##_index(void) \
+ { \
+ BUILD_BUG_ON(_index != _val); \
+ } \
+diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
+index eaf04c9a1dfcb..59afe8787cf7c 100644
+--- a/include/scsi/scsi_cmnd.h
++++ b/include/scsi/scsi_cmnd.h
+@@ -68,7 +68,7 @@ struct scsi_pointer {
+ struct scsi_cmnd {
+ struct scsi_request req;
+ struct scsi_device *device;
+- struct list_head eh_entry; /* entry for the host eh_cmd_q */
++ struct list_head eh_entry; /* entry for the host eh_abort_list/eh_cmd_q */
+ struct delayed_work abort_work;
+
+ struct rcu_head rcu;
+diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
+index 75363707b73f9..1a02e58eb4e44 100644
+--- a/include/scsi/scsi_host.h
++++ b/include/scsi/scsi_host.h
+@@ -556,6 +556,7 @@ struct Scsi_Host {
+
+ struct mutex scan_mutex;/* serialize scanning activity */
+
++ struct list_head eh_abort_list;
+ struct list_head eh_cmd_q;
+ struct task_struct * ehandler; /* Error recovery thread. */
+ struct completion * eh_action; /* Wait for specific actions on the
+diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
+index 375581634143c..d4e31ea16aba3 100644
+--- a/include/sound/hdaudio_ext.h
++++ b/include/sound/hdaudio_ext.h
+@@ -88,6 +88,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream,
+ int type);
+ void snd_hdac_ext_stream_release(struct hdac_ext_stream *azx_dev, int type);
++void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
++ struct hdac_ext_stream *azx_dev, bool decouple);
+ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
+ struct hdac_ext_stream *azx_dev, bool decouple);
+ void snd_hdac_ext_stop_streams(struct hdac_bus *bus);
+diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
+index 4afd667e124c2..3e8a85e1e8094 100644
+--- a/include/sound/soc-topology.h
++++ b/include/sound/soc-topology.h
+@@ -188,8 +188,7 @@ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
+
+ #else
+
+-static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp,
+- u32 index)
++static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
+ {
+ return 0;
+ }
+diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
+index fb11c7693b257..2121a323fd6c3 100644
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -812,8 +812,9 @@ struct se_device {
+ atomic_long_t read_bytes;
+ atomic_long_t write_bytes;
+ /* Active commands on this virtual SE device */
+- atomic_t simple_cmds;
+- atomic_t dev_ordered_sync;
++ atomic_t non_ordered;
++ bool ordered_sync_in_progress;
++ atomic_t delayed_cmd_count;
+ atomic_t dev_qf_count;
+ u32 export_count;
+ spinlock_t delayed_cmd_lock;
+@@ -834,6 +835,7 @@ struct se_device {
+ struct list_head dev_sep_list;
+ struct list_head dev_tmr_list;
+ struct work_struct qf_work_queue;
++ struct work_struct delayed_cmd_work;
+ struct list_head delayed_cmd_list;
+ struct list_head qf_cmd_list;
+ /* Pointer to associated SE HBA */
+diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
+index 4e881d91c8744..4cb055af1ec0b 100644
+--- a/include/trace/events/f2fs.h
++++ b/include/trace/events/f2fs.h
+@@ -807,20 +807,20 @@ TRACE_EVENT(f2fs_lookup_start,
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+- __field(const char *, name)
++ __string(name, dentry->d_name.name)
+ __field(unsigned int, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dir->i_sb->s_dev;
+ __entry->ino = dir->i_ino;
+- __entry->name = dentry->d_name.name;
++ __assign_str(name, dentry->d_name.name);
+ __entry->flags = flags;
+ ),
+
+ TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u",
+ show_dev_ino(__entry),
+- __entry->name,
++ __get_str(name),
+ __entry->flags)
+ );
+
+@@ -834,7 +834,7 @@ TRACE_EVENT(f2fs_lookup_end,
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+- __field(const char *, name)
++ __string(name, dentry->d_name.name)
+ __field(nid_t, cino)
+ __field(int, err)
+ ),
+@@ -842,14 +842,14 @@ TRACE_EVENT(f2fs_lookup_end,
+ TP_fast_assign(
+ __entry->dev = dir->i_sb->s_dev;
+ __entry->ino = dir->i_ino;
+- __entry->name = dentry->d_name.name;
++ __assign_str(name, dentry->d_name.name);
+ __entry->cino = ino;
+ __entry->err = err;
+ ),
+
+ TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d",
+ show_dev_ino(__entry),
+- __entry->name,
++ __get_str(name),
+ __entry->cino,
+ __entry->err)
+ );
+diff --git a/include/uapi/asm-generic/poll.h b/include/uapi/asm-generic/poll.h
+index 41b509f410bf9..f9c520ce4bf4e 100644
+--- a/include/uapi/asm-generic/poll.h
++++ b/include/uapi/asm-generic/poll.h
+@@ -29,7 +29,7 @@
+ #define POLLRDHUP 0x2000
+ #endif
+
+-#define POLLFREE (__force __poll_t)0x4000 /* currently only for epoll */
++#define POLLFREE (__force __poll_t)0x4000
+
+ #define POLL_BUSY_LOOP (__force __poll_t)0x8000
+
+diff --git a/include/uapi/asm-generic/signal-defs.h b/include/uapi/asm-generic/signal-defs.h
+index fe929e7b77ca1..7572f2f46ee89 100644
+--- a/include/uapi/asm-generic/signal-defs.h
++++ b/include/uapi/asm-generic/signal-defs.h
+@@ -45,6 +45,7 @@
+ #define SA_UNSUPPORTED 0x00000400
+ #define SA_EXPOSE_TAGBITS 0x00000800
+ /* 0x00010000 used on mips */
++/* 0x00800000 used for internal SA_IMMUTABLE */
+ /* 0x01000000 used on x86 */
+ /* 0x02000000 used on x86 */
+ /*
+diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
+index 5545f1ca9237c..f7204bdfe8db1 100644
+--- a/include/uapi/linux/ethtool_netlink.h
++++ b/include/uapi/linux/ethtool_netlink.h
+@@ -407,7 +407,9 @@ enum {
+ ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
+ ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
+
+- /* add new constants above here */
++ /* add new constants above here
++ * adjust ETHTOOL_PAUSE_STAT_CNT if adding non-stats!
++ */
+ __ETHTOOL_A_PAUSE_STAT_CNT,
+ ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
+ };
+diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h
+index f66038b9551fa..80c40194e2977 100644
+--- a/include/uapi/linux/mptcp.h
++++ b/include/uapi/linux/mptcp.h
+@@ -129,19 +129,21 @@ struct mptcp_info {
+ * MPTCP_EVENT_REMOVED: token, rem_id
+ * An address has been lost by the peer.
+ *
+- * MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6,
+- * daddr4 | daddr6, sport, dport, backup,
+- * if_idx [, error]
++ * MPTCP_EVENT_SUB_ESTABLISHED: token, family, loc_id, rem_id,
++ * saddr4 | saddr6, daddr4 | daddr6, sport,
++ * dport, backup, if_idx [, error]
+ * A new subflow has been established. 'error' should not be set.
+ *
+- * MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6,
+- * sport, dport, backup, if_idx [, error]
++ * MPTCP_EVENT_SUB_CLOSED: token, family, loc_id, rem_id, saddr4 | saddr6,
++ * daddr4 | daddr6, sport, dport, backup, if_idx
++ * [, error]
+ * A subflow has been closed. An error (copy of sk_err) could be set if an
+ * error has been detected for this subflow.
+ *
+- * MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6,
+- * sport, dport, backup, if_idx [, error]
+- * The priority of a subflow has changed. 'error' should not be set.
++ * MPTCP_EVENT_SUB_PRIORITY: token, family, loc_id, rem_id, saddr4 | saddr6,
++ * daddr4 | daddr6, sport, dport, backup, if_idx
++ * [, error]
++ * The priority of a subflow has changed. 'error' should not be set.
+ */
+ enum mptcp_event_type {
+ MPTCP_EVENT_UNSPEC = 0,
+diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
+index e709ae8235e7f..ff6ccbc6efe96 100644
+--- a/include/uapi/linux/pci_regs.h
++++ b/include/uapi/linux/pci_regs.h
+@@ -504,6 +504,12 @@
+ #define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */
+ #define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+ #define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
++#define PCI_EXP_DEVCTL_PAYLOAD_128B 0x0000 /* 128 Bytes */
++#define PCI_EXP_DEVCTL_PAYLOAD_256B 0x0020 /* 256 Bytes */
++#define PCI_EXP_DEVCTL_PAYLOAD_512B 0x0040 /* 512 Bytes */
++#define PCI_EXP_DEVCTL_PAYLOAD_1024B 0x0060 /* 1024 Bytes */
++#define PCI_EXP_DEVCTL_PAYLOAD_2048B 0x0080 /* 2048 Bytes */
++#define PCI_EXP_DEVCTL_PAYLOAD_4096B 0x00a0 /* 4096 Bytes */
+ #define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */
+ #define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
+ #define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */
+diff --git a/include/xen/events.h b/include/xen/events.h
+index c204262d9fc24..344081e71584b 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -17,6 +17,7 @@ struct xenbus_device;
+ unsigned xen_evtchn_nr_channels(void);
+
+ int bind_evtchn_to_irq(evtchn_port_t evtchn);
++int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
+ int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+diff --git a/init/main.c b/init/main.c
+index 3c4054a955458..bcd132d4e7bdd 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -924,7 +924,9 @@ static void __init print_unknown_bootoptions(void)
+ for (p = &envp_init[2]; *p; p++)
+ end += sprintf(end, " %s", *p);
+
+- pr_notice("Unknown command line parameters:%s\n", unknown_options);
++ /* Start at unknown_options[1] to skip the initial space */
++ pr_notice("Unknown kernel command line parameters \"%s\", will be passed to user space.\n",
++ &unknown_options[1]);
+ memblock_free_ptr(unknown_options, len);
+ }
+
+diff --git a/ipc/shm.c b/ipc/shm.c
+index ab749be6d8b71..048eb183b24b9 100644
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -62,9 +62,18 @@ struct shmid_kernel /* private to the kernel */
+ struct pid *shm_lprid;
+ struct ucounts *mlock_ucounts;
+
+- /* The task created the shm object. NULL if the task is dead. */
++ /*
++ * The task created the shm object, for
++ * task_lock(shp->shm_creator)
++ */
+ struct task_struct *shm_creator;
+- struct list_head shm_clist; /* list by creator */
++
++ /*
++ * List by creator. task_lock(->shm_creator) required for read/write.
++ * If list_empty(), then the creator is dead already.
++ */
++ struct list_head shm_clist;
++ struct ipc_namespace *ns;
+ } __randomize_layout;
+
+ /* shm_mode upper byte flags */
+@@ -115,6 +124,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
+ struct shmid_kernel *shp;
+
+ shp = container_of(ipcp, struct shmid_kernel, shm_perm);
++ WARN_ON(ns != shp->ns);
+
+ if (shp->shm_nattch) {
+ shp->shm_perm.mode |= SHM_DEST;
+@@ -225,10 +235,43 @@ static void shm_rcu_free(struct rcu_head *head)
+ kfree(shp);
+ }
+
+-static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
++/*
++ * It has to be called with shp locked.
++ * It must be called before ipc_rmid()
++ */
++static inline void shm_clist_rm(struct shmid_kernel *shp)
+ {
+- list_del(&s->shm_clist);
+- ipc_rmid(&shm_ids(ns), &s->shm_perm);
++ struct task_struct *creator;
++
++ /* ensure that shm_creator does not disappear */
++ rcu_read_lock();
++
++ /*
++ * A concurrent exit_shm may do a list_del_init() as well.
++ * Just do nothing if exit_shm already did the work
++ */
++ if (!list_empty(&shp->shm_clist)) {
++ /*
++ * shp->shm_creator is guaranteed to be valid *only*
++ * if shp->shm_clist is not empty.
++ */
++ creator = shp->shm_creator;
++
++ task_lock(creator);
++ /*
++ * list_del_init() is a nop if the entry was already removed
++ * from the list.
++ */
++ list_del_init(&shp->shm_clist);
++ task_unlock(creator);
++ }
++ rcu_read_unlock();
++}
++
++static inline void shm_rmid(struct shmid_kernel *s)
++{
++ shm_clist_rm(s);
++ ipc_rmid(&shm_ids(s->ns), &s->shm_perm);
+ }
+
+
+@@ -283,7 +326,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
+ shm_file = shp->shm_file;
+ shp->shm_file = NULL;
+ ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
+- shm_rmid(ns, shp);
++ shm_rmid(shp);
+ shm_unlock(shp);
+ if (!is_file_hugepages(shm_file))
+ shmem_lock(shm_file, 0, shp->mlock_ucounts);
+@@ -306,10 +349,10 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
+ *
+ * 2) sysctl kernel.shm_rmid_forced is set to 1.
+ */
+-static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
++static bool shm_may_destroy(struct shmid_kernel *shp)
+ {
+ return (shp->shm_nattch == 0) &&
+- (ns->shm_rmid_forced ||
++ (shp->ns->shm_rmid_forced ||
+ (shp->shm_perm.mode & SHM_DEST));
+ }
+
+@@ -340,7 +383,7 @@ static void shm_close(struct vm_area_struct *vma)
+ ipc_update_pid(&shp->shm_lprid, task_tgid(current));
+ shp->shm_dtim = ktime_get_real_seconds();
+ shp->shm_nattch--;
+- if (shm_may_destroy(ns, shp))
++ if (shm_may_destroy(shp))
+ shm_destroy(ns, shp);
+ else
+ shm_unlock(shp);
+@@ -361,10 +404,10 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
+ *
+ * As shp->* are changed under rwsem, it's safe to skip shp locking.
+ */
+- if (shp->shm_creator != NULL)
++ if (!list_empty(&shp->shm_clist))
+ return 0;
+
+- if (shm_may_destroy(ns, shp)) {
++ if (shm_may_destroy(shp)) {
+ shm_lock_by_ptr(shp);
+ shm_destroy(ns, shp);
+ }
+@@ -382,48 +425,97 @@ void shm_destroy_orphaned(struct ipc_namespace *ns)
+ /* Locking assumes this will only be called with task == current */
+ void exit_shm(struct task_struct *task)
+ {
+- struct ipc_namespace *ns = task->nsproxy->ipc_ns;
+- struct shmid_kernel *shp, *n;
++ for (;;) {
++ struct shmid_kernel *shp;
++ struct ipc_namespace *ns;
+
+- if (list_empty(&task->sysvshm.shm_clist))
+- return;
++ task_lock(task);
++
++ if (list_empty(&task->sysvshm.shm_clist)) {
++ task_unlock(task);
++ break;
++ }
++
++ shp = list_first_entry(&task->sysvshm.shm_clist, struct shmid_kernel,
++ shm_clist);
+
+- /*
+- * If kernel.shm_rmid_forced is not set then only keep track of
+- * which shmids are orphaned, so that a later set of the sysctl
+- * can clean them up.
+- */
+- if (!ns->shm_rmid_forced) {
+- down_read(&shm_ids(ns).rwsem);
+- list_for_each_entry(shp, &task->sysvshm.shm_clist, shm_clist)
+- shp->shm_creator = NULL;
+ /*
+- * Only under read lock but we are only called on current
+- * so no entry on the list will be shared.
++ * 1) Get pointer to the ipc namespace. It is worth to say
++ * that this pointer is guaranteed to be valid because
++ * shp lifetime is always shorter than namespace lifetime
++ * in which shp lives.
++ * We taken task_lock it means that shp won't be freed.
+ */
+- list_del(&task->sysvshm.shm_clist);
+- up_read(&shm_ids(ns).rwsem);
+- return;
+- }
++ ns = shp->ns;
+
+- /*
+- * Destroy all already created segments, that were not yet mapped,
+- * and mark any mapped as orphan to cover the sysctl toggling.
+- * Destroy is skipped if shm_may_destroy() returns false.
+- */
+- down_write(&shm_ids(ns).rwsem);
+- list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) {
+- shp->shm_creator = NULL;
++ /*
++ * 2) If kernel.shm_rmid_forced is not set then only keep track of
++ * which shmids are orphaned, so that a later set of the sysctl
++ * can clean them up.
++ */
++ if (!ns->shm_rmid_forced)
++ goto unlink_continue;
+
+- if (shm_may_destroy(ns, shp)) {
+- shm_lock_by_ptr(shp);
+- shm_destroy(ns, shp);
++ /*
++ * 3) get a reference to the namespace.
++ * The refcount could be already 0. If it is 0, then
++ * the shm objects will be free by free_ipc_work().
++ */
++ ns = get_ipc_ns_not_zero(ns);
++ if (!ns) {
++unlink_continue:
++ list_del_init(&shp->shm_clist);
++ task_unlock(task);
++ continue;
+ }
+- }
+
+- /* Remove the list head from any segments still attached. */
+- list_del(&task->sysvshm.shm_clist);
+- up_write(&shm_ids(ns).rwsem);
++ /*
++ * 4) get a reference to shp.
++ * This cannot fail: shm_clist_rm() is called before
++ * ipc_rmid(), thus the refcount cannot be 0.
++ */
++ WARN_ON(!ipc_rcu_getref(&shp->shm_perm));
++
++ /*
++ * 5) unlink the shm segment from the list of segments
++ * created by current.
++ * This must be done last. After unlinking,
++ * only the refcounts obtained above prevent IPC_RMID
++ * from destroying the segment or the namespace.
++ */
++ list_del_init(&shp->shm_clist);
++
++ task_unlock(task);
++
++ /*
++ * 6) we have all references
++ * Thus lock & if needed destroy shp.
++ */
++ down_write(&shm_ids(ns).rwsem);
++ shm_lock_by_ptr(shp);
++ /*
++ * rcu_read_lock was implicitly taken in shm_lock_by_ptr, it's
++ * safe to call ipc_rcu_putref here
++ */
++ ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
++
++ if (ipc_valid_object(&shp->shm_perm)) {
++ if (shm_may_destroy(shp))
++ shm_destroy(ns, shp);
++ else
++ shm_unlock(shp);
++ } else {
++ /*
++ * Someone else deleted the shp from namespace
++ * idr/kht while we have waited.
++ * Just unlock and continue.
++ */
++ shm_unlock(shp);
++ }
++
++ up_write(&shm_ids(ns).rwsem);
++ put_ipc_ns(ns); /* paired with get_ipc_ns_not_zero */
++ }
+ }
+
+ static vm_fault_t shm_fault(struct vm_fault *vmf)
+@@ -680,7 +772,11 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
+ if (error < 0)
+ goto no_id;
+
++ shp->ns = ns;
++
++ task_lock(current);
+ list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
++ task_unlock(current);
+
+ /*
+ * shmid gets reported as "inode#" in /proc/pid/maps.
+@@ -1573,7 +1669,8 @@ out_nattch:
+ down_write(&shm_ids(ns).rwsem);
+ shp = shm_lock(ns, shmid);
+ shp->shm_nattch--;
+- if (shm_may_destroy(ns, shp))
++
++ if (shm_may_destroy(shp))
+ shm_destroy(ns, shp);
+ else
+ shm_unlock(shp);
+diff --git a/ipc/util.c b/ipc/util.c
+index d48d8cfa1f3fa..fa2d86ef3fb80 100644
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -447,8 +447,8 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
+ static void ipc_kht_remove(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
+ {
+ if (ipcp->key != IPC_PRIVATE)
+- rhashtable_remove_fast(&ids->key_ht, &ipcp->khtnode,
+- ipc_kht_params);
++ WARN_ON_ONCE(rhashtable_remove_fast(&ids->key_ht, &ipcp->khtnode,
++ ipc_kht_params));
+ }
+
+ /**
+@@ -498,7 +498,7 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
+ {
+ int idx = ipcid_to_idx(ipcp->id);
+
+- idr_remove(&ids->ipcs_idr, idx);
++ WARN_ON_ONCE(idr_remove(&ids->ipcs_idr, idx) != ipcp);
+ ipc_kht_remove(ids, ipcp);
+ ids->in_use--;
+ ipcp->deleted = true;
+diff --git a/kernel/audit.c b/kernel/audit.c
+index 121d37e700a62..4cebadb5f30db 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -718,7 +718,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
+ {
+ int rc = 0;
+ struct sk_buff *skb;
+- static unsigned int failed = 0;
++ unsigned int failed = 0;
+
+ /* NOTE: kauditd_thread takes care of all our locking, we just use
+ * the netlink info passed to us (e.g. sk and portid) */
+@@ -735,32 +735,30 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
+ continue;
+ }
+
++retry:
+ /* grab an extra skb reference in case of error */
+ skb_get(skb);
+ rc = netlink_unicast(sk, skb, portid, 0);
+ if (rc < 0) {
+- /* fatal failure for our queue flush attempt? */
++ /* send failed - try a few times unless fatal error */
+ if (++failed >= retry_limit ||
+ rc == -ECONNREFUSED || rc == -EPERM) {
+- /* yes - error processing for the queue */
+ sk = NULL;
+ if (err_hook)
+ (*err_hook)(skb);
+- if (!skb_hook)
+- goto out;
+- /* keep processing with the skb_hook */
++ if (rc == -EAGAIN)
++ rc = 0;
++ /* continue to drain the queue */
+ continue;
+ } else
+- /* no - requeue to preserve ordering */
+- skb_queue_head(queue, skb);
++ goto retry;
+ } else {
+- /* it worked - drop the extra reference and continue */
++ /* skb sent - drop the extra reference and continue */
+ consume_skb(skb);
+ failed = 0;
+ }
+ }
+
+-out:
+ return (rc >= 0 ? 0 : rc);
+ }
+
+@@ -1609,7 +1607,8 @@ static int __net_init audit_net_init(struct net *net)
+ audit_panic("cannot initialize netlink socket in namespace");
+ return -ENOMEM;
+ }
+- aunet->sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
++ /* limit the timeout in case auditd is blocked/stopped */
++ aunet->sk->sk_sndtimeo = HZ / 10;
+
+ return 0;
+ }
+diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
+index 03145d45e3d5b..7dbd68195a2b0 100644
+--- a/kernel/bpf/cgroup.c
++++ b/kernel/bpf/cgroup.c
+@@ -1773,6 +1773,8 @@ sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
+ return &bpf_sysctl_get_new_value_proto;
+ case BPF_FUNC_sysctl_set_new_value:
+ return &bpf_sysctl_set_new_value_proto;
++ case BPF_FUNC_ktime_get_coarse_ns:
++ return &bpf_ktime_get_coarse_ns_proto;
+ default:
+ return cgroup_base_func_proto(func_id, prog);
+ }
+diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
+index 9aabf84afd4b2..6f600cc95ccda 100644
+--- a/kernel/bpf/helpers.c
++++ b/kernel/bpf/helpers.c
+@@ -1367,8 +1367,6 @@ bpf_base_func_proto(enum bpf_func_id func_id)
+ return &bpf_ktime_get_ns_proto;
+ case BPF_FUNC_ktime_get_boot_ns:
+ return &bpf_ktime_get_boot_ns_proto;
+- case BPF_FUNC_ktime_get_coarse_ns:
+- return &bpf_ktime_get_coarse_ns_proto;
+ case BPF_FUNC_ringbuf_output:
+ return &bpf_ringbuf_output_proto;
+ case BPF_FUNC_ringbuf_reserve:
+diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
+index 1cad6979a0d0f..ecd51a8a8680c 100644
+--- a/kernel/bpf/syscall.c
++++ b/kernel/bpf/syscall.c
+@@ -132,6 +132,21 @@ static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
+ return map;
+ }
+
++static void bpf_map_write_active_inc(struct bpf_map *map)
++{
++ atomic64_inc(&map->writecnt);
++}
++
++static void bpf_map_write_active_dec(struct bpf_map *map)
++{
++ atomic64_dec(&map->writecnt);
++}
++
++bool bpf_map_write_active(const struct bpf_map *map)
++{
++ return atomic64_read(&map->writecnt) != 0;
++}
++
+ static u32 bpf_map_value_size(const struct bpf_map *map)
+ {
+ if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+@@ -596,11 +611,8 @@ static void bpf_map_mmap_open(struct vm_area_struct *vma)
+ {
+ struct bpf_map *map = vma->vm_file->private_data;
+
+- if (vma->vm_flags & VM_MAYWRITE) {
+- mutex_lock(&map->freeze_mutex);
+- map->writecnt++;
+- mutex_unlock(&map->freeze_mutex);
+- }
++ if (vma->vm_flags & VM_MAYWRITE)
++ bpf_map_write_active_inc(map);
+ }
+
+ /* called for all unmapped memory region (including initial) */
+@@ -608,11 +620,8 @@ static void bpf_map_mmap_close(struct vm_area_struct *vma)
+ {
+ struct bpf_map *map = vma->vm_file->private_data;
+
+- if (vma->vm_flags & VM_MAYWRITE) {
+- mutex_lock(&map->freeze_mutex);
+- map->writecnt--;
+- mutex_unlock(&map->freeze_mutex);
+- }
++ if (vma->vm_flags & VM_MAYWRITE)
++ bpf_map_write_active_dec(map);
+ }
+
+ static const struct vm_operations_struct bpf_map_default_vmops = {
+@@ -663,7 +672,7 @@ static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
+ goto out;
+
+ if (vma->vm_flags & VM_MAYWRITE)
+- map->writecnt++;
++ bpf_map_write_active_inc(map);
+ out:
+ mutex_unlock(&map->freeze_mutex);
+ return err;
+@@ -1122,6 +1131,7 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
+ map = __bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
++ bpf_map_write_active_inc(map);
+ if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+ goto err_put;
+@@ -1157,6 +1167,7 @@ free_value:
+ free_key:
+ kvfree(key);
+ err_put:
++ bpf_map_write_active_dec(map);
+ fdput(f);
+ return err;
+ }
+@@ -1179,6 +1190,7 @@ static int map_delete_elem(union bpf_attr *attr)
+ map = __bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
++ bpf_map_write_active_inc(map);
+ if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+ goto err_put;
+@@ -1209,6 +1221,7 @@ static int map_delete_elem(union bpf_attr *attr)
+ out:
+ kvfree(key);
+ err_put:
++ bpf_map_write_active_dec(map);
+ fdput(f);
+ return err;
+ }
+@@ -1516,6 +1529,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr)
+ map = __bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
++ bpf_map_write_active_inc(map);
+ if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
+ !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+@@ -1580,6 +1594,7 @@ free_value:
+ free_key:
+ kvfree(key);
+ err_put:
++ bpf_map_write_active_dec(map);
+ fdput(f);
+ return err;
+ }
+@@ -1607,8 +1622,7 @@ static int map_freeze(const union bpf_attr *attr)
+ }
+
+ mutex_lock(&map->freeze_mutex);
+-
+- if (map->writecnt) {
++ if (bpf_map_write_active(map)) {
+ err = -EBUSY;
+ goto err_put;
+ }
+@@ -4143,6 +4157,9 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
+ union bpf_attr __user *uattr,
+ int cmd)
+ {
++ bool has_read = cmd == BPF_MAP_LOOKUP_BATCH ||
++ cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
++ bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
+ struct bpf_map *map;
+ int err, ufd;
+ struct fd f;
+@@ -4155,16 +4172,13 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
+ map = __bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+-
+- if ((cmd == BPF_MAP_LOOKUP_BATCH ||
+- cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) &&
+- !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
++ if (has_write)
++ bpf_map_write_active_inc(map);
++ if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
+ err = -EPERM;
+ goto err_put;
+ }
+-
+- if (cmd != BPF_MAP_LOOKUP_BATCH &&
+- !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
++ if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
+ err = -EPERM;
+ goto err_put;
+ }
+@@ -4177,8 +4191,9 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
+ BPF_DO_BATCH(map->ops->map_update_batch);
+ else
+ BPF_DO_BATCH(map->ops->map_delete_batch);
+-
+ err_put:
++ if (has_write)
++ bpf_map_write_active_dec(map);
+ fdput(f);
+ return err;
+ }
+diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
+index fe1e857324e66..d3a307a8c42b9 100644
+--- a/kernel/bpf/trampoline.c
++++ b/kernel/bpf/trampoline.c
+@@ -585,11 +585,13 @@ static void notrace update_prog_stats(struct bpf_prog *prog,
+ * Hence check that 'start' is valid.
+ */
+ start > NO_START_TIME) {
++ unsigned long flags;
++
+ stats = this_cpu_ptr(prog->stats);
+- u64_stats_update_begin(&stats->syncp);
++ flags = u64_stats_update_begin_irqsave(&stats->syncp);
+ stats->cnt++;
+ stats->nsecs += sched_clock() - start;
+- u64_stats_update_end(&stats->syncp);
++ u64_stats_update_end_irqrestore(&stats->syncp, flags);
+ }
+ }
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index e76b559179054..93c3a332e8536 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1143,7 +1143,8 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg)
+ /* transfer reg's id which is unique for every map_lookup_elem
+ * as UID of the inner map.
+ */
+- reg->map_uid = reg->id;
++ if (map_value_has_timer(map->inner_map_meta))
++ reg->map_uid = reg->id;
+ } else if (map->map_type == BPF_MAP_TYPE_XSKMAP) {
+ reg->type = PTR_TO_XDP_SOCK;
+ } else if (map->map_type == BPF_MAP_TYPE_SOCKMAP ||
+@@ -1357,22 +1358,28 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
+ reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
+ }
+
++static bool __reg32_bound_s64(s32 a)
++{
++ return a >= 0 && a <= S32_MAX;
++}
++
+ static void __reg_assign_32_into_64(struct bpf_reg_state *reg)
+ {
+ reg->umin_value = reg->u32_min_value;
+ reg->umax_value = reg->u32_max_value;
+- /* Attempt to pull 32-bit signed bounds into 64-bit bounds
+- * but must be positive otherwise set to worse case bounds
+- * and refine later from tnum.
++
++ /* Attempt to pull 32-bit signed bounds into 64-bit bounds but must
++ * be positive otherwise set to worse case bounds and refine later
++ * from tnum.
+ */
+- if (reg->s32_min_value >= 0 && reg->s32_max_value >= 0)
+- reg->smax_value = reg->s32_max_value;
+- else
+- reg->smax_value = U32_MAX;
+- if (reg->s32_min_value >= 0)
++ if (__reg32_bound_s64(reg->s32_min_value) &&
++ __reg32_bound_s64(reg->s32_max_value)) {
+ reg->smin_value = reg->s32_min_value;
+- else
++ reg->smax_value = reg->s32_max_value;
++ } else {
+ reg->smin_value = 0;
++ reg->smax_value = U32_MAX;
++ }
+ }
+
+ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
+@@ -1406,12 +1413,12 @@ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
+
+ static bool __reg64_bound_s32(s64 a)
+ {
+- return a > S32_MIN && a < S32_MAX;
++ return a >= S32_MIN && a <= S32_MAX;
+ }
+
+ static bool __reg64_bound_u32(u64 a)
+ {
+- return a > U32_MIN && a < U32_MAX;
++ return a >= U32_MIN && a <= U32_MAX;
+ }
+
+ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
+@@ -3884,7 +3891,22 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
+
+ static bool bpf_map_is_rdonly(const struct bpf_map *map)
+ {
+- return (map->map_flags & BPF_F_RDONLY_PROG) && map->frozen;
++ /* A map is considered read-only if the following condition are true:
++ *
++ * 1) BPF program side cannot change any of the map content. The
++ * BPF_F_RDONLY_PROG flag is throughout the lifetime of a map
++ * and was set at map creation time.
++ * 2) The map value(s) have been initialized from user space by a
++ * loader and then "frozen", such that no new map update/delete
++ * operations from syscall side are possible for the rest of
++ * the map's lifetime from that point onwards.
++ * 3) Any parallel/pending map update/delete operations from syscall
++ * side have been completed. Only after that point, it's safe to
++ * assume that map value(s) are immutable.
++ */
++ return (map->map_flags & BPF_F_RDONLY_PROG) &&
++ READ_ONCE(map->frozen) &&
++ !bpf_map_write_active(map);
+ }
+
+ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
+@@ -4364,9 +4386,16 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
+
+ if (insn->imm == BPF_CMPXCHG) {
+ /* Check comparison of R0 with memory location */
+- err = check_reg_arg(env, BPF_REG_0, SRC_OP);
++ const u32 aux_reg = BPF_REG_0;
++
++ err = check_reg_arg(env, aux_reg, SRC_OP);
+ if (err)
+ return err;
++
++ if (is_pointer_value(env, aux_reg)) {
++ verbose(env, "R%d leaks addr into mem\n", aux_reg);
++ return -EACCES;
++ }
+ }
+
+ if (is_pointer_value(env, insn->src_reg)) {
+@@ -4401,13 +4430,19 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
+ load_reg = -1;
+ }
+
+- /* check whether we can read the memory */
++ /* Check whether we can read the memory, with second call for fetch
++ * case to simulate the register fill.
++ */
+ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+- BPF_SIZE(insn->code), BPF_READ, load_reg, true);
++ BPF_SIZE(insn->code), BPF_READ, -1, true);
++ if (!err && load_reg >= 0)
++ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
++ BPF_SIZE(insn->code), BPF_READ, load_reg,
++ true);
+ if (err)
+ return err;
+
+- /* check whether we can write into the same memory */
++ /* Check whether we can write into the same memory. */
+ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+ BPF_SIZE(insn->code), BPF_WRITE, -1, true);
+ if (err)
+@@ -8098,6 +8133,10 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ insn->dst_reg);
+ }
+ zext_32_to_64(dst_reg);
++
++ __update_reg_bounds(dst_reg);
++ __reg_deduce_bounds(dst_reg);
++ __reg_bound_offset(dst_reg);
+ }
+ } else {
+ /* case: R = imm
+@@ -8212,7 +8251,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,
+
+ new_range = dst_reg->off;
+ if (range_right_open)
+- new_range--;
++ new_range++;
+
+ /* Examples for register markings:
+ *
+@@ -11435,6 +11474,13 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
+ }
+ }
+
++ if (map_value_has_timer(map)) {
++ if (is_tracing_prog_type(prog_type)) {
++ verbose(env, "tracing progs cannot use bpf_timer yet\n");
++ return -EINVAL;
++ }
++ }
++
+ if ((bpf_prog_is_dev_bound(prog->aux) || bpf_map_is_dev_bound(map)) &&
+ !bpf_offload_prog_map_match(prog, map)) {
+ verbose(env, "offload device mismatch between prog and map\n");
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index ea08f01d0111a..d6ea872b23aad 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -1740,6 +1740,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+ struct cgroup *dcgrp = &dst_root->cgrp;
+ struct cgroup_subsys *ss;
+ int ssid, i, ret;
++ u16 dfl_disable_ss_mask = 0;
+
+ lockdep_assert_held(&cgroup_mutex);
+
+@@ -1756,8 +1757,28 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+ /* can't move between two non-dummy roots either */
+ if (ss->root != &cgrp_dfl_root && dst_root != &cgrp_dfl_root)
+ return -EBUSY;
++
++ /*
++ * Collect ssid's that need to be disabled from default
++ * hierarchy.
++ */
++ if (ss->root == &cgrp_dfl_root)
++ dfl_disable_ss_mask |= 1 << ssid;
++
+ } while_each_subsys_mask();
+
++ if (dfl_disable_ss_mask) {
++ struct cgroup *scgrp = &cgrp_dfl_root.cgrp;
++
++ /*
++ * Controllers from default hierarchy that need to be rebound
++ * are all disabled together in one go.
++ */
++ cgrp_dfl_root.subsys_mask &= ~dfl_disable_ss_mask;
++ WARN_ON(cgroup_apply_control(scgrp));
++ cgroup_finalize_control(scgrp, 0);
++ }
++
+ do_each_subsys_mask(ss, ssid, ss_mask) {
+ struct cgroup_root *src_root = ss->root;
+ struct cgroup *scgrp = &src_root->cgrp;
+@@ -1766,10 +1787,12 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+
+ WARN_ON(!css || cgroup_css(dcgrp, ss));
+
+- /* disable from the source */
+- src_root->subsys_mask &= ~(1 << ssid);
+- WARN_ON(cgroup_apply_control(scgrp));
+- cgroup_finalize_control(scgrp, 0);
++ if (src_root != &cgrp_dfl_root) {
++ /* disable from the source */
++ src_root->subsys_mask &= ~(1 << ssid);
++ WARN_ON(cgroup_apply_control(scgrp));
++ cgroup_finalize_control(scgrp, 0);
++ }
+
+ /* rebind */
+ RCU_INIT_POINTER(scgrp->subsys[ssid], NULL);
+diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c
+index b264ab5652ba9..1486768f23185 100644
+--- a/kernel/cgroup/rstat.c
++++ b/kernel/cgroup/rstat.c
+@@ -433,8 +433,6 @@ static void root_cgroup_cputime(struct task_cputime *cputime)
+ cputime->sum_exec_runtime += user;
+ cputime->sum_exec_runtime += sys;
+ cputime->sum_exec_runtime += cpustat[CPUTIME_STEAL];
+- cputime->sum_exec_runtime += cpustat[CPUTIME_GUEST];
+- cputime->sum_exec_runtime += cpustat[CPUTIME_GUEST_NICE];
+ }
+ }
+
+diff --git a/kernel/cpu.c b/kernel/cpu.c
+index 192e43a874076..407a2568f35eb 100644
+--- a/kernel/cpu.c
++++ b/kernel/cpu.c
+@@ -31,6 +31,7 @@
+ #include <linux/smpboot.h>
+ #include <linux/relay.h>
+ #include <linux/slab.h>
++#include <linux/scs.h>
+ #include <linux/percpu-rwsem.h>
+ #include <linux/cpuset.h>
+
+@@ -587,6 +588,12 @@ static int bringup_cpu(unsigned int cpu)
+ struct task_struct *idle = idle_thread_get(cpu);
+ int ret;
+
++ /*
++ * Reset stale stack state from the last time this CPU was online.
++ */
++ scs_task_reset(idle);
++ kasan_unpoison_task_stack(idle);
++
+ /*
+ * Some architectures have to walk the irq descriptors to
+ * setup the vector space for the cpu which comes online.
+diff --git a/kernel/debug/kdb/kdb_bt.c b/kernel/debug/kdb/kdb_bt.c
+index 1f9f0e47aedaa..10b454554ab03 100644
+--- a/kernel/debug/kdb/kdb_bt.c
++++ b/kernel/debug/kdb/kdb_bt.c
+@@ -46,7 +46,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
+ * btp <pid> Kernel stack for <pid>
+ * btt <address-expression> Kernel stack for task structure at
+ * <address-expression>
+- * bta [DRSTCZEUIMA] All useful processes, optionally
++ * bta [state_chars>|A] All useful processes, optionally
+ * filtered by state
+ * btc [<cpu>] The current process on one cpu,
+ * default is all cpus
+@@ -74,7 +74,7 @@ static void kdb_show_stack(struct task_struct *p, void *addr)
+ */
+
+ static int
+-kdb_bt1(struct task_struct *p, unsigned long mask, bool btaprompt)
++kdb_bt1(struct task_struct *p, const char *mask, bool btaprompt)
+ {
+ char ch;
+
+@@ -120,7 +120,7 @@ kdb_bt_cpu(unsigned long cpu)
+ return;
+ }
+
+- kdb_bt1(kdb_tsk, ~0UL, false);
++ kdb_bt1(kdb_tsk, "A", false);
+ }
+
+ int
+@@ -138,8 +138,8 @@ kdb_bt(int argc, const char **argv)
+ if (strcmp(argv[0], "bta") == 0) {
+ struct task_struct *g, *p;
+ unsigned long cpu;
+- unsigned long mask = kdb_task_state_string(argc ? argv[1] :
+- NULL);
++ const char *mask = argc ? argv[1] : kdbgetenv("PS");
++
+ if (argc == 0)
+ kdb_ps_suppressed();
+ /* Run the active tasks first */
+@@ -167,7 +167,7 @@ kdb_bt(int argc, const char **argv)
+ return diag;
+ p = find_task_by_pid_ns(pid, &init_pid_ns);
+ if (p)
+- return kdb_bt1(p, ~0UL, false);
++ return kdb_bt1(p, "A", false);
+ kdb_printf("No process with pid == %ld found\n", pid);
+ return 0;
+ } else if (strcmp(argv[0], "btt") == 0) {
+@@ -176,7 +176,7 @@ kdb_bt(int argc, const char **argv)
+ diag = kdbgetularg((char *)argv[1], &addr);
+ if (diag)
+ return diag;
+- return kdb_bt1((struct task_struct *)addr, ~0UL, false);
++ return kdb_bt1((struct task_struct *)addr, "A", false);
+ } else if (strcmp(argv[0], "btc") == 0) {
+ unsigned long cpu = ~0;
+ if (argc > 1)
+@@ -212,7 +212,7 @@ kdb_bt(int argc, const char **argv)
+ kdb_show_stack(kdb_current_task, (void *)addr);
+ return 0;
+ } else {
+- return kdb_bt1(kdb_current_task, ~0UL, false);
++ return kdb_bt1(kdb_current_task, "A", false);
+ }
+ }
+
+diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
+index fa6deda894a17..0852a537dad4c 100644
+--- a/kernel/debug/kdb/kdb_main.c
++++ b/kernel/debug/kdb/kdb_main.c
+@@ -2203,8 +2203,8 @@ static void kdb_cpu_status(void)
+ state = 'D'; /* cpu is online but unresponsive */
+ } else {
+ state = ' '; /* cpu is responding to kdb */
+- if (kdb_task_state_char(KDB_TSK(i)) == 'I')
+- state = 'I'; /* idle task */
++ if (kdb_task_state_char(KDB_TSK(i)) == '-')
++ state = '-'; /* idle task */
+ }
+ if (state != prev_state) {
+ if (prev_state != '?') {
+@@ -2271,37 +2271,30 @@ static int kdb_cpu(int argc, const char **argv)
+ void kdb_ps_suppressed(void)
+ {
+ int idle = 0, daemon = 0;
+- unsigned long mask_I = kdb_task_state_string("I"),
+- mask_M = kdb_task_state_string("M");
+ unsigned long cpu;
+ const struct task_struct *p, *g;
+ for_each_online_cpu(cpu) {
+ p = kdb_curr_task(cpu);
+- if (kdb_task_state(p, mask_I))
++ if (kdb_task_state(p, "-"))
+ ++idle;
+ }
+ for_each_process_thread(g, p) {
+- if (kdb_task_state(p, mask_M))
++ if (kdb_task_state(p, "ims"))
+ ++daemon;
+ }
+ if (idle || daemon) {
+ if (idle)
+- kdb_printf("%d idle process%s (state I)%s\n",
++ kdb_printf("%d idle process%s (state -)%s\n",
+ idle, idle == 1 ? "" : "es",
+ daemon ? " and " : "");
+ if (daemon)
+- kdb_printf("%d sleeping system daemon (state M) "
++ kdb_printf("%d sleeping system daemon (state [ims]) "
+ "process%s", daemon,
+ daemon == 1 ? "" : "es");
+ kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
+ }
+ }
+
+-/*
+- * kdb_ps - This function implements the 'ps' command which shows a
+- * list of the active processes.
+- * ps [DRSTCZEUIMA] All processes, optionally filtered by state
+- */
+ void kdb_ps1(const struct task_struct *p)
+ {
+ int cpu;
+@@ -2330,17 +2323,25 @@ void kdb_ps1(const struct task_struct *p)
+ }
+ }
+
++/*
++ * kdb_ps - This function implements the 'ps' command which shows a
++ * list of the active processes.
++ *
++ * ps [<state_chars>] Show processes, optionally selecting only those whose
++ * state character is found in <state_chars>.
++ */
+ static int kdb_ps(int argc, const char **argv)
+ {
+ struct task_struct *g, *p;
+- unsigned long mask, cpu;
++ const char *mask;
++ unsigned long cpu;
+
+ if (argc == 0)
+ kdb_ps_suppressed();
+ kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n",
+ (int)(2*sizeof(void *))+2, "Task Addr",
+ (int)(2*sizeof(void *))+2, "Thread");
+- mask = kdb_task_state_string(argc ? argv[1] : NULL);
++ mask = argc ? argv[1] : kdbgetenv("PS");
+ /* Run the active tasks first */
+ for_each_online_cpu(cpu) {
+ if (KDB_FLAG(CMD_INTERRUPT))
+@@ -2742,8 +2743,8 @@ static kdbtab_t maintab[] = {
+ },
+ { .name = "bta",
+ .func = kdb_bt,
+- .usage = "[D|R|S|T|C|Z|E|U|I|M|A]",
+- .help = "Backtrace all processes matching state flag",
++ .usage = "[<state_chars>|A]",
++ .help = "Backtrace all processes whose state matches",
+ .flags = KDB_ENABLE_INSPECT,
+ },
+ { .name = "btc",
+@@ -2797,7 +2798,7 @@ static kdbtab_t maintab[] = {
+ },
+ { .name = "ps",
+ .func = kdb_ps,
+- .usage = "[<flags>|A]",
++ .usage = "[<state_chars>|A]",
+ .help = "Display active task list",
+ .flags = KDB_ENABLE_INSPECT,
+ },
+diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
+index 629590084a0dc..0d2f9feea0a46 100644
+--- a/kernel/debug/kdb/kdb_private.h
++++ b/kernel/debug/kdb/kdb_private.h
+@@ -190,10 +190,8 @@ extern char kdb_grep_string[];
+ extern int kdb_grep_leading;
+ extern int kdb_grep_trailing;
+ extern char *kdb_cmds[];
+-extern unsigned long kdb_task_state_string(const char *);
+ extern char kdb_task_state_char (const struct task_struct *);
+-extern unsigned long kdb_task_state(const struct task_struct *p,
+- unsigned long mask);
++extern bool kdb_task_state(const struct task_struct *p, const char *mask);
+ extern void kdb_ps_suppressed(void);
+ extern void kdb_ps1(const struct task_struct *p);
+ extern void kdb_send_sig(struct task_struct *p, int sig);
+diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c
+index 7507d9a8dc6ac..df2bface866ef 100644
+--- a/kernel/debug/kdb/kdb_support.c
++++ b/kernel/debug/kdb/kdb_support.c
+@@ -24,6 +24,7 @@
+ #include <linux/uaccess.h>
+ #include <linux/kdb.h>
+ #include <linux/slab.h>
++#include <linux/ctype.h>
+ #include "kdb_private.h"
+
+ /*
+@@ -473,82 +474,7 @@ int kdb_putword(unsigned long addr, unsigned long word, size_t size)
+ return diag;
+ }
+
+-/*
+- * kdb_task_state_string - Convert a string containing any of the
+- * letters DRSTCZEUIMA to a mask for the process state field and
+- * return the value. If no argument is supplied, return the mask
+- * that corresponds to environment variable PS, DRSTCZEU by
+- * default.
+- * Inputs:
+- * s String to convert
+- * Returns:
+- * Mask for process state.
+- * Notes:
+- * The mask folds data from several sources into a single long value, so
+- * be careful not to overlap the bits. TASK_* bits are in the LSB,
+- * special cases like UNRUNNABLE are in the MSB. As of 2.6.10-rc1 there
+- * is no overlap between TASK_* and EXIT_* but that may not always be
+- * true, so EXIT_* bits are shifted left 16 bits before being stored in
+- * the mask.
+- */
+-
+-/* unrunnable is < 0 */
+-#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1))
+-#define RUNNING (1UL << (8*sizeof(unsigned long) - 2))
+-#define IDLE (1UL << (8*sizeof(unsigned long) - 3))
+-#define DAEMON (1UL << (8*sizeof(unsigned long) - 4))
+
+-unsigned long kdb_task_state_string(const char *s)
+-{
+- long res = 0;
+- if (!s) {
+- s = kdbgetenv("PS");
+- if (!s)
+- s = "DRSTCZEU"; /* default value for ps */
+- }
+- while (*s) {
+- switch (*s) {
+- case 'D':
+- res |= TASK_UNINTERRUPTIBLE;
+- break;
+- case 'R':
+- res |= RUNNING;
+- break;
+- case 'S':
+- res |= TASK_INTERRUPTIBLE;
+- break;
+- case 'T':
+- res |= TASK_STOPPED;
+- break;
+- case 'C':
+- res |= TASK_TRACED;
+- break;
+- case 'Z':
+- res |= EXIT_ZOMBIE << 16;
+- break;
+- case 'E':
+- res |= EXIT_DEAD << 16;
+- break;
+- case 'U':
+- res |= UNRUNNABLE;
+- break;
+- case 'I':
+- res |= IDLE;
+- break;
+- case 'M':
+- res |= DAEMON;
+- break;
+- case 'A':
+- res = ~0UL;
+- break;
+- default:
+- kdb_func_printf("unknown flag '%c' ignored\n", *s);
+- break;
+- }
+- ++s;
+- }
+- return res;
+-}
+
+ /*
+ * kdb_task_state_char - Return the character that represents the task state.
+@@ -559,7 +485,6 @@ unsigned long kdb_task_state_string(const char *s)
+ */
+ char kdb_task_state_char (const struct task_struct *p)
+ {
+- unsigned int p_state;
+ unsigned long tmp;
+ char state;
+ int cpu;
+@@ -568,25 +493,18 @@ char kdb_task_state_char (const struct task_struct *p)
+ copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long)))
+ return 'E';
+
+- cpu = kdb_process_cpu(p);
+- p_state = READ_ONCE(p->__state);
+- state = (p_state == 0) ? 'R' :
+- (p_state < 0) ? 'U' :
+- (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
+- (p_state & TASK_STOPPED) ? 'T' :
+- (p_state & TASK_TRACED) ? 'C' :
+- (p->exit_state & EXIT_ZOMBIE) ? 'Z' :
+- (p->exit_state & EXIT_DEAD) ? 'E' :
+- (p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
++ state = task_state_to_char((struct task_struct *) p);
++
+ if (is_idle_task(p)) {
+ /* Idle task. Is it really idle, apart from the kdb
+ * interrupt? */
++ cpu = kdb_process_cpu(p);
+ if (!kdb_task_has_cpu(p) || kgdb_info[cpu].irq_depth == 1) {
+ if (cpu != kdb_initial_cpu)
+- state = 'I'; /* idle task */
++ state = '-'; /* idle task */
+ }
+- } else if (!p->mm && state == 'S') {
+- state = 'M'; /* sleeping system daemon */
++ } else if (!p->mm && strchr("IMS", state)) {
++ state = tolower(state); /* sleeping system daemon */
+ }
+ return state;
+ }
+@@ -596,14 +514,28 @@ char kdb_task_state_char (const struct task_struct *p)
+ * given by the mask.
+ * Inputs:
+ * p struct task for the process
+- * mask mask from kdb_task_state_string to select processes
++ * mask set of characters used to select processes; both NULL
++ * and the empty string mean adopt a default filter, which
++ * is to suppress sleeping system daemons and the idle tasks
+ * Returns:
+ * True if the process matches at least one criteria defined by the mask.
+ */
+-unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask)
++bool kdb_task_state(const struct task_struct *p, const char *mask)
+ {
+- char state[] = { kdb_task_state_char(p), '\0' };
+- return (mask & kdb_task_state_string(state)) != 0;
++ char state = kdb_task_state_char(p);
++
++ /* If there is no mask, then we will filter code that runs when the
++ * scheduler is idling and any system daemons that are currently
++ * sleeping.
++ */
++ if (!mask || mask[0] == '\0')
++ return !strchr("-ims", state);
++
++ /* A is a special case that matches all states */
++ if (strchr(mask, 'A'))
++ return true;
++
++ return strchr(mask, state);
+ }
+
+ /* Maintain a small stack of kdb_flags to allow recursion without disturbing
+diff --git a/kernel/entry/syscall_user_dispatch.c b/kernel/entry/syscall_user_dispatch.c
+index c240302f56e23..0b6379adff6bd 100644
+--- a/kernel/entry/syscall_user_dispatch.c
++++ b/kernel/entry/syscall_user_dispatch.c
+@@ -47,14 +47,18 @@ bool syscall_user_dispatch(struct pt_regs *regs)
+ * access_ok() is performed once, at prctl time, when
+ * the selector is loaded by userspace.
+ */
+- if (unlikely(__get_user(state, sd->selector)))
+- do_exit(SIGSEGV);
++ if (unlikely(__get_user(state, sd->selector))) {
++ force_exit_sig(SIGSEGV);
++ return true;
++ }
+
+ if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
+ return false;
+
+- if (state != SYSCALL_DISPATCH_FILTER_BLOCK)
+- do_exit(SIGSYS);
++ if (state != SYSCALL_DISPATCH_FILTER_BLOCK) {
++ force_exit_sig(SIGSYS);
++ return true;
++ }
+ }
+
+ sd->on_dispatch = true;
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index f23ca260307f0..2931faf92a76f 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -7154,7 +7154,6 @@ void perf_output_sample(struct perf_output_handle *handle,
+ static u64 perf_virt_to_phys(u64 virt)
+ {
+ u64 phys_addr = 0;
+- struct page *p = NULL;
+
+ if (!virt)
+ return 0;
+@@ -7173,14 +7172,15 @@ static u64 perf_virt_to_phys(u64 virt)
+ * If failed, leave phys_addr as 0.
+ */
+ if (current->mm != NULL) {
++ struct page *p;
++
+ pagefault_disable();
+- if (get_user_page_fast_only(virt, 0, &p))
++ if (get_user_page_fast_only(virt, 0, &p)) {
+ phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
++ put_page(p);
++ }
+ pagefault_enable();
+ }
+-
+- if (p)
+- put_page(p);
+ }
+
+ return phys_addr;
+@@ -9729,6 +9729,9 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,
+ continue;
+ if (event->attr.config != entry->type)
+ continue;
++ /* Cannot deliver synchronous signal to other task. */
++ if (event->attr.sigtrap)
++ continue;
+ if (perf_tp_event_match(event, &data, regs))
+ perf_swevent_event(event, count, &data, regs);
+ }
+diff --git a/kernel/fork.c b/kernel/fork.c
+index 38681ad44c76b..10885c649ca42 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -2280,6 +2280,7 @@ static __latent_entropy struct task_struct *copy_process(
+ p->pdeath_signal = 0;
+ INIT_LIST_HEAD(&p->thread_group);
+ p->task_works = NULL;
++ clear_posix_cputimers_work(p);
+
+ #ifdef CONFIG_KRETPROBES
+ p->kretprobe_instances.first = NULL;
+@@ -2405,7 +2406,7 @@ static __latent_entropy struct task_struct *copy_process(
+ write_unlock_irq(&tasklist_lock);
+
+ proc_fork_connector(p);
+- sched_post_fork(p);
++ sched_post_fork(p, args);
+ cgroup_post_fork(p, args);
+ perf_event_fork(p);
+
+diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
+index 6a5ecee6e5674..7f350ae59c5fd 100644
+--- a/kernel/irq/msi.c
++++ b/kernel/irq/msi.c
+@@ -529,10 +529,10 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
+
+ /*
+ * Checking the first MSI descriptor is sufficient. MSIX supports
+- * masking and MSI does so when the maskbit is set.
++ * masking and MSI does so when the can_mask attribute is set.
+ */
+ desc = first_msi_entry(dev);
+- return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
++ return desc->msi_attrib.is_msix || desc->msi_attrib.can_mask;
+ }
+
+ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+diff --git a/kernel/kprobes.c b/kernel/kprobes.c
+index 790a573bbe00c..2ef90d15699fb 100644
+--- a/kernel/kprobes.c
++++ b/kernel/kprobes.c
+@@ -2006,6 +2006,9 @@ int register_kretprobe(struct kretprobe *rp)
+ }
+ }
+
++ if (rp->data_size > KRETPROBE_MAX_DATA_SIZE)
++ return -E2BIG;
++
+ rp->kp.pre_handler = pre_handler_kretprobe;
+ rp->kp.post_handler = NULL;
+
+@@ -2809,13 +2812,12 @@ static const struct file_operations fops_kp = {
+ static int __init debugfs_kprobe_init(void)
+ {
+ struct dentry *dir;
+- unsigned int value = 1;
+
+ dir = debugfs_create_dir("kprobes", NULL);
+
+ debugfs_create_file("list", 0400, dir, NULL, &kprobes_fops);
+
+- debugfs_create_file("enabled", 0600, dir, &value, &fops_kp);
++ debugfs_create_file("enabled", 0600, dir, NULL, &fops_kp);
+
+ debugfs_create_file("blacklist", 0400, dir, NULL,
+ &kprobe_blacklist_fops);
+diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
+index bf1c00c881e48..d624231eab2bb 100644
+--- a/kernel/locking/lockdep.c
++++ b/kernel/locking/lockdep.c
+@@ -888,7 +888,7 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
+ if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+ return NULL;
+
+- hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
++ hlist_for_each_entry_rcu_notrace(class, hash_head, hash_entry) {
+ if (class->key == key) {
+ /*
+ * Huh! same key, different name? Did someone trample
+@@ -5366,7 +5366,7 @@ int __lock_is_held(const struct lockdep_map *lock, int read)
+ struct held_lock *hlock = curr->held_locks + i;
+
+ if (match_held_lock(hlock, lock)) {
+- if (read == -1 || hlock->read == read)
++ if (read == -1 || !!hlock->read == read)
+ return LOCK_STATE_HELD;
+
+ return LOCK_STATE_NOT_HELD;
+diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
+index 6bb116c559b4a..ea5a701ab2408 100644
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1373,7 +1373,7 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
+ * - the VCPU on which owner runs is preempted
+ */
+ if (!owner->on_cpu || need_resched() ||
+- rt_mutex_waiter_is_top_waiter(lock, waiter) ||
++ !rt_mutex_waiter_is_top_waiter(lock, waiter) ||
+ vcpu_is_preempted(task_cpu(owner))) {
+ res = false;
+ break;
+diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
+index 000e8d5a28841..e63f740c2cc84 100644
+--- a/kernel/locking/rwsem.c
++++ b/kernel/locking/rwsem.c
+@@ -106,9 +106,9 @@
+ * atomic_long_cmpxchg() will be used to obtain writer lock.
+ *
+ * There are three places where the lock handoff bit may be set or cleared.
+- * 1) rwsem_mark_wake() for readers.
+- * 2) rwsem_try_write_lock() for writers.
+- * 3) Error path of rwsem_down_write_slowpath().
++ * 1) rwsem_mark_wake() for readers -- set, clear
++ * 2) rwsem_try_write_lock() for writers -- set, clear
++ * 3) rwsem_del_waiter() -- clear
+ *
+ * For all the above cases, wait_lock will be held. A writer must also
+ * be the first one in the wait_list to be eligible for setting the handoff
+@@ -335,6 +335,9 @@ struct rwsem_waiter {
+ struct task_struct *task;
+ enum rwsem_waiter_type type;
+ unsigned long timeout;
++
++ /* Writer only, not initialized in reader */
++ bool handoff_set;
+ };
+ #define rwsem_first_waiter(sem) \
+ list_first_entry(&sem->wait_list, struct rwsem_waiter, list)
+@@ -345,12 +348,6 @@ enum rwsem_wake_type {
+ RWSEM_WAKE_READ_OWNED /* Waker thread holds the read lock */
+ };
+
+-enum writer_wait_state {
+- WRITER_NOT_FIRST, /* Writer is not first in wait list */
+- WRITER_FIRST, /* Writer is first in wait list */
+- WRITER_HANDOFF /* Writer is first & handoff needed */
+-};
+-
+ /*
+ * The typical HZ value is either 250 or 1000. So set the minimum waiting
+ * time to at least 4ms or 1 jiffy (if it is higher than 4ms) in the wait
+@@ -366,6 +363,31 @@ enum writer_wait_state {
+ */
+ #define MAX_READERS_WAKEUP 0x100
+
++static inline void
++rwsem_add_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
++{
++ lockdep_assert_held(&sem->wait_lock);
++ list_add_tail(&waiter->list, &sem->wait_list);
++ /* caller will set RWSEM_FLAG_WAITERS */
++}
++
++/*
++ * Remove a waiter from the wait_list and clear flags.
++ *
++ * Both rwsem_mark_wake() and rwsem_try_write_lock() contain a full 'copy' of
++ * this function. Modify with care.
++ */
++static inline void
++rwsem_del_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
++{
++ lockdep_assert_held(&sem->wait_lock);
++ list_del(&waiter->list);
++ if (likely(!list_empty(&sem->wait_list)))
++ return;
++
++ atomic_long_andnot(RWSEM_FLAG_HANDOFF | RWSEM_FLAG_WAITERS, &sem->count);
++}
++
+ /*
+ * handle the lock release when processes blocked on it that can now run
+ * - if we come here from up_xxxx(), then the RWSEM_FLAG_WAITERS bit must
+@@ -377,6 +399,8 @@ enum writer_wait_state {
+ * preferably when the wait_lock is released
+ * - woken process blocks are discarded from the list after having task zeroed
+ * - writers are only marked woken if downgrading is false
++ *
++ * Implies rwsem_del_waiter() for all woken readers.
+ */
+ static void rwsem_mark_wake(struct rw_semaphore *sem,
+ enum rwsem_wake_type wake_type,
+@@ -491,18 +515,25 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
+
+ adjustment = woken * RWSEM_READER_BIAS - adjustment;
+ lockevent_cond_inc(rwsem_wake_reader, woken);
++
++ oldcount = atomic_long_read(&sem->count);
+ if (list_empty(&sem->wait_list)) {
+- /* hit end of list above */
++ /*
++ * Combined with list_move_tail() above, this implies
++ * rwsem_del_waiter().
++ */
+ adjustment -= RWSEM_FLAG_WAITERS;
++ if (oldcount & RWSEM_FLAG_HANDOFF)
++ adjustment -= RWSEM_FLAG_HANDOFF;
++ } else if (woken) {
++ /*
++ * When we've woken a reader, we no longer need to force
++ * writers to give up the lock and we can clear HANDOFF.
++ */
++ if (oldcount & RWSEM_FLAG_HANDOFF)
++ adjustment -= RWSEM_FLAG_HANDOFF;
+ }
+
+- /*
+- * When we've woken a reader, we no longer need to force writers
+- * to give up the lock and we can clear HANDOFF.
+- */
+- if (woken && (atomic_long_read(&sem->count) & RWSEM_FLAG_HANDOFF))
+- adjustment -= RWSEM_FLAG_HANDOFF;
+-
+ if (adjustment)
+ atomic_long_add(adjustment, &sem->count);
+
+@@ -533,12 +564,12 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
+ * race conditions between checking the rwsem wait list and setting the
+ * sem->count accordingly.
+ *
+- * If wstate is WRITER_HANDOFF, it will make sure that either the handoff
+- * bit is set or the lock is acquired with handoff bit cleared.
++ * Implies rwsem_del_waiter() on success.
+ */
+ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
+- enum writer_wait_state wstate)
++ struct rwsem_waiter *waiter)
+ {
++ bool first = rwsem_first_waiter(sem) == waiter;
+ long count, new;
+
+ lockdep_assert_held(&sem->wait_lock);
+@@ -547,13 +578,19 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
+ do {
+ bool has_handoff = !!(count & RWSEM_FLAG_HANDOFF);
+
+- if (has_handoff && wstate == WRITER_NOT_FIRST)
+- return false;
++ if (has_handoff) {
++ if (!first)
++ return false;
++
++ /* First waiter inherits a previously set handoff bit */
++ waiter->handoff_set = true;
++ }
+
+ new = count;
+
+ if (count & RWSEM_LOCK_MASK) {
+- if (has_handoff || (wstate != WRITER_HANDOFF))
++ if (has_handoff || (!rt_task(waiter->task) &&
++ !time_after(jiffies, waiter->timeout)))
+ return false;
+
+ new |= RWSEM_FLAG_HANDOFF;
+@@ -570,13 +607,39 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
+ * We have either acquired the lock with handoff bit cleared or
+ * set the handoff bit.
+ */
+- if (new & RWSEM_FLAG_HANDOFF)
++ if (new & RWSEM_FLAG_HANDOFF) {
++ waiter->handoff_set = true;
++ lockevent_inc(rwsem_wlock_handoff);
+ return false;
++ }
+
++ /*
++ * Have rwsem_try_write_lock() fully imply rwsem_del_waiter() on
++ * success.
++ */
++ list_del(&waiter->list);
+ rwsem_set_owner(sem);
+ return true;
+ }
+
++/*
++ * The rwsem_spin_on_owner() function returns the following 4 values
++ * depending on the lock owner state.
++ * OWNER_NULL : owner is currently NULL
++ * OWNER_WRITER: when owner changes and is a writer
++ * OWNER_READER: when owner changes and the new owner may be a reader.
++ * OWNER_NONSPINNABLE:
++ * when optimistic spinning has to stop because either the
++ * owner stops running, is unknown, or its timeslice has
++ * been used up.
++ */
++enum owner_state {
++ OWNER_NULL = 1 << 0,
++ OWNER_WRITER = 1 << 1,
++ OWNER_READER = 1 << 2,
++ OWNER_NONSPINNABLE = 1 << 3,
++};
++
+ #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
+ /*
+ * Try to acquire write lock before the writer has been put on wait queue.
+@@ -632,23 +695,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
+ return ret;
+ }
+
+-/*
+- * The rwsem_spin_on_owner() function returns the following 4 values
+- * depending on the lock owner state.
+- * OWNER_NULL : owner is currently NULL
+- * OWNER_WRITER: when owner changes and is a writer
+- * OWNER_READER: when owner changes and the new owner may be a reader.
+- * OWNER_NONSPINNABLE:
+- * when optimistic spinning has to stop because either the
+- * owner stops running, is unknown, or its timeslice has
+- * been used up.
+- */
+-enum owner_state {
+- OWNER_NULL = 1 << 0,
+- OWNER_WRITER = 1 << 1,
+- OWNER_READER = 1 << 2,
+- OWNER_NONSPINNABLE = 1 << 3,
+-};
+ #define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER | OWNER_READER)
+
+ static inline enum owner_state
+@@ -878,12 +924,11 @@ static inline bool rwsem_optimistic_spin(struct rw_semaphore *sem)
+
+ static inline void clear_nonspinnable(struct rw_semaphore *sem) { }
+
+-static inline int
++static inline enum owner_state
+ rwsem_spin_on_owner(struct rw_semaphore *sem)
+ {
+- return 0;
++ return OWNER_NONSPINNABLE;
+ }
+-#define OWNER_NULL 1
+ #endif
+
+ /*
+@@ -953,7 +998,7 @@ queue:
+ }
+ adjustment += RWSEM_FLAG_WAITERS;
+ }
+- list_add_tail(&waiter.list, &sem->wait_list);
++ rwsem_add_waiter(sem, &waiter);
+
+ /* we're now waiting on the lock, but no longer actively locking */
+ count = atomic_long_add_return(adjustment, &sem->count);
+@@ -999,11 +1044,7 @@ queue:
+ return sem;
+
+ out_nolock:
+- list_del(&waiter.list);
+- if (list_empty(&sem->wait_list)) {
+- atomic_long_andnot(RWSEM_FLAG_WAITERS|RWSEM_FLAG_HANDOFF,
+- &sem->count);
+- }
++ rwsem_del_waiter(sem, &waiter);
+ raw_spin_unlock_irq(&sem->wait_lock);
+ __set_current_state(TASK_RUNNING);
+ lockevent_inc(rwsem_rlock_fail);
+@@ -1017,9 +1058,7 @@ static struct rw_semaphore *
+ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
+ {
+ long count;
+- enum writer_wait_state wstate;
+ struct rwsem_waiter waiter;
+- struct rw_semaphore *ret = sem;
+ DEFINE_WAKE_Q(wake_q);
+
+ /* do optimistic spinning and steal lock if possible */
+@@ -1035,16 +1074,13 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
+ waiter.task = current;
+ waiter.type = RWSEM_WAITING_FOR_WRITE;
+ waiter.timeout = jiffies + RWSEM_WAIT_TIMEOUT;
++ waiter.handoff_set = false;
+
+ raw_spin_lock_irq(&sem->wait_lock);
+-
+- /* account for this before adding a new element to the list */
+- wstate = list_empty(&sem->wait_list) ? WRITER_FIRST : WRITER_NOT_FIRST;
+-
+- list_add_tail(&waiter.list, &sem->wait_list);
++ rwsem_add_waiter(sem, &waiter);
+
+ /* we're now waiting on the lock */
+- if (wstate == WRITER_NOT_FIRST) {
++ if (rwsem_first_waiter(sem) != &waiter) {
+ count = atomic_long_read(&sem->count);
+
+ /*
+@@ -1080,13 +1116,16 @@ wait:
+ /* wait until we successfully acquire the lock */
+ set_current_state(state);
+ for (;;) {
+- if (rwsem_try_write_lock(sem, wstate)) {
++ if (rwsem_try_write_lock(sem, &waiter)) {
+ /* rwsem_try_write_lock() implies ACQUIRE on success */
+ break;
+ }
+
+ raw_spin_unlock_irq(&sem->wait_lock);
+
++ if (signal_pending_state(state, current))
++ goto out_nolock;
++
+ /*
+ * After setting the handoff bit and failing to acquire
+ * the lock, attempt to spin on owner to accelerate lock
+@@ -1095,70 +1134,37 @@ wait:
+ * In this case, we attempt to acquire the lock again
+ * without sleeping.
+ */
+- if (wstate == WRITER_HANDOFF &&
+- rwsem_spin_on_owner(sem) == OWNER_NULL)
+- goto trylock_again;
+-
+- /* Block until there are no active lockers. */
+- for (;;) {
+- if (signal_pending_state(state, current))
+- goto out_nolock;
+-
+- schedule();
+- lockevent_inc(rwsem_sleep_writer);
+- set_current_state(state);
+- /*
+- * If HANDOFF bit is set, unconditionally do
+- * a trylock.
+- */
+- if (wstate == WRITER_HANDOFF)
+- break;
+-
+- if ((wstate == WRITER_NOT_FIRST) &&
+- (rwsem_first_waiter(sem) == &waiter))
+- wstate = WRITER_FIRST;
++ if (waiter.handoff_set) {
++ enum owner_state owner_state;
+
+- count = atomic_long_read(&sem->count);
+- if (!(count & RWSEM_LOCK_MASK))
+- break;
++ preempt_disable();
++ owner_state = rwsem_spin_on_owner(sem);
++ preempt_enable();
+
+- /*
+- * The setting of the handoff bit is deferred
+- * until rwsem_try_write_lock() is called.
+- */
+- if ((wstate == WRITER_FIRST) && (rt_task(current) ||
+- time_after(jiffies, waiter.timeout))) {
+- wstate = WRITER_HANDOFF;
+- lockevent_inc(rwsem_wlock_handoff);
+- break;
+- }
++ if (owner_state == OWNER_NULL)
++ goto trylock_again;
+ }
++
++ schedule();
++ lockevent_inc(rwsem_sleep_writer);
++ set_current_state(state);
+ trylock_again:
+ raw_spin_lock_irq(&sem->wait_lock);
+ }
+ __set_current_state(TASK_RUNNING);
+- list_del(&waiter.list);
+ raw_spin_unlock_irq(&sem->wait_lock);
+ lockevent_inc(rwsem_wlock);
+-
+- return ret;
++ return sem;
+
+ out_nolock:
+ __set_current_state(TASK_RUNNING);
+ raw_spin_lock_irq(&sem->wait_lock);
+- list_del(&waiter.list);
+-
+- if (unlikely(wstate == WRITER_HANDOFF))
+- atomic_long_add(-RWSEM_FLAG_HANDOFF, &sem->count);
+-
+- if (list_empty(&sem->wait_list))
+- atomic_long_andnot(RWSEM_FLAG_WAITERS, &sem->count);
+- else
++ rwsem_del_waiter(sem, &waiter);
++ if (!list_empty(&sem->wait_list))
+ rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q);
+ raw_spin_unlock_irq(&sem->wait_lock);
+ wake_up_q(&wake_q);
+ lockevent_inc(rwsem_wlock_fail);
+-
+ return ERR_PTR(-EINTR);
+ }
+
+diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
+index a332ccd829e24..97e62469a6b32 100644
+--- a/kernel/power/energy_model.c
++++ b/kernel/power/energy_model.c
+@@ -107,8 +107,7 @@ static void em_debug_remove_pd(struct device *dev) {}
+ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
+ int nr_states, struct em_data_callback *cb)
+ {
+- unsigned long opp_eff, prev_opp_eff = ULONG_MAX;
+- unsigned long power, freq, prev_freq = 0;
++ unsigned long power, freq, prev_freq = 0, prev_cost = ULONG_MAX;
+ struct em_perf_state *table;
+ int i, ret;
+ u64 fmax;
+@@ -153,27 +152,21 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
+
+ table[i].power = power;
+ table[i].frequency = prev_freq = freq;
+-
+- /*
+- * The hertz/watts efficiency ratio should decrease as the
+- * frequency grows on sane platforms. But this isn't always
+- * true in practice so warn the user if a higher OPP is more
+- * power efficient than a lower one.
+- */
+- opp_eff = freq / power;
+- if (opp_eff >= prev_opp_eff)
+- dev_dbg(dev, "EM: hertz/watts ratio non-monotonically decreasing: em_perf_state %d >= em_perf_state%d\n",
+- i, i - 1);
+- prev_opp_eff = opp_eff;
+ }
+
+ /* Compute the cost of each performance state. */
+ fmax = (u64) table[nr_states - 1].frequency;
+- for (i = 0; i < nr_states; i++) {
++ for (i = nr_states - 1; i >= 0; i--) {
+ unsigned long power_res = em_scale_power(table[i].power);
+
+ table[i].cost = div64_u64(fmax * power_res,
+ table[i].frequency);
++ if (table[i].cost >= prev_cost) {
++ dev_dbg(dev, "EM: OPP:%lu is inefficient\n",
++ table[i].frequency);
++ } else {
++ prev_cost = table[i].cost;
++ }
+ }
+
+ pd->table = table;
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 559acef3fddb8..b0888e9224da3 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -691,7 +691,7 @@ static int load_image_and_restore(void)
+ goto Unlock;
+
+ error = swsusp_read(&flags);
+- swsusp_close(FMODE_READ);
++ swsusp_close(FMODE_READ | FMODE_EXCL);
+ if (!error)
+ error = hibernation_restore(flags & SF_PLATFORM_MODE);
+
+@@ -981,7 +981,7 @@ static int software_resume(void)
+ /* The snapshot device should not be opened while we're running */
+ if (!hibernate_acquire()) {
+ error = -EBUSY;
+- swsusp_close(FMODE_READ);
++ swsusp_close(FMODE_READ | FMODE_EXCL);
+ goto Unlock;
+ }
+
+@@ -1016,7 +1016,7 @@ static int software_resume(void)
+ pm_pr_dbg("Hibernation image not present or could not be loaded.\n");
+ return error;
+ Close_Finish:
+- swsusp_close(FMODE_READ);
++ swsusp_close(FMODE_READ | FMODE_EXCL);
+ goto Finish;
+ }
+
+diff --git a/kernel/power/swap.c b/kernel/power/swap.c
+index 3cb89baebc796..f3a1086f7cdb2 100644
+--- a/kernel/power/swap.c
++++ b/kernel/power/swap.c
+@@ -299,7 +299,7 @@ static int hib_submit_io(int op, int op_flags, pgoff_t page_off, void *addr,
+ return error;
+ }
+
+-static blk_status_t hib_wait_io(struct hib_bio_batch *hb)
++static int hib_wait_io(struct hib_bio_batch *hb)
+ {
+ /*
+ * We are relying on the behavior of blk_plug that a thread with
+@@ -1521,9 +1521,10 @@ end:
+ int swsusp_check(void)
+ {
+ int error;
++ void *holder;
+
+ hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device,
+- FMODE_READ, NULL);
++ FMODE_READ | FMODE_EXCL, &holder);
+ if (!IS_ERR(hib_resume_bdev)) {
+ set_blocksize(hib_resume_bdev, PAGE_SIZE);
+ clear_page(swsusp_header);
+@@ -1545,7 +1546,7 @@ int swsusp_check(void)
+
+ put:
+ if (error)
+- blkdev_put(hib_resume_bdev, FMODE_READ);
++ blkdev_put(hib_resume_bdev, FMODE_READ | FMODE_EXCL);
+ else
+ pr_debug("Image signature found, resuming\n");
+ } else {
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+index a8d0a58deebc7..99221b016c68b 100644
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -3252,6 +3252,11 @@ void defer_console_output(void)
+ preempt_enable();
+ }
+
++void printk_trigger_flush(void)
++{
++ defer_console_output();
++}
++
+ int vprintk_deferred(const char *fmt, va_list args)
+ {
+ int r;
+diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
+index ab4215266ebee..968696ace8f3f 100644
+--- a/kernel/rcu/rcutorture.c
++++ b/kernel/rcu/rcutorture.c
+@@ -1432,28 +1432,34 @@ static void rcutorture_one_extend(int *readstate, int newstate,
+ /* First, put new protection in place to avoid critical-section gap. */
+ if (statesnew & RCUTORTURE_RDR_BH)
+ local_bh_disable();
++ if (statesnew & RCUTORTURE_RDR_RBH)
++ rcu_read_lock_bh();
+ if (statesnew & RCUTORTURE_RDR_IRQ)
+ local_irq_disable();
+ if (statesnew & RCUTORTURE_RDR_PREEMPT)
+ preempt_disable();
+- if (statesnew & RCUTORTURE_RDR_RBH)
+- rcu_read_lock_bh();
+ if (statesnew & RCUTORTURE_RDR_SCHED)
+ rcu_read_lock_sched();
+ if (statesnew & RCUTORTURE_RDR_RCU)
+ idxnew = cur_ops->readlock() << RCUTORTURE_RDR_SHIFT;
+
+- /* Next, remove old protection, irq first due to bh conflict. */
++ /*
++ * Next, remove old protection, in decreasing order of strength
++ * to avoid unlock paths that aren't safe in the stronger
++ * context. Namely: BH can not be enabled with disabled interrupts.
++ * Additionally PREEMPT_RT requires that BH is enabled in preemptible
++ * context.
++ */
+ if (statesold & RCUTORTURE_RDR_IRQ)
+ local_irq_enable();
+- if (statesold & RCUTORTURE_RDR_BH)
+- local_bh_enable();
+ if (statesold & RCUTORTURE_RDR_PREEMPT)
+ preempt_enable();
+- if (statesold & RCUTORTURE_RDR_RBH)
+- rcu_read_unlock_bh();
+ if (statesold & RCUTORTURE_RDR_SCHED)
+ rcu_read_unlock_sched();
++ if (statesold & RCUTORTURE_RDR_BH)
++ local_bh_enable();
++ if (statesold & RCUTORTURE_RDR_RBH)
++ rcu_read_unlock_bh();
+ if (statesold & RCUTORTURE_RDR_RCU) {
+ bool lockit = !statesnew && !(torture_random(trsp) & 0xffff);
+
+@@ -1496,6 +1502,9 @@ rcutorture_extend_mask(int oldmask, struct torture_random_state *trsp)
+ int mask = rcutorture_extend_mask_max();
+ unsigned long randmask1 = torture_random(trsp) >> 8;
+ unsigned long randmask2 = randmask1 >> 3;
++ unsigned long preempts = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED;
++ unsigned long preempts_irq = preempts | RCUTORTURE_RDR_IRQ;
++ unsigned long bhs = RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH;
+
+ WARN_ON_ONCE(mask >> RCUTORTURE_RDR_SHIFT);
+ /* Mostly only one bit (need preemption!), sometimes lots of bits. */
+@@ -1503,11 +1512,26 @@ rcutorture_extend_mask(int oldmask, struct torture_random_state *trsp)
+ mask = mask & randmask2;
+ else
+ mask = mask & (1 << (randmask2 % RCUTORTURE_RDR_NBITS));
+- /* Can't enable bh w/irq disabled. */
+- if ((mask & RCUTORTURE_RDR_IRQ) &&
+- ((!(mask & RCUTORTURE_RDR_BH) && (oldmask & RCUTORTURE_RDR_BH)) ||
+- (!(mask & RCUTORTURE_RDR_RBH) && (oldmask & RCUTORTURE_RDR_RBH))))
+- mask |= RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH;
++
++ /*
++ * Can't enable bh w/irq disabled.
++ */
++ if (mask & RCUTORTURE_RDR_IRQ)
++ mask |= oldmask & bhs;
++
++ /*
++ * Ideally these sequences would be detected in debug builds
++ * (regardless of RT), but until then don't stop testing
++ * them on non-RT.
++ */
++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
++ /* Can't modify BH in atomic context */
++ if (oldmask & preempts_irq)
++ mask &= ~bhs;
++ if ((oldmask | mask) & preempts_irq)
++ mask |= oldmask & bhs;
++ }
++
+ return mask ?: RCUTORTURE_RDR_RCU;
+ }
+
+diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
+index 806160c44b172..6591914af4864 100644
+--- a/kernel/rcu/tasks.h
++++ b/kernel/rcu/tasks.h
+@@ -197,6 +197,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
+ * This loop is terminated by the system going down. ;-)
+ */
+ for (;;) {
++ set_tasks_gp_state(rtp, RTGS_WAIT_CBS);
+
+ /* Pick up any new callbacks. */
+ raw_spin_lock_irqsave(&rtp->cbs_lock, flags);
+@@ -236,8 +237,6 @@ static int __noreturn rcu_tasks_kthread(void *arg)
+ }
+ /* Paranoid sleep to keep this from entering a tight loop */
+ schedule_timeout_idle(rtp->gp_sleep);
+-
+- set_tasks_gp_state(rtp, RTGS_WAIT_CBS);
+ }
+ }
+
+diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
+index bce848e50512e..7ae10fab68b8f 100644
+--- a/kernel/rcu/tree.c
++++ b/kernel/rcu/tree.c
+@@ -327,7 +327,7 @@ static void rcu_dynticks_eqs_online(void)
+ */
+ static __always_inline bool rcu_dynticks_curr_cpu_in_eqs(void)
+ {
+- return !(atomic_read(this_cpu_ptr(&rcu_data.dynticks)) & 0x1);
++ return !(arch_atomic_read(this_cpu_ptr(&rcu_data.dynticks)) & 0x1);
+ }
+
+ /*
+@@ -1907,7 +1907,7 @@ static void rcu_gp_fqs(bool first_time)
+ struct rcu_node *rnp = rcu_get_root();
+
+ WRITE_ONCE(rcu_state.gp_activity, jiffies);
+- rcu_state.n_force_qs++;
++ WRITE_ONCE(rcu_state.n_force_qs, rcu_state.n_force_qs + 1);
+ if (first_time) {
+ /* Collect dyntick-idle snapshots. */
+ force_qs_rnp(dyntick_save_progress_counter);
+@@ -2550,7 +2550,7 @@ static void rcu_do_batch(struct rcu_data *rdp)
+ /* Reset ->qlen_last_fqs_check trigger if enough CBs have drained. */
+ if (count == 0 && rdp->qlen_last_fqs_check != 0) {
+ rdp->qlen_last_fqs_check = 0;
+- rdp->n_force_qs_snap = rcu_state.n_force_qs;
++ rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
+ } else if (count < rdp->qlen_last_fqs_check - qhimark)
+ rdp->qlen_last_fqs_check = count;
+
+@@ -2898,10 +2898,10 @@ static void __call_rcu_core(struct rcu_data *rdp, struct rcu_head *head,
+ } else {
+ /* Give the grace period a kick. */
+ rdp->blimit = DEFAULT_MAX_RCU_BLIMIT;
+- if (rcu_state.n_force_qs == rdp->n_force_qs_snap &&
++ if (READ_ONCE(rcu_state.n_force_qs) == rdp->n_force_qs_snap &&
+ rcu_segcblist_first_pend_cb(&rdp->cblist) != head)
+ rcu_force_quiescent_state();
+- rdp->n_force_qs_snap = rcu_state.n_force_qs;
++ rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
+ rdp->qlen_last_fqs_check = rcu_segcblist_n_cbs(&rdp->cblist);
+ }
+ }
+@@ -4128,7 +4128,7 @@ int rcutree_prepare_cpu(unsigned int cpu)
+ /* Set up local state, ensuring consistent view of global state. */
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
+ rdp->qlen_last_fqs_check = 0;
+- rdp->n_force_qs_snap = rcu_state.n_force_qs;
++ rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
+ rdp->blimit = blimit;
+ rdp->dynticks_nesting = 1; /* CPU not up, no tearing. */
+ rcu_dynticks_eqs_online();
+diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
+index 2796084ef85a5..454b516ea566e 100644
+--- a/kernel/rcu/tree_exp.h
++++ b/kernel/rcu/tree_exp.h
+@@ -760,7 +760,7 @@ static void sync_sched_exp_online_cleanup(int cpu)
+ my_cpu = get_cpu();
+ /* Quiescent state either not needed or already requested, leave. */
+ if (!(READ_ONCE(rnp->expmask) & rdp->grpmask) ||
+- __this_cpu_read(rcu_data.cpu_no_qs.b.exp)) {
++ rdp->cpu_no_qs.b.exp) {
+ put_cpu();
+ return;
+ }
+diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
+index d070059163d70..0d21a5cdc7247 100644
+--- a/kernel/rcu/tree_plugin.h
++++ b/kernel/rcu/tree_plugin.h
+@@ -1480,7 +1480,7 @@ static void rcu_bind_gp_kthread(void)
+ }
+
+ /* Record the current task on dyntick-idle entry. */
+-static void noinstr rcu_dynticks_task_enter(void)
++static __always_inline void rcu_dynticks_task_enter(void)
+ {
+ #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+ WRITE_ONCE(current->rcu_tasks_idle_cpu, smp_processor_id());
+@@ -1488,7 +1488,7 @@ static void noinstr rcu_dynticks_task_enter(void)
+ }
+
+ /* Record no current task on dyntick-idle exit. */
+-static void noinstr rcu_dynticks_task_exit(void)
++static __always_inline void rcu_dynticks_task_exit(void)
+ {
+ #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+ WRITE_ONCE(current->rcu_tasks_idle_cpu, -1);
+@@ -1496,7 +1496,7 @@ static void noinstr rcu_dynticks_task_exit(void)
+ }
+
+ /* Turn on heavyweight RCU tasks trace readers on idle/user entry. */
+-static void rcu_dynticks_task_trace_enter(void)
++static __always_inline void rcu_dynticks_task_trace_enter(void)
+ {
+ #ifdef CONFIG_TASKS_TRACE_RCU
+ if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
+@@ -1505,7 +1505,7 @@ static void rcu_dynticks_task_trace_enter(void)
+ }
+
+ /* Turn off heavyweight RCU tasks trace readers on idle/user exit. */
+-static void rcu_dynticks_task_trace_exit(void)
++static __always_inline void rcu_dynticks_task_trace_exit(void)
+ {
+ #ifdef CONFIG_TASKS_TRACE_RCU
+ if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
+diff --git a/kernel/sched/autogroup.c b/kernel/sched/autogroup.c
+index 2067080bb2358..8629b37d118e7 100644
+--- a/kernel/sched/autogroup.c
++++ b/kernel/sched/autogroup.c
+@@ -31,7 +31,7 @@ static inline void autogroup_destroy(struct kref *kref)
+ ag->tg->rt_se = NULL;
+ ag->tg->rt_rq = NULL;
+ #endif
+- sched_offline_group(ag->tg);
++ sched_release_group(ag->tg);
+ sched_destroy_group(ag->tg);
+ }
+
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index f21714ea3db85..0d12ec7be3017 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1914,7 +1914,7 @@ static void __init init_uclamp_rq(struct rq *rq)
+ };
+ }
+
+- rq->uclamp_flags = 0;
++ rq->uclamp_flags = UCLAMP_FLAG_IDLE;
+ }
+
+ static void __init init_uclamp(void)
+@@ -3707,6 +3707,9 @@ out:
+
+ bool cpus_share_cache(int this_cpu, int that_cpu)
+ {
++ if (this_cpu == that_cpu)
++ return true;
++
+ return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
+ }
+
+@@ -4328,8 +4331,6 @@ int sysctl_schedstats(struct ctl_table *table, int write, void *buffer,
+ */
+ int sched_fork(unsigned long clone_flags, struct task_struct *p)
+ {
+- unsigned long flags;
+-
+ __sched_fork(clone_flags, p);
+ /*
+ * We mark the process as NEW here. This guarantees that
+@@ -4375,24 +4376,6 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
+
+ init_entity_runnable_average(&p->se);
+
+- /*
+- * The child is not yet in the pid-hash so no cgroup attach races,
+- * and the cgroup is pinned to this child due to cgroup_fork()
+- * is ran before sched_fork().
+- *
+- * Silence PROVE_RCU.
+- */
+- raw_spin_lock_irqsave(&p->pi_lock, flags);
+- rseq_migrate(p);
+- /*
+- * We're setting the CPU for the first time, we don't migrate,
+- * so use __set_task_cpu().
+- */
+- __set_task_cpu(p, smp_processor_id());
+- if (p->sched_class->task_fork)
+- p->sched_class->task_fork(p);
+- raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+-
+ #ifdef CONFIG_SCHED_INFO
+ if (likely(sched_info_on()))
+ memset(&p->sched_info, 0, sizeof(p->sched_info));
+@@ -4408,8 +4391,29 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
+ return 0;
+ }
+
+-void sched_post_fork(struct task_struct *p)
++void sched_post_fork(struct task_struct *p, struct kernel_clone_args *kargs)
+ {
++ unsigned long flags;
++#ifdef CONFIG_CGROUP_SCHED
++ struct task_group *tg;
++#endif
++
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++#ifdef CONFIG_CGROUP_SCHED
++ tg = container_of(kargs->cset->subsys[cpu_cgrp_id],
++ struct task_group, css);
++ p->sched_task_group = autogroup_task_group(p, tg);
++#endif
++ rseq_migrate(p);
++ /*
++ * We're setting the CPU for the first time, we don't migrate,
++ * so use __set_task_cpu().
++ */
++ __set_task_cpu(p, smp_processor_id());
++ if (p->sched_class->task_fork)
++ p->sched_class->task_fork(p);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++
+ uclamp_post_fork(p);
+ }
+
+@@ -6656,11 +6660,11 @@ static int __init setup_preempt_mode(char *str)
+ int mode = sched_dynamic_mode(str);
+ if (mode < 0) {
+ pr_warn("Dynamic Preempt: unsupported mode: %s\n", str);
+- return 1;
++ return 0;
+ }
+
+ sched_dynamic_update(mode);
+- return 0;
++ return 1;
+ }
+ __setup("preempt=", setup_preempt_mode);
+
+@@ -8637,9 +8641,6 @@ void __init init_idle(struct task_struct *idle, int cpu)
+ idle->flags |= PF_IDLE | PF_KTHREAD | PF_NO_SETAFFINITY;
+ kthread_set_per_cpu(idle, cpu);
+
+- scs_task_reset(idle);
+- kasan_unpoison_task_stack(idle);
+-
+ #ifdef CONFIG_SMP
+ /*
+ * It's possible that init_idle() gets called multiple times on a task,
+@@ -8795,7 +8796,6 @@ void idle_task_exit(void)
+ finish_arch_post_lock_switch();
+ }
+
+- scs_task_reset(current);
+ /* finish_cpu(), as ran on the BP, will clean up the active_mm state */
+ }
+
+@@ -9716,6 +9716,22 @@ static void sched_free_group(struct task_group *tg)
+ kmem_cache_free(task_group_cache, tg);
+ }
+
++static void sched_free_group_rcu(struct rcu_head *rcu)
++{
++ sched_free_group(container_of(rcu, struct task_group, rcu));
++}
++
++static void sched_unregister_group(struct task_group *tg)
++{
++ unregister_fair_sched_group(tg);
++ unregister_rt_sched_group(tg);
++ /*
++ * We have to wait for yet another RCU grace period to expire, as
++ * print_cfs_stats() might run concurrently.
++ */
++ call_rcu(&tg->rcu, sched_free_group_rcu);
++}
++
+ /* allocate runqueue etc for a new task group */
+ struct task_group *sched_create_group(struct task_group *parent)
+ {
+@@ -9759,25 +9775,35 @@ void sched_online_group(struct task_group *tg, struct task_group *parent)
+ }
+
+ /* rcu callback to free various structures associated with a task group */
+-static void sched_free_group_rcu(struct rcu_head *rhp)
++static void sched_unregister_group_rcu(struct rcu_head *rhp)
+ {
+ /* Now it should be safe to free those cfs_rqs: */
+- sched_free_group(container_of(rhp, struct task_group, rcu));
++ sched_unregister_group(container_of(rhp, struct task_group, rcu));
+ }
+
+ void sched_destroy_group(struct task_group *tg)
+ {
+ /* Wait for possible concurrent references to cfs_rqs complete: */
+- call_rcu(&tg->rcu, sched_free_group_rcu);
++ call_rcu(&tg->rcu, sched_unregister_group_rcu);
+ }
+
+-void sched_offline_group(struct task_group *tg)
++void sched_release_group(struct task_group *tg)
+ {
+ unsigned long flags;
+
+- /* End participation in shares distribution: */
+- unregister_fair_sched_group(tg);
+-
++ /*
++ * Unlink first, to avoid walk_tg_tree_from() from finding us (via
++ * sched_cfs_period_timer()).
++ *
++ * For this to be effective, we have to wait for all pending users of
++ * this task group to leave their RCU critical section to ensure no new
++ * user will see our dying task group any more. Specifically ensure
++ * that tg_unthrottle_up() won't add decayed cfs_rq's to it.
++ *
++ * We therefore defer calling unregister_fair_sched_group() to
++ * sched_unregister_group() which is guarantied to get called only after the
++ * current RCU grace period has expired.
++ */
+ spin_lock_irqsave(&task_group_lock, flags);
+ list_del_rcu(&tg->list);
+ list_del_rcu(&tg->siblings);
+@@ -9896,7 +9922,7 @@ static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
+ {
+ struct task_group *tg = css_tg(css);
+
+- sched_offline_group(tg);
++ sched_release_group(tg);
+ }
+
+ static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
+@@ -9906,7 +9932,7 @@ static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
+ /*
+ * Relies on the RCU grace period between css_released() and this.
+ */
+- sched_free_group(tg);
++ sched_unregister_group(tg);
+ }
+
+ /*
+diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
+index f6a05d9b54436..6f16dfb742462 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -11358,8 +11358,6 @@ void free_fair_sched_group(struct task_group *tg)
+ {
+ int i;
+
+- destroy_cfs_bandwidth(tg_cfs_bandwidth(tg));
+-
+ for_each_possible_cpu(i) {
+ if (tg->cfs_rq)
+ kfree(tg->cfs_rq[i]);
+@@ -11436,6 +11434,8 @@ void unregister_fair_sched_group(struct task_group *tg)
+ struct rq *rq;
+ int cpu;
+
++ destroy_cfs_bandwidth(tg_cfs_bandwidth(tg));
++
+ for_each_possible_cpu(cpu) {
+ if (tg->se[cpu])
+ remove_entity_load_avg(tg->se[cpu]);
+diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
+index 3daf42a0f4623..bfef3f39b5552 100644
+--- a/kernel/sched/rt.c
++++ b/kernel/sched/rt.c
+@@ -137,13 +137,17 @@ static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se)
+ return rt_rq->rq;
+ }
+
+-void free_rt_sched_group(struct task_group *tg)
++void unregister_rt_sched_group(struct task_group *tg)
+ {
+- int i;
+-
+ if (tg->rt_se)
+ destroy_rt_bandwidth(&tg->rt_bandwidth);
+
++}
++
++void free_rt_sched_group(struct task_group *tg)
++{
++ int i;
++
+ for_each_possible_cpu(i) {
+ if (tg->rt_rq)
+ kfree(tg->rt_rq[i]);
+@@ -250,6 +254,8 @@ static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se)
+ return &rq->rt;
+ }
+
++void unregister_rt_sched_group(struct task_group *tg) { }
++
+ void free_rt_sched_group(struct task_group *tg) { }
+
+ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index 3d3e5793e1172..4f432826933da 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -486,6 +486,7 @@ extern void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b);
+ extern void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b);
+ extern void unthrottle_cfs_rq(struct cfs_rq *cfs_rq);
+
++extern void unregister_rt_sched_group(struct task_group *tg);
+ extern void free_rt_sched_group(struct task_group *tg);
+ extern int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent);
+ extern void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,
+@@ -501,7 +502,7 @@ extern struct task_group *sched_create_group(struct task_group *parent);
+ extern void sched_online_group(struct task_group *tg,
+ struct task_group *parent);
+ extern void sched_destroy_group(struct task_group *tg);
+-extern void sched_offline_group(struct task_group *tg);
++extern void sched_release_group(struct task_group *tg);
+
+ extern void sched_move_task(struct task_struct *tsk);
+
+diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
+index 76577d1642a5d..eca38107b32f1 100644
+--- a/kernel/sched/wait.c
++++ b/kernel/sched/wait.c
+@@ -238,6 +238,13 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode)
+ }
+ EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */
+
++void __wake_up_pollfree(struct wait_queue_head *wq_head)
++{
++ __wake_up(wq_head, TASK_NORMAL, 0, poll_to_key(EPOLLHUP | POLLFREE));
++ /* POLLFREE must have cleared the queue. */
++ WARN_ON_ONCE(waitqueue_active(wq_head));
++}
++
+ /*
+ * Note: we use "set_current_state()" _after_ the wait-queue add,
+ * because we need a memory barrier there on SMP, so that any
+diff --git a/kernel/scs.c b/kernel/scs.c
+index e2a71fc82fa06..579841be88646 100644
+--- a/kernel/scs.c
++++ b/kernel/scs.c
+@@ -78,6 +78,7 @@ void scs_free(void *s)
+ if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL)
+ return;
+
++ kasan_unpoison_vmalloc(s, SCS_SIZE);
+ vfree_atomic(s);
+ }
+
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 487bf4f5dadf4..5892c91696f84 100644
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -1298,6 +1298,12 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p
+ return ret;
+ }
+
++enum sig_handler {
++ HANDLER_CURRENT, /* If reachable use the current handler */
++ HANDLER_SIG_DFL, /* Always use SIG_DFL handler semantics */
++ HANDLER_EXIT, /* Only visible as the process exit code */
++};
++
+ /*
+ * Force a signal that the process can't ignore: if necessary
+ * we unblock the signal and change any SIG_IGN to SIG_DFL.
+@@ -1310,7 +1316,8 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p
+ * that is why we also clear SIGNAL_UNKILLABLE.
+ */
+ static int
+-force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool sigdfl)
++force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
++ enum sig_handler handler)
+ {
+ unsigned long int flags;
+ int ret, blocked, ignored;
+@@ -1321,8 +1328,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool
+ action = &t->sighand->action[sig-1];
+ ignored = action->sa.sa_handler == SIG_IGN;
+ blocked = sigismember(&t->blocked, sig);
+- if (blocked || ignored || sigdfl) {
++ if (blocked || ignored || (handler != HANDLER_CURRENT)) {
+ action->sa.sa_handler = SIG_DFL;
++ if (handler == HANDLER_EXIT)
++ action->sa.sa_flags |= SA_IMMUTABLE;
+ if (blocked) {
+ sigdelset(&t->blocked, sig);
+ recalc_sigpending_and_wake(t);
+@@ -1342,7 +1351,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool
+
+ int force_sig_info(struct kernel_siginfo *info)
+ {
+- return force_sig_info_to_task(info, current, false);
++ return force_sig_info_to_task(info, current, HANDLER_CURRENT);
+ }
+
+ /*
+@@ -1649,6 +1658,32 @@ void force_sig(int sig)
+ }
+ EXPORT_SYMBOL(force_sig);
+
++void force_fatal_sig(int sig)
++{
++ struct kernel_siginfo info;
++
++ clear_siginfo(&info);
++ info.si_signo = sig;
++ info.si_errno = 0;
++ info.si_code = SI_KERNEL;
++ info.si_pid = 0;
++ info.si_uid = 0;
++ force_sig_info_to_task(&info, current, HANDLER_SIG_DFL);
++}
++
++void force_exit_sig(int sig)
++{
++ struct kernel_siginfo info;
++
++ clear_siginfo(&info);
++ info.si_signo = sig;
++ info.si_errno = 0;
++ info.si_code = SI_KERNEL;
++ info.si_pid = 0;
++ info.si_uid = 0;
++ force_sig_info_to_task(&info, current, HANDLER_EXIT);
++}
++
+ /*
+ * When things go south during signal handling, we
+ * will force a SIGSEGV. And if the signal that caused
+@@ -1657,15 +1692,10 @@ EXPORT_SYMBOL(force_sig);
+ */
+ void force_sigsegv(int sig)
+ {
+- struct task_struct *p = current;
+-
+- if (sig == SIGSEGV) {
+- unsigned long flags;
+- spin_lock_irqsave(&p->sighand->siglock, flags);
+- p->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
+- spin_unlock_irqrestore(&p->sighand->siglock, flags);
+- }
+- force_sig(SIGSEGV);
++ if (sig == SIGSEGV)
++ force_fatal_sig(SIGSEGV);
++ else
++ force_sig(SIGSEGV);
+ }
+
+ int force_sig_fault_to_task(int sig, int code, void __user *addr
+@@ -1684,7 +1714,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addr
+ info.si_flags = flags;
+ info.si_isr = isr;
+ #endif
+- return force_sig_info_to_task(&info, t, false);
++ return force_sig_info_to_task(&info, t, HANDLER_CURRENT);
+ }
+
+ int force_sig_fault(int sig, int code, void __user *addr
+@@ -1804,7 +1834,8 @@ int force_sig_seccomp(int syscall, int reason, bool force_coredump)
+ info.si_errno = reason;
+ info.si_arch = syscall_get_arch(current);
+ info.si_syscall = syscall;
+- return force_sig_info_to_task(&info, current, force_coredump);
++ return force_sig_info_to_task(&info, current,
++ force_coredump ? HANDLER_EXIT : HANDLER_CURRENT);
+ }
+
+ /* For the crazy architectures that include trap information in
+@@ -2169,15 +2200,6 @@ static inline bool may_ptrace_stop(void)
+ return true;
+ }
+
+-/*
+- * Return non-zero if there is a SIGKILL that should be waking us up.
+- * Called with the siglock held.
+- */
+-static bool sigkill_pending(struct task_struct *tsk)
+-{
+- return sigismember(&tsk->pending.signal, SIGKILL) ||
+- sigismember(&tsk->signal->shared_pending.signal, SIGKILL);
+-}
+
+ /*
+ * This must be called with current->sighand->siglock held.
+@@ -2204,17 +2226,16 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
+ * calling arch_ptrace_stop, so we must release it now.
+ * To preserve proper semantics, we must do this before
+ * any signal bookkeeping like checking group_stop_count.
+- * Meanwhile, a SIGKILL could come in before we retake the
+- * siglock. That must prevent us from sleeping in TASK_TRACED.
+- * So after regaining the lock, we must check for SIGKILL.
+ */
+ spin_unlock_irq(&current->sighand->siglock);
+ arch_ptrace_stop(exit_code, info);
+ spin_lock_irq(&current->sighand->siglock);
+- if (sigkill_pending(current))
+- return;
+ }
+
++ /*
++ * schedule() will not sleep if there is a pending signal that
++ * can awaken the task.
++ */
+ set_special_state(TASK_TRACED);
+
+ /*
+@@ -2739,7 +2760,8 @@ relock:
+ if (!signr)
+ break; /* will return 0 */
+
+- if (unlikely(current->ptrace) && signr != SIGKILL) {
++ if (unlikely(current->ptrace) && (signr != SIGKILL) &&
++ !(sighand->action[signr -1].sa.sa_flags & SA_IMMUTABLE)) {
+ signr = ptrace_signal(signr, &ksig->info);
+ if (!signr)
+ continue;
+@@ -4089,6 +4111,10 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
+ k = &p->sighand->action[sig-1];
+
+ spin_lock_irq(&p->sighand->siglock);
++ if (k->sa.sa_flags & SA_IMMUTABLE) {
++ spin_unlock_irq(&p->sighand->siglock);
++ return -EINVAL;
++ }
+ if (oact)
+ *oact = *k;
+
+diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
+index 643d412ac6235..96b4e78104266 100644
+--- a/kernel/time/posix-cpu-timers.c
++++ b/kernel/time/posix-cpu-timers.c
+@@ -1158,14 +1158,29 @@ static void posix_cpu_timers_work(struct callback_head *work)
+ handle_posix_cpu_timers(current);
+ }
+
++/*
++ * Clear existing posix CPU timers task work.
++ */
++void clear_posix_cputimers_work(struct task_struct *p)
++{
++ /*
++ * A copied work entry from the old task is not meaningful, clear it.
++ * N.B. init_task_work will not do this.
++ */
++ memset(&p->posix_cputimers_work.work, 0,
++ sizeof(p->posix_cputimers_work.work));
++ init_task_work(&p->posix_cputimers_work.work,
++ posix_cpu_timers_work);
++ p->posix_cputimers_work.scheduled = false;
++}
++
+ /*
+ * Initialize posix CPU timers task work in init task. Out of line to
+ * keep the callback static and to avoid header recursion hell.
+ */
+ void __init posix_cputimers_init_work(void)
+ {
+- init_task_work(&current->posix_cputimers_work.work,
+- posix_cpu_timers_work);
++ clear_posix_cputimers_work(current);
+ }
+
+ /*
+diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
+index b348749a9fc62..dcdcb85121e40 100644
+--- a/kernel/time/timekeeping.c
++++ b/kernel/time/timekeeping.c
+@@ -1306,8 +1306,7 @@ int do_settimeofday64(const struct timespec64 *ts)
+ timekeeping_forward_now(tk);
+
+ xt = tk_xtime(tk);
+- ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
+- ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
++ ts_delta = timespec64_sub(*ts, xt);
+
+ if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
+ ret = -EINVAL;
+diff --git a/kernel/time/timer.c b/kernel/time/timer.c
+index e3d2c23c413d4..85f1021ad4595 100644
+--- a/kernel/time/timer.c
++++ b/kernel/time/timer.c
+@@ -2054,26 +2054,28 @@ unsigned long msleep_interruptible(unsigned int msecs)
+ EXPORT_SYMBOL(msleep_interruptible);
+
+ /**
+- * usleep_range - Sleep for an approximate time
+- * @min: Minimum time in usecs to sleep
+- * @max: Maximum time in usecs to sleep
++ * usleep_range_state - Sleep for an approximate time in a given state
++ * @min: Minimum time in usecs to sleep
++ * @max: Maximum time in usecs to sleep
++ * @state: State of the current task that will be while sleeping
+ *
+ * In non-atomic context where the exact wakeup time is flexible, use
+- * usleep_range() instead of udelay(). The sleep improves responsiveness
++ * usleep_range_state() instead of udelay(). The sleep improves responsiveness
+ * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces
+ * power usage by allowing hrtimers to take advantage of an already-
+ * scheduled interrupt instead of scheduling a new one just for this sleep.
+ */
+-void __sched usleep_range(unsigned long min, unsigned long max)
++void __sched usleep_range_state(unsigned long min, unsigned long max,
++ unsigned int state)
+ {
+ ktime_t exp = ktime_add_us(ktime_get(), min);
+ u64 delta = (u64)(max - min) * NSEC_PER_USEC;
+
+ for (;;) {
+- __set_current_state(TASK_UNINTERRUPTIBLE);
++ __set_current_state(state);
+ /* Do not return before the requested sleep time has elapsed */
+ if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS))
+ break;
+ }
+ }
+-EXPORT_SYMBOL(usleep_range);
++EXPORT_SYMBOL(usleep_range_state);
+diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
+index 8e2eb950aa829..6c1038526d1fc 100644
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -1037,8 +1037,6 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
+ return &bpf_ktime_get_ns_proto;
+ case BPF_FUNC_ktime_get_boot_ns:
+ return &bpf_ktime_get_boot_ns_proto;
+- case BPF_FUNC_ktime_get_coarse_ns:
+- return &bpf_ktime_get_coarse_ns_proto;
+ case BPF_FUNC_tail_call:
+ return &bpf_tail_call_proto;
+ case BPF_FUNC_get_current_pid_tgid:
+diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
+index feebf57c64588..c672040142e98 100644
+--- a/kernel/trace/ftrace.c
++++ b/kernel/trace/ftrace.c
+@@ -988,8 +988,9 @@ static __init void ftrace_profile_tracefs(struct dentry *d_tracer)
+ }
+ }
+
+- entry = tracefs_create_file("function_profile_enabled", 0644,
+- d_tracer, NULL, &ftrace_profile_fops);
++ entry = tracefs_create_file("function_profile_enabled",
++ TRACE_MODE_WRITE, d_tracer, NULL,
++ &ftrace_profile_fops);
+ if (!entry)
+ pr_warn("Could not create tracefs 'function_profile_enabled' entry\n");
+ }
+@@ -6109,10 +6110,10 @@ void ftrace_create_filter_files(struct ftrace_ops *ops,
+ struct dentry *parent)
+ {
+
+- trace_create_file("set_ftrace_filter", 0644, parent,
++ trace_create_file("set_ftrace_filter", TRACE_MODE_WRITE, parent,
+ ops, &ftrace_filter_fops);
+
+- trace_create_file("set_ftrace_notrace", 0644, parent,
++ trace_create_file("set_ftrace_notrace", TRACE_MODE_WRITE, parent,
+ ops, &ftrace_notrace_fops);
+ }
+
+@@ -6139,19 +6140,19 @@ void ftrace_destroy_filter_files(struct ftrace_ops *ops)
+ static __init int ftrace_init_dyn_tracefs(struct dentry *d_tracer)
+ {
+
+- trace_create_file("available_filter_functions", 0444,
++ trace_create_file("available_filter_functions", TRACE_MODE_READ,
+ d_tracer, NULL, &ftrace_avail_fops);
+
+- trace_create_file("enabled_functions", 0444,
++ trace_create_file("enabled_functions", TRACE_MODE_READ,
+ d_tracer, NULL, &ftrace_enabled_fops);
+
+ ftrace_create_filter_files(&global_ops, d_tracer);
+
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+- trace_create_file("set_graph_function", 0644, d_tracer,
++ trace_create_file("set_graph_function", TRACE_MODE_WRITE, d_tracer,
+ NULL,
+ &ftrace_graph_fops);
+- trace_create_file("set_graph_notrace", 0644, d_tracer,
++ trace_create_file("set_graph_notrace", TRACE_MODE_WRITE, d_tracer,
+ NULL,
+ &ftrace_graph_notrace_fops);
+ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+@@ -7494,10 +7495,10 @@ static const struct file_operations ftrace_no_pid_fops = {
+
+ void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer)
+ {
+- trace_create_file("set_ftrace_pid", 0644, d_tracer,
++ trace_create_file("set_ftrace_pid", TRACE_MODE_WRITE, d_tracer,
+ tr, &ftrace_pid_fops);
+- trace_create_file("set_ftrace_notrace_pid", 0644, d_tracer,
+- tr, &ftrace_no_pid_fops);
++ trace_create_file("set_ftrace_notrace_pid", TRACE_MODE_WRITE,
++ d_tracer, tr, &ftrace_no_pid_fops);
+ }
+
+ void __init ftrace_init_tracefs_toplevel(struct trace_array *tr,
+diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
+index c5a3fbf19617e..46ae72095c1e2 100644
+--- a/kernel/trace/ring_buffer.c
++++ b/kernel/trace/ring_buffer.c
+@@ -5233,6 +5233,9 @@ void ring_buffer_reset(struct trace_buffer *buffer)
+ struct ring_buffer_per_cpu *cpu_buffer;
+ int cpu;
+
++ /* prevent another thread from changing buffer sizes */
++ mutex_lock(&buffer->mutex);
++
+ for_each_buffer_cpu(buffer, cpu) {
+ cpu_buffer = buffer->buffers[cpu];
+
+@@ -5251,6 +5254,8 @@ void ring_buffer_reset(struct trace_buffer *buffer)
+ atomic_dec(&cpu_buffer->record_disabled);
+ atomic_dec(&cpu_buffer->resize_disabled);
+ }
++
++ mutex_unlock(&buffer->mutex);
+ }
+ EXPORT_SYMBOL_GPL(ring_buffer_reset);
+
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index bc677cd642240..18db461f77cdf 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -1714,7 +1714,8 @@ static void trace_create_maxlat_file(struct trace_array *tr,
+ {
+ INIT_WORK(&tr->fsnotify_work, latency_fsnotify_workfn);
+ init_irq_work(&tr->fsnotify_irqwork, latency_fsnotify_workfn_irq);
+- tr->d_max_latency = trace_create_file("tracing_max_latency", 0644,
++ tr->d_max_latency = trace_create_file("tracing_max_latency",
++ TRACE_MODE_WRITE,
+ d_tracer, &tr->max_latency,
+ &tracing_max_lat_fops);
+ }
+@@ -1748,8 +1749,8 @@ void latency_fsnotify(struct trace_array *tr)
+ || defined(CONFIG_OSNOISE_TRACER)
+
+ #define trace_create_maxlat_file(tr, d_tracer) \
+- trace_create_file("tracing_max_latency", 0644, d_tracer, \
+- &tr->max_latency, &tracing_max_lat_fops)
++ trace_create_file("tracing_max_latency", TRACE_MODE_WRITE, \
++ d_tracer, &tr->max_latency, &tracing_max_lat_fops)
+
+ #else
+ #define trace_create_maxlat_file(tr, d_tracer) do { } while (0)
+@@ -3835,6 +3836,18 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
+ iter->fmt[i] = '\0';
+ trace_seq_vprintf(&iter->seq, iter->fmt, ap);
+
++ /*
++ * If iter->seq is full, the above call no longer guarantees
++ * that ap is in sync with fmt processing, and further calls
++ * to va_arg() can return wrong positional arguments.
++ *
++ * Ensure that ap is no longer used in this case.
++ */
++ if (iter->seq.full) {
++ p = "";
++ break;
++ }
++
+ if (star)
+ len = va_arg(ap, int);
+
+@@ -6077,7 +6090,7 @@ trace_insert_eval_map_file(struct module *mod, struct trace_eval_map **start,
+
+ static void trace_create_eval_file(struct dentry *d_tracer)
+ {
+- trace_create_file("eval_map", 0444, d_tracer,
++ trace_create_file("eval_map", TRACE_MODE_READ, d_tracer,
+ NULL, &tracing_eval_map_fops);
+ }
+
+@@ -8590,27 +8603,27 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
+ }
+
+ /* per cpu trace_pipe */
+- trace_create_cpu_file("trace_pipe", 0444, d_cpu,
++ trace_create_cpu_file("trace_pipe", TRACE_MODE_READ, d_cpu,
+ tr, cpu, &tracing_pipe_fops);
+
+ /* per cpu trace */
+- trace_create_cpu_file("trace", 0644, d_cpu,
++ trace_create_cpu_file("trace", TRACE_MODE_WRITE, d_cpu,
+ tr, cpu, &tracing_fops);
+
+- trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
++ trace_create_cpu_file("trace_pipe_raw", TRACE_MODE_READ, d_cpu,
+ tr, cpu, &tracing_buffers_fops);
+
+- trace_create_cpu_file("stats", 0444, d_cpu,
++ trace_create_cpu_file("stats", TRACE_MODE_READ, d_cpu,
+ tr, cpu, &tracing_stats_fops);
+
+- trace_create_cpu_file("buffer_size_kb", 0444, d_cpu,
++ trace_create_cpu_file("buffer_size_kb", TRACE_MODE_READ, d_cpu,
+ tr, cpu, &tracing_entries_fops);
+
+ #ifdef CONFIG_TRACER_SNAPSHOT
+- trace_create_cpu_file("snapshot", 0644, d_cpu,
++ trace_create_cpu_file("snapshot", TRACE_MODE_WRITE, d_cpu,
+ tr, cpu, &snapshot_fops);
+
+- trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
++ trace_create_cpu_file("snapshot_raw", TRACE_MODE_READ, d_cpu,
+ tr, cpu, &snapshot_raw_fops);
+ #endif
+ }
+@@ -8816,8 +8829,8 @@ create_trace_option_file(struct trace_array *tr,
+ topt->opt = opt;
+ topt->tr = tr;
+
+- topt->entry = trace_create_file(opt->name, 0644, t_options, topt,
+- &trace_options_fops);
++ topt->entry = trace_create_file(opt->name, TRACE_MODE_WRITE,
++ t_options, topt, &trace_options_fops);
+
+ }
+
+@@ -8892,7 +8905,7 @@ create_trace_option_core_file(struct trace_array *tr,
+ if (!t_options)
+ return NULL;
+
+- return trace_create_file(option, 0644, t_options,
++ return trace_create_file(option, TRACE_MODE_WRITE, t_options,
+ (void *)&tr->trace_flags_index[index],
+ &trace_options_core_fops);
+ }
+@@ -9417,28 +9430,28 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
+ struct trace_event_file *file;
+ int cpu;
+
+- trace_create_file("available_tracers", 0444, d_tracer,
++ trace_create_file("available_tracers", TRACE_MODE_READ, d_tracer,
+ tr, &show_traces_fops);
+
+- trace_create_file("current_tracer", 0644, d_tracer,
++ trace_create_file("current_tracer", TRACE_MODE_WRITE, d_tracer,
+ tr, &set_tracer_fops);
+
+- trace_create_file("tracing_cpumask", 0644, d_tracer,
++ trace_create_file("tracing_cpumask", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_cpumask_fops);
+
+- trace_create_file("trace_options", 0644, d_tracer,
++ trace_create_file("trace_options", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_iter_fops);
+
+- trace_create_file("trace", 0644, d_tracer,
++ trace_create_file("trace", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_fops);
+
+- trace_create_file("trace_pipe", 0444, d_tracer,
++ trace_create_file("trace_pipe", TRACE_MODE_READ, d_tracer,
+ tr, &tracing_pipe_fops);
+
+- trace_create_file("buffer_size_kb", 0644, d_tracer,
++ trace_create_file("buffer_size_kb", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_entries_fops);
+
+- trace_create_file("buffer_total_size_kb", 0444, d_tracer,
++ trace_create_file("buffer_total_size_kb", TRACE_MODE_READ, d_tracer,
+ tr, &tracing_total_entries_fops);
+
+ trace_create_file("free_buffer", 0200, d_tracer,
+@@ -9449,25 +9462,25 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
+
+ file = __find_event_file(tr, "ftrace", "print");
+ if (file && file->dir)
+- trace_create_file("trigger", 0644, file->dir, file,
+- &event_trigger_fops);
++ trace_create_file("trigger", TRACE_MODE_WRITE, file->dir,
++ file, &event_trigger_fops);
+ tr->trace_marker_file = file;
+
+ trace_create_file("trace_marker_raw", 0220, d_tracer,
+ tr, &tracing_mark_raw_fops);
+
+- trace_create_file("trace_clock", 0644, d_tracer, tr,
++ trace_create_file("trace_clock", TRACE_MODE_WRITE, d_tracer, tr,
+ &trace_clock_fops);
+
+- trace_create_file("tracing_on", 0644, d_tracer,
++ trace_create_file("tracing_on", TRACE_MODE_WRITE, d_tracer,
+ tr, &rb_simple_fops);
+
+- trace_create_file("timestamp_mode", 0444, d_tracer, tr,
++ trace_create_file("timestamp_mode", TRACE_MODE_READ, d_tracer, tr,
+ &trace_time_stamp_mode_fops);
+
+ tr->buffer_percent = 50;
+
+- trace_create_file("buffer_percent", 0444, d_tracer,
++ trace_create_file("buffer_percent", TRACE_MODE_READ, d_tracer,
+ tr, &buffer_percent_fops);
+
+ create_trace_options_dir(tr);
+@@ -9478,11 +9491,11 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
+ MEM_FAIL(1, "Could not allocate function filter files");
+
+ #ifdef CONFIG_TRACER_SNAPSHOT
+- trace_create_file("snapshot", 0644, d_tracer,
++ trace_create_file("snapshot", TRACE_MODE_WRITE, d_tracer,
+ tr, &snapshot_fops);
+ #endif
+
+- trace_create_file("error_log", 0644, d_tracer,
++ trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_err_log_fops);
+
+ for_each_tracing_cpu(cpu)
+@@ -9675,19 +9688,19 @@ static __init int tracer_init_tracefs(void)
+ init_tracer_tracefs(&global_trace, NULL);
+ ftrace_init_tracefs_toplevel(&global_trace, NULL);
+
+- trace_create_file("tracing_thresh", 0644, NULL,
++ trace_create_file("tracing_thresh", TRACE_MODE_WRITE, NULL,
+ &global_trace, &tracing_thresh_fops);
+
+- trace_create_file("README", 0444, NULL,
++ trace_create_file("README", TRACE_MODE_READ, NULL,
+ NULL, &tracing_readme_fops);
+
+- trace_create_file("saved_cmdlines", 0444, NULL,
++ trace_create_file("saved_cmdlines", TRACE_MODE_READ, NULL,
+ NULL, &tracing_saved_cmdlines_fops);
+
+- trace_create_file("saved_cmdlines_size", 0644, NULL,
++ trace_create_file("saved_cmdlines_size", TRACE_MODE_WRITE, NULL,
+ NULL, &tracing_saved_cmdlines_size_fops);
+
+- trace_create_file("saved_tgids", 0444, NULL,
++ trace_create_file("saved_tgids", TRACE_MODE_READ, NULL,
+ NULL, &tracing_saved_tgids_fops);
+
+ trace_eval_init();
+@@ -9699,7 +9712,7 @@ static __init int tracer_init_tracefs(void)
+ #endif
+
+ #ifdef CONFIG_DYNAMIC_FTRACE
+- trace_create_file("dyn_ftrace_total_info", 0444, NULL,
++ trace_create_file("dyn_ftrace_total_info", TRACE_MODE_READ, NULL,
+ NULL, &tracing_dyn_info_fops);
+ #endif
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index b7c0f8e160fb4..421374c304fc0 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -27,6 +27,9 @@
+ #include <asm/syscall.h> /* some archs define it here */
+ #endif
+
++#define TRACE_MODE_WRITE 0640
++#define TRACE_MODE_READ 0440
++
+ enum trace_type {
+ __TRACE_FIRST_TYPE = 0,
+
+@@ -1357,14 +1360,26 @@ __event_trigger_test_discard(struct trace_event_file *file,
+ if (eflags & EVENT_FILE_FL_TRIGGER_COND)
+ *tt = event_triggers_call(file, buffer, entry, event);
+
+- if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags) ||
+- (unlikely(file->flags & EVENT_FILE_FL_FILTERED) &&
+- !filter_match_preds(file->filter, entry))) {
+- __trace_event_discard_commit(buffer, event);
+- return true;
+- }
++ if (likely(!(file->flags & (EVENT_FILE_FL_SOFT_DISABLED |
++ EVENT_FILE_FL_FILTERED |
++ EVENT_FILE_FL_PID_FILTER))))
++ return false;
++
++ if (file->flags & EVENT_FILE_FL_SOFT_DISABLED)
++ goto discard;
++
++ if (file->flags & EVENT_FILE_FL_FILTERED &&
++ !filter_match_preds(file->filter, entry))
++ goto discard;
++
++ if ((file->flags & EVENT_FILE_FL_PID_FILTER) &&
++ trace_event_ignore_this_pid(file))
++ goto discard;
+
+ return false;
++ discard:
++ __trace_event_discard_commit(buffer, event);
++ return true;
+ }
+
+ /**
+diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
+index 8d252f63cd784..0580287d7a0d1 100644
+--- a/kernel/trace/trace_boot.c
++++ b/kernel/trace/trace_boot.c
+@@ -430,6 +430,8 @@ trace_boot_init_histograms(struct trace_event_file *file,
+ /* All digit started node should be instances. */
+ if (trace_boot_compose_hist_cmd(node, buf, size) == 0) {
+ tmp = kstrdup(buf, GFP_KERNEL);
++ if (!tmp)
++ return;
+ if (trigger_process_regex(file, buf) < 0)
+ pr_err("Failed to apply hist trigger: %s\n", tmp);
+ kfree(tmp);
+@@ -439,6 +441,8 @@ trace_boot_init_histograms(struct trace_event_file *file,
+ if (xbc_node_find_subkey(hnode, "keys")) {
+ if (trace_boot_compose_hist_cmd(hnode, buf, size) == 0) {
+ tmp = kstrdup(buf, GFP_KERNEL);
++ if (!tmp)
++ return;
+ if (trigger_process_regex(file, buf) < 0)
+ pr_err("Failed to apply hist trigger: %s\n", tmp);
+ kfree(tmp);
+diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
+index 1110112e55bd7..e34e8182ee4b5 100644
+--- a/kernel/trace/trace_dynevent.c
++++ b/kernel/trace/trace_dynevent.c
+@@ -262,7 +262,7 @@ static __init int init_dynamic_event(void)
+ if (ret)
+ return 0;
+
+- entry = tracefs_create_file("dynamic_events", 0644, NULL,
++ entry = tracefs_create_file("dynamic_events", TRACE_MODE_WRITE, NULL,
+ NULL, &dynamic_events_ops);
+
+ /* Event list interface */
+diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
+index 6aed10e2f7ce0..fba8cb77a73af 100644
+--- a/kernel/trace/trace_event_perf.c
++++ b/kernel/trace/trace_event_perf.c
+@@ -441,13 +441,13 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
+ if (!rcu_is_watching())
+ return;
+
+- if ((unsigned long)ops->private != smp_processor_id())
+- return;
+-
+ bit = ftrace_test_recursion_trylock(ip, parent_ip);
+ if (bit < 0)
+ return;
+
++ if ((unsigned long)ops->private != smp_processor_id())
++ goto out;
++
+ event = container_of(ops, struct perf_event, ftrace_ops);
+
+ /*
+diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
+index 830b3b9940f4c..44d031ffe5112 100644
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -2312,7 +2312,8 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
+ /* the ftrace system is special, do not create enable or filter files */
+ if (strcmp(name, "ftrace") != 0) {
+
+- entry = tracefs_create_file("filter", 0644, dir->entry, dir,
++ entry = tracefs_create_file("filter", TRACE_MODE_WRITE,
++ dir->entry, dir,
+ &ftrace_subsystem_filter_fops);
+ if (!entry) {
+ kfree(system->filter);
+@@ -2320,7 +2321,7 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
+ pr_warn("Could not create tracefs '%s/filter' entry\n", name);
+ }
+
+- trace_create_file("enable", 0644, dir->entry, dir,
++ trace_create_file("enable", TRACE_MODE_WRITE, dir->entry, dir,
+ &ftrace_system_enable_fops);
+ }
+
+@@ -2402,12 +2403,12 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
+ }
+
+ if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
+- trace_create_file("enable", 0644, file->dir, file,
++ trace_create_file("enable", TRACE_MODE_WRITE, file->dir, file,
+ &ftrace_enable_fops);
+
+ #ifdef CONFIG_PERF_EVENTS
+ if (call->event.type && call->class->reg)
+- trace_create_file("id", 0444, file->dir,
++ trace_create_file("id", TRACE_MODE_READ, file->dir,
+ (void *)(long)call->event.type,
+ &ftrace_event_id_fops);
+ #endif
+@@ -2423,22 +2424,22 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
+ * triggers or filters.
+ */
+ if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) {
+- trace_create_file("filter", 0644, file->dir, file,
+- &ftrace_event_filter_fops);
++ trace_create_file("filter", TRACE_MODE_WRITE, file->dir,
++ file, &ftrace_event_filter_fops);
+
+- trace_create_file("trigger", 0644, file->dir, file,
+- &event_trigger_fops);
++ trace_create_file("trigger", TRACE_MODE_WRITE, file->dir,
++ file, &event_trigger_fops);
+ }
+
+ #ifdef CONFIG_HIST_TRIGGERS
+- trace_create_file("hist", 0444, file->dir, file,
++ trace_create_file("hist", TRACE_MODE_READ, file->dir, file,
+ &event_hist_fops);
+ #endif
+ #ifdef CONFIG_HIST_TRIGGERS_DEBUG
+- trace_create_file("hist_debug", 0444, file->dir, file,
++ trace_create_file("hist_debug", TRACE_MODE_READ, file->dir, file,
+ &event_hist_debug_fops);
+ #endif
+- trace_create_file("format", 0444, file->dir, call,
++ trace_create_file("format", TRACE_MODE_READ, file->dir, call,
+ &ftrace_event_format_fops);
+
+ #ifdef CONFIG_TRACE_EVENT_INJECT
+@@ -2677,12 +2678,22 @@ static struct trace_event_file *
+ trace_create_new_event(struct trace_event_call *call,
+ struct trace_array *tr)
+ {
++ struct trace_pid_list *no_pid_list;
++ struct trace_pid_list *pid_list;
+ struct trace_event_file *file;
+
+ file = kmem_cache_alloc(file_cachep, GFP_TRACE);
+ if (!file)
+ return NULL;
+
++ pid_list = rcu_dereference_protected(tr->filtered_pids,
++ lockdep_is_held(&event_mutex));
++ no_pid_list = rcu_dereference_protected(tr->filtered_no_pids,
++ lockdep_is_held(&event_mutex));
++
++ if (pid_list || no_pid_list)
++ file->flags |= EVENT_FILE_FL_PID_FILTER;
++
+ file->event_call = call;
+ file->tr = tr;
+ atomic_set(&file->sm_ref, 0);
+@@ -3433,7 +3444,7 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
+ struct dentry *d_events;
+ struct dentry *entry;
+
+- entry = tracefs_create_file("set_event", 0644, parent,
++ entry = tracefs_create_file("set_event", TRACE_MODE_WRITE, parent,
+ tr, &ftrace_set_event_fops);
+ if (!entry) {
+ pr_warn("Could not create tracefs 'set_event' entry\n");
+@@ -3446,7 +3457,7 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
+ return -ENOMEM;
+ }
+
+- entry = trace_create_file("enable", 0644, d_events,
++ entry = trace_create_file("enable", TRACE_MODE_WRITE, d_events,
+ tr, &ftrace_tr_enable_fops);
+ if (!entry) {
+ pr_warn("Could not create tracefs 'enable' entry\n");
+@@ -3455,24 +3466,25 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
+
+ /* There are not as crucial, just warn if they are not created */
+
+- entry = tracefs_create_file("set_event_pid", 0644, parent,
++ entry = tracefs_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
+ tr, &ftrace_set_event_pid_fops);
+ if (!entry)
+ pr_warn("Could not create tracefs 'set_event_pid' entry\n");
+
+- entry = tracefs_create_file("set_event_notrace_pid", 0644, parent,
+- tr, &ftrace_set_event_notrace_pid_fops);
++ entry = tracefs_create_file("set_event_notrace_pid",
++ TRACE_MODE_WRITE, parent, tr,
++ &ftrace_set_event_notrace_pid_fops);
+ if (!entry)
+ pr_warn("Could not create tracefs 'set_event_notrace_pid' entry\n");
+
+ /* ring buffer internal formats */
+- entry = trace_create_file("header_page", 0444, d_events,
++ entry = trace_create_file("header_page", TRACE_MODE_READ, d_events,
+ ring_buffer_print_page_header,
+ &ftrace_show_header_fops);
+ if (!entry)
+ pr_warn("Could not create tracefs 'header_page' entry\n");
+
+- entry = trace_create_file("header_event", 0444, d_events,
++ entry = trace_create_file("header_event", TRACE_MODE_READ, d_events,
+ ring_buffer_print_entry_header,
+ &ftrace_show_header_fops);
+ if (!entry)
+@@ -3689,8 +3701,8 @@ __init int event_trace_init(void)
+ if (!tr)
+ return -ENODEV;
+
+- entry = tracefs_create_file("available_events", 0444, NULL,
+- tr, &ftrace_avail_fops);
++ entry = tracefs_create_file("available_events", TRACE_MODE_READ,
++ NULL, tr, &ftrace_avail_fops);
+ if (!entry)
+ pr_warn("Could not create tracefs 'available_events' entry\n");
+
+diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
+index f01e442716e2f..12a735bd90a56 100644
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -1733,9 +1733,10 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
+ if (!hist_field->type)
+ goto free;
+
+- if (field->filter_type == FILTER_STATIC_STRING)
++ if (field->filter_type == FILTER_STATIC_STRING) {
+ hist_field->fn = hist_field_string;
+- else if (field->filter_type == FILTER_DYN_STRING)
++ hist_field->size = field->size;
++ } else if (field->filter_type == FILTER_DYN_STRING)
+ hist_field->fn = hist_field_dynstring;
+ else
+ hist_field->fn = hist_field_pstring;
+@@ -2690,8 +2691,10 @@ static inline void __update_field_vars(struct tracing_map_elt *elt,
+ if (val->flags & HIST_FIELD_FL_STRING) {
+ char *str = elt_data->field_var_str[j++];
+ char *val_str = (char *)(uintptr_t)var_val;
++ unsigned int size;
+
+- strscpy(str, val_str, STR_VAR_LEN_MAX);
++ size = min(val->size, STR_VAR_LEN_MAX);
++ strscpy(str, val_str, size);
+ var_val = (u64)(uintptr_t)str;
+ }
+ tracing_map_set_var(elt, var_idx, var_val);
+@@ -3416,7 +3419,7 @@ static int check_synth_field(struct synth_event *event,
+
+ if (strcmp(field->type, hist_field->type) != 0) {
+ if (field->size != hist_field->size ||
+- field->is_signed != hist_field->is_signed)
++ (!field->is_string && field->is_signed != hist_field->is_signed))
+ return -EINVAL;
+ }
+
+@@ -4578,6 +4581,7 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
+ if (hist_field->flags & HIST_FIELD_FL_STRING) {
+ unsigned int str_start, var_str_idx, idx;
+ char *str, *val_str;
++ unsigned int size;
+
+ str_start = hist_data->n_field_var_str +
+ hist_data->n_save_var_str;
+@@ -4586,7 +4590,9 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
+
+ str = elt_data->field_var_str[idx];
+ val_str = (char *)(uintptr_t)hist_val;
+- strscpy(str, val_str, STR_VAR_LEN_MAX);
++
++ size = min(hist_field->size, STR_VAR_LEN_MAX);
++ strscpy(str, val_str, size);
+
+ hist_val = (u64)(uintptr_t)str;
+ }
+diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
+index d54094b7a9d75..22db3ce95e74f 100644
+--- a/kernel/trace/trace_events_synth.c
++++ b/kernel/trace/trace_events_synth.c
+@@ -2227,8 +2227,8 @@ static __init int trace_events_synth_init(void)
+ if (err)
+ goto err;
+
+- entry = tracefs_create_file("synthetic_events", 0644, NULL,
+- NULL, &synth_events_fops);
++ entry = tracefs_create_file("synthetic_events", TRACE_MODE_WRITE,
++ NULL, NULL, &synth_events_fops);
+ if (!entry) {
+ err = -ENODEV;
+ goto err;
+diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
+index 0de6837722da5..6b5ff3ba4251f 100644
+--- a/kernel/trace/trace_functions_graph.c
++++ b/kernel/trace/trace_functions_graph.c
+@@ -1340,7 +1340,7 @@ static __init int init_graph_tracefs(void)
+ if (ret)
+ return 0;
+
+- trace_create_file("max_graph_depth", 0644, NULL,
++ trace_create_file("max_graph_depth", TRACE_MODE_WRITE, NULL,
+ NULL, &graph_depth_fops);
+
+ return 0;
+diff --git a/kernel/trace/trace_hwlat.c b/kernel/trace/trace_hwlat.c
+index 1b83d75eb103b..d0a730d99a331 100644
+--- a/kernel/trace/trace_hwlat.c
++++ b/kernel/trace/trace_hwlat.c
+@@ -782,21 +782,21 @@ static int init_tracefs(void)
+ if (!top_dir)
+ return -ENOMEM;
+
+- hwlat_sample_window = tracefs_create_file("window", 0640,
++ hwlat_sample_window = tracefs_create_file("window", TRACE_MODE_WRITE,
+ top_dir,
+ &hwlat_window,
+ &trace_min_max_fops);
+ if (!hwlat_sample_window)
+ goto err;
+
+- hwlat_sample_width = tracefs_create_file("width", 0644,
++ hwlat_sample_width = tracefs_create_file("width", TRACE_MODE_WRITE,
+ top_dir,
+ &hwlat_width,
+ &trace_min_max_fops);
+ if (!hwlat_sample_width)
+ goto err;
+
+- hwlat_thread_mode = trace_create_file("mode", 0644,
++ hwlat_thread_mode = trace_create_file("mode", TRACE_MODE_WRITE,
+ top_dir,
+ NULL,
+ &thread_mode_fops);
+diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
+index 3a64ba4bbad6f..92caef33b68c2 100644
+--- a/kernel/trace/trace_kprobe.c
++++ b/kernel/trace/trace_kprobe.c
+@@ -1925,16 +1925,16 @@ static __init int init_kprobe_trace(void)
+ if (ret)
+ return 0;
+
+- entry = tracefs_create_file("kprobe_events", 0644, NULL,
+- NULL, &kprobe_events_ops);
++ entry = tracefs_create_file("kprobe_events", TRACE_MODE_WRITE,
++ NULL, NULL, &kprobe_events_ops);
+
+ /* Event list interface */
+ if (!entry)
+ pr_warn("Could not create tracefs 'kprobe_events' entry\n");
+
+ /* Profile interface */
+- entry = tracefs_create_file("kprobe_profile", 0444, NULL,
+- NULL, &kprobe_profile_ops);
++ entry = tracefs_create_file("kprobe_profile", TRACE_MODE_READ,
++ NULL, NULL, &kprobe_profile_ops);
+
+ if (!entry)
+ pr_warn("Could not create tracefs 'kprobe_profile' entry\n");
+diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c
+index ce053619f289e..c4f14fb98aaac 100644
+--- a/kernel/trace/trace_osnoise.c
++++ b/kernel/trace/trace_osnoise.c
+@@ -1856,38 +1856,38 @@ static int init_tracefs(void)
+ if (!top_dir)
+ return 0;
+
+- tmp = tracefs_create_file("period_us", 0640, top_dir,
++ tmp = tracefs_create_file("period_us", TRACE_MODE_WRITE, top_dir,
+ &osnoise_period, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+
+- tmp = tracefs_create_file("runtime_us", 0644, top_dir,
++ tmp = tracefs_create_file("runtime_us", TRACE_MODE_WRITE, top_dir,
+ &osnoise_runtime, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+
+- tmp = tracefs_create_file("stop_tracing_us", 0640, top_dir,
++ tmp = tracefs_create_file("stop_tracing_us", TRACE_MODE_WRITE, top_dir,
+ &osnoise_stop_tracing_in, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+
+- tmp = tracefs_create_file("stop_tracing_total_us", 0640, top_dir,
++ tmp = tracefs_create_file("stop_tracing_total_us", TRACE_MODE_WRITE, top_dir,
+ &osnoise_stop_tracing_total, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+
+- tmp = trace_create_file("cpus", 0644, top_dir, NULL, &cpus_fops);
++ tmp = trace_create_file("cpus", TRACE_MODE_WRITE, top_dir, NULL, &cpus_fops);
+ if (!tmp)
+ goto err;
+ #ifdef CONFIG_TIMERLAT_TRACER
+ #ifdef CONFIG_STACKTRACE
+- tmp = tracefs_create_file("print_stack", 0640, top_dir,
++ tmp = tracefs_create_file("print_stack", TRACE_MODE_WRITE, top_dir,
+ &osnoise_print_stack, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+ #endif
+
+- tmp = tracefs_create_file("timerlat_period_us", 0640, top_dir,
++ tmp = tracefs_create_file("timerlat_period_us", TRACE_MODE_WRITE, top_dir,
+ &timerlat_period, &trace_min_max_fops);
+ if (!tmp)
+ goto err;
+diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
+index 4b320fe7df704..29f6e95439b67 100644
+--- a/kernel/trace/trace_printk.c
++++ b/kernel/trace/trace_printk.c
+@@ -384,7 +384,7 @@ static __init int init_trace_printk_function_export(void)
+ if (ret)
+ return 0;
+
+- trace_create_file("printk_formats", 0444, NULL,
++ trace_create_file("printk_formats", TRACE_MODE_READ, NULL,
+ NULL, &ftrace_formats_fops);
+
+ return 0;
+diff --git a/kernel/trace/trace_recursion_record.c b/kernel/trace/trace_recursion_record.c
+index b2edac1fe156e..4d4b78c8ca257 100644
+--- a/kernel/trace/trace_recursion_record.c
++++ b/kernel/trace/trace_recursion_record.c
+@@ -226,8 +226,8 @@ __init static int create_recursed_functions(void)
+ {
+ struct dentry *dentry;
+
+- dentry = trace_create_file("recursed_functions", 0644, NULL, NULL,
+- &recursed_functions_fops);
++ dentry = trace_create_file("recursed_functions", TRACE_MODE_WRITE,
++ NULL, NULL, &recursed_functions_fops);
+ if (!dentry)
+ pr_warn("WARNING: Failed to create recursed_functions\n");
+ return 0;
+diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
+index 63c2850420516..5a48dba912eae 100644
+--- a/kernel/trace/trace_stack.c
++++ b/kernel/trace/trace_stack.c
+@@ -559,14 +559,14 @@ static __init int stack_trace_init(void)
+ if (ret)
+ return 0;
+
+- trace_create_file("stack_max_size", 0644, NULL,
++ trace_create_file("stack_max_size", TRACE_MODE_WRITE, NULL,
+ &stack_trace_max_size, &stack_max_size_fops);
+
+- trace_create_file("stack_trace", 0444, NULL,
++ trace_create_file("stack_trace", TRACE_MODE_READ, NULL,
+ NULL, &stack_trace_fops);
+
+ #ifdef CONFIG_DYNAMIC_FTRACE
+- trace_create_file("stack_trace_filter", 0644, NULL,
++ trace_create_file("stack_trace_filter", TRACE_MODE_WRITE, NULL,
+ &trace_ops, &stack_trace_filter_fops);
+ #endif
+
+diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
+index 8d141c3825a94..bb247beec4470 100644
+--- a/kernel/trace/trace_stat.c
++++ b/kernel/trace/trace_stat.c
+@@ -297,9 +297,9 @@ static int init_stat_file(struct stat_session *session)
+ if (!stat_dir && (ret = tracing_stat_init()))
+ return ret;
+
+- session->file = tracefs_create_file(session->ts->name, 0644,
+- stat_dir,
+- session, &tracing_stat_fops);
++ session->file = tracefs_create_file(session->ts->name, TRACE_MODE_WRITE,
++ stat_dir, session,
++ &tracing_stat_fops);
+ if (!session->file)
+ return -ENOMEM;
+ return 0;
+diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
+index 225ce569bf8f8..f5f0039d31e5a 100644
+--- a/kernel/trace/trace_uprobe.c
++++ b/kernel/trace/trace_uprobe.c
+@@ -1313,6 +1313,7 @@ static int uprobe_perf_open(struct trace_event_call *call,
+ return 0;
+
+ list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
++ tu = container_of(pos, struct trace_uprobe, tp);
+ err = uprobe_apply(tu->inode, tu->offset, &tu->consumer, true);
+ if (err) {
+ uprobe_perf_close(call, event);
+@@ -1655,10 +1656,10 @@ static __init int init_uprobe_trace(void)
+ if (ret)
+ return 0;
+
+- trace_create_file("uprobe_events", 0644, NULL,
++ trace_create_file("uprobe_events", TRACE_MODE_WRITE, NULL,
+ NULL, &uprobe_events_ops);
+ /* Profile interface */
+- trace_create_file("uprobe_profile", 0444, NULL,
++ trace_create_file("uprobe_profile", TRACE_MODE_READ, NULL,
+ NULL, &uprobe_profile_ops);
+ return 0;
+ }
+diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c
+index d6bddb157ef20..9628b55718468 100644
+--- a/kernel/trace/tracing_map.c
++++ b/kernel/trace/tracing_map.c
+@@ -15,6 +15,7 @@
+ #include <linux/jhash.h>
+ #include <linux/slab.h>
+ #include <linux/sort.h>
++#include <linux/kmemleak.h>
+
+ #include "tracing_map.h"
+ #include "trace.h"
+@@ -307,6 +308,7 @@ static void tracing_map_array_free(struct tracing_map_array *a)
+ for (i = 0; i < a->n_pages; i++) {
+ if (!a->pages[i])
+ break;
++ kmemleak_free(a->pages[i]);
+ free_page((unsigned long)a->pages[i]);
+ }
+
+@@ -342,6 +344,7 @@ static struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
+ a->pages[i] = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!a->pages[i])
+ goto free;
++ kmemleak_alloc(a->pages[i], PAGE_SIZE, 1, GFP_KERNEL);
+ }
+ out:
+ return a;
+@@ -834,29 +837,35 @@ int tracing_map_init(struct tracing_map *map)
+ return err;
+ }
+
+-static int cmp_entries_dup(const struct tracing_map_sort_entry **a,
+- const struct tracing_map_sort_entry **b)
++static int cmp_entries_dup(const void *A, const void *B)
+ {
++ const struct tracing_map_sort_entry *a, *b;
+ int ret = 0;
+
+- if (memcmp((*a)->key, (*b)->key, (*a)->elt->map->key_size))
++ a = *(const struct tracing_map_sort_entry **)A;
++ b = *(const struct tracing_map_sort_entry **)B;
++
++ if (memcmp(a->key, b->key, a->elt->map->key_size))
+ ret = 1;
+
+ return ret;
+ }
+
+-static int cmp_entries_sum(const struct tracing_map_sort_entry **a,
+- const struct tracing_map_sort_entry **b)
++static int cmp_entries_sum(const void *A, const void *B)
+ {
+ const struct tracing_map_elt *elt_a, *elt_b;
++ const struct tracing_map_sort_entry *a, *b;
+ struct tracing_map_sort_key *sort_key;
+ struct tracing_map_field *field;
+ tracing_map_cmp_fn_t cmp_fn;
+ void *val_a, *val_b;
+ int ret = 0;
+
+- elt_a = (*a)->elt;
+- elt_b = (*b)->elt;
++ a = *(const struct tracing_map_sort_entry **)A;
++ b = *(const struct tracing_map_sort_entry **)B;
++
++ elt_a = a->elt;
++ elt_b = b->elt;
+
+ sort_key = &elt_a->map->sort_key;
+
+@@ -873,18 +882,21 @@ static int cmp_entries_sum(const struct tracing_map_sort_entry **a,
+ return ret;
+ }
+
+-static int cmp_entries_key(const struct tracing_map_sort_entry **a,
+- const struct tracing_map_sort_entry **b)
++static int cmp_entries_key(const void *A, const void *B)
+ {
+ const struct tracing_map_elt *elt_a, *elt_b;
++ const struct tracing_map_sort_entry *a, *b;
+ struct tracing_map_sort_key *sort_key;
+ struct tracing_map_field *field;
+ tracing_map_cmp_fn_t cmp_fn;
+ void *val_a, *val_b;
+ int ret = 0;
+
+- elt_a = (*a)->elt;
+- elt_b = (*b)->elt;
++ a = *(const struct tracing_map_sort_entry **)A;
++ b = *(const struct tracing_map_sort_entry **)B;
++
++ elt_a = a->elt;
++ elt_b = b->elt;
+
+ sort_key = &elt_a->map->sort_key;
+
+@@ -989,10 +1001,8 @@ static void sort_secondary(struct tracing_map *map,
+ struct tracing_map_sort_key *primary_key,
+ struct tracing_map_sort_key *secondary_key)
+ {
+- int (*primary_fn)(const struct tracing_map_sort_entry **,
+- const struct tracing_map_sort_entry **);
+- int (*secondary_fn)(const struct tracing_map_sort_entry **,
+- const struct tracing_map_sort_entry **);
++ int (*primary_fn)(const void *, const void *);
++ int (*secondary_fn)(const void *, const void *);
+ unsigned i, start = 0, n_sub = 1;
+
+ if (is_key(map, primary_key->field_idx))
+@@ -1061,8 +1071,7 @@ int tracing_map_sort_entries(struct tracing_map *map,
+ unsigned int n_sort_keys,
+ struct tracing_map_sort_entry ***sort_entries)
+ {
+- int (*cmp_entries_fn)(const struct tracing_map_sort_entry **,
+- const struct tracing_map_sort_entry **);
++ int (*cmp_entries_fn)(const void *, const void *);
+ struct tracing_map_sort_entry *sort_entry, **entries;
+ int i, n_entries, ret;
+
+diff --git a/kernel/workqueue.c b/kernel/workqueue.c
+index 1b3eb1e9531f4..76988f39ed5ac 100644
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -5384,9 +5384,6 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
+ int ret = -EINVAL;
+ cpumask_var_t saved_cpumask;
+
+- if (!zalloc_cpumask_var(&saved_cpumask, GFP_KERNEL))
+- return -ENOMEM;
+-
+ /*
+ * Not excluding isolated cpus on purpose.
+ * If the user wishes to include them, we allow that.
+@@ -5394,6 +5391,15 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
+ cpumask_and(cpumask, cpumask, cpu_possible_mask);
+ if (!cpumask_empty(cpumask)) {
+ apply_wqattrs_lock();
++ if (cpumask_equal(cpumask, wq_unbound_cpumask)) {
++ ret = 0;
++ goto out_unlock;
++ }
++
++ if (!zalloc_cpumask_var(&saved_cpumask, GFP_KERNEL)) {
++ ret = -ENOMEM;
++ goto out_unlock;
++ }
+
+ /* save the old wq_unbound_cpumask. */
+ cpumask_copy(saved_cpumask, wq_unbound_cpumask);
+@@ -5406,10 +5412,11 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
+ if (ret < 0)
+ cpumask_copy(wq_unbound_cpumask, saved_cpumask);
+
++ free_cpumask_var(saved_cpumask);
++out_unlock:
+ apply_wqattrs_unlock();
+ }
+
+- free_cpumask_var(saved_cpumask);
+ return ret;
+ }
+
+diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence
+index e641add339475..912f252a41fc6 100644
+--- a/lib/Kconfig.kfence
++++ b/lib/Kconfig.kfence
+@@ -25,17 +25,6 @@ menuconfig KFENCE
+
+ if KFENCE
+
+-config KFENCE_STATIC_KEYS
+- bool "Use static keys to set up allocations"
+- default y
+- depends on JUMP_LABEL # To ensure performance, require jump labels
+- help
+- Use static keys (static branches) to set up KFENCE allocations. Using
+- static keys is normally recommended, because it avoids a dynamic
+- branch in the allocator's fast path. However, with very low sample
+- intervals, or on systems that do not support jump labels, a dynamic
+- branch may still be an acceptable performance trade-off.
+-
+ config KFENCE_SAMPLE_INTERVAL
+ int "Default sample interval in milliseconds"
+ default 100
+@@ -56,6 +45,21 @@ config KFENCE_NUM_OBJECTS
+ pages are required; with one containing the object and two adjacent
+ ones used as guard pages.
+
++config KFENCE_STATIC_KEYS
++ bool "Use static keys to set up allocations" if EXPERT
++ depends on JUMP_LABEL
++ help
++ Use static keys (static branches) to set up KFENCE allocations. This
++ option is only recommended when using very large sample intervals, or
++ performance has carefully been evaluated with this option.
++
++ Using static keys comes with trade-offs that need to be carefully
++ evaluated given target workloads and system architectures. Notably,
++ enabling and disabling static keys invoke IPI broadcasts, the latency
++ and impact of which is much harder to predict than a dynamic branch.
++
++ Say N if you are unsure.
++
+ config KFENCE_STRESS_TEST_FAULTS
+ int "Stress testing of fault handling and error reporting" if EXPERT
+ default 0
+diff --git a/lib/crypto/sm4.c b/lib/crypto/sm4.c
+index 633b59fed9db8..284e62576d0c6 100644
+--- a/lib/crypto/sm4.c
++++ b/lib/crypto/sm4.c
+@@ -15,7 +15,7 @@ static const u32 fk[4] = {
+ 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
+ };
+
+-static const u32 __cacheline_aligned ck[32] = {
++static const u32 ____cacheline_aligned ck[32] = {
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
+ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
+ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
+@@ -26,7 +26,7 @@ static const u32 __cacheline_aligned ck[32] = {
+ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
+ };
+
+-static const u8 __cacheline_aligned sbox[256] = {
++static const u8 ____cacheline_aligned sbox[256] = {
+ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
+ 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
+ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
+diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c
+index a2f38e23004aa..f7a3dc13316a3 100644
+--- a/lib/decompress_unxz.c
++++ b/lib/decompress_unxz.c
+@@ -167,7 +167,7 @@
+ * memeq and memzero are not used much and any remotely sane implementation
+ * is fast enough. memcpy/memmove speed matters in multi-call mode, but
+ * the kernel image is decompressed in single-call mode, in which only
+- * memcpy speed can matter and only if there is a lot of uncompressible data
++ * memmove speed can matter and only if there is a lot of uncompressible data
+ * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the
+ * functions below should just be kept small; it's probably not worth
+ * optimizing for speed.
+diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
+index cb5abb42c16a2..84c16309cc637 100644
+--- a/lib/dynamic_debug.c
++++ b/lib/dynamic_debug.c
+@@ -761,6 +761,18 @@ static __init int ddebug_setup_query(char *str)
+
+ __setup("ddebug_query=", ddebug_setup_query);
+
++/*
++ * Install a noop handler to make dyndbg look like a normal kernel cli param.
++ * This avoids warnings about dyndbg being an unknown cli param when supplied
++ * by a user.
++ */
++static __init int dyndbg_setup(char *str)
++{
++ return 1;
++}
++
++__setup("dyndbg=", dyndbg_setup);
++
+ /*
+ * File_ops->write method for <debugfs>/dynamic_debug/control. Gathers the
+ * command text from userspace, parses and executes it.
+diff --git a/lib/iov_iter.c b/lib/iov_iter.c
+index 755c10c5138cd..60b5e6edfbaa7 100644
+--- a/lib/iov_iter.c
++++ b/lib/iov_iter.c
+@@ -1488,7 +1488,7 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
+ res = get_user_pages_fast(addr, n,
+ iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0,
+ pages);
+- if (unlikely(res < 0))
++ if (unlikely(res <= 0))
+ return res;
+ return (res == n ? len : res * PAGE_SIZE) - *start;
+ }
+@@ -1612,8 +1612,9 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
+ return -ENOMEM;
+ res = get_user_pages_fast(addr, n,
+ iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0, p);
+- if (unlikely(res < 0)) {
++ if (unlikely(res <= 0)) {
+ kvfree(p);
++ *pages = NULL;
+ return res;
+ }
+ *pages = p;
+diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
+index f9e89001b52eb..199ab201d5019 100644
+--- a/lib/nmi_backtrace.c
++++ b/lib/nmi_backtrace.c
+@@ -75,6 +75,12 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+ touch_softlockup_watchdog();
+ }
+
++ /*
++ * Force flush any remote buffers that might be stuck in IRQ context
++ * and therefore could not run their irq_work.
++ */
++ printk_trigger_flush();
++
+ clear_bit_unlock(0, &backtrace_flag);
+ put_cpu();
+ }
+diff --git a/lib/siphash.c b/lib/siphash.c
+index a90112ee72a1f..72b9068ab57bf 100644
+--- a/lib/siphash.c
++++ b/lib/siphash.c
+@@ -49,6 +49,7 @@
+ SIPROUND; \
+ return (v0 ^ v1) ^ (v2 ^ v3);
+
++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
+ {
+ const u8 *end = data + len - (len % sizeof(u64));
+@@ -80,8 +81,8 @@ u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
+ POSTAMBLE
+ }
+ EXPORT_SYMBOL(__siphash_aligned);
++#endif
+
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
+ {
+ const u8 *end = data + len - (len % sizeof(u64));
+@@ -113,7 +114,6 @@ u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
+ POSTAMBLE
+ }
+ EXPORT_SYMBOL(__siphash_unaligned);
+-#endif
+
+ /**
+ * siphash_1u64 - compute 64-bit siphash PRF value of a u64
+@@ -250,6 +250,7 @@ EXPORT_SYMBOL(siphash_3u32);
+ HSIPROUND; \
+ return (v0 ^ v1) ^ (v2 ^ v3);
+
++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+ {
+ const u8 *end = data + len - (len % sizeof(u64));
+@@ -280,8 +281,8 @@ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+ HPOSTAMBLE
+ }
+ EXPORT_SYMBOL(__hsiphash_aligned);
++#endif
+
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u32 __hsiphash_unaligned(const void *data, size_t len,
+ const hsiphash_key_t *key)
+ {
+@@ -313,7 +314,6 @@ u32 __hsiphash_unaligned(const void *data, size_t len,
+ HPOSTAMBLE
+ }
+ EXPORT_SYMBOL(__hsiphash_unaligned);
+-#endif
+
+ /**
+ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
+@@ -418,6 +418,7 @@ EXPORT_SYMBOL(hsiphash_4u32);
+ HSIPROUND; \
+ return v1 ^ v3;
+
++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+ {
+ const u8 *end = data + len - (len % sizeof(u32));
+@@ -438,8 +439,8 @@ u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key)
+ HPOSTAMBLE
+ }
+ EXPORT_SYMBOL(__hsiphash_aligned);
++#endif
+
+-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ u32 __hsiphash_unaligned(const void *data, size_t len,
+ const hsiphash_key_t *key)
+ {
+@@ -461,7 +462,6 @@ u32 __hsiphash_unaligned(const void *data, size_t len,
+ HPOSTAMBLE
+ }
+ EXPORT_SYMBOL(__hsiphash_unaligned);
+-#endif
+
+ /**
+ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
+diff --git a/lib/string_helpers.c b/lib/string_helpers.c
+index 3806a52ce697a..2ddc10bd9add6 100644
+--- a/lib/string_helpers.c
++++ b/lib/string_helpers.c
+@@ -696,3 +696,23 @@ void kfree_strarray(char **array, size_t n)
+ kfree(array);
+ }
+ EXPORT_SYMBOL_GPL(kfree_strarray);
++
++/**
++ * memcpy_and_pad - Copy one buffer to another with padding
++ * @dest: Where to copy to
++ * @dest_len: The destination buffer size
++ * @src: Where to copy from
++ * @count: The number of bytes to copy
++ * @pad: Character to use for padding if space is left in destination.
++ */
++void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
++ int pad)
++{
++ if (dest_len > count) {
++ memcpy(dest, src, count);
++ memset(dest + count, pad, dest_len - count);
++ } else {
++ memcpy(dest, src, dest_len);
++ }
++}
++EXPORT_SYMBOL(memcpy_and_pad);
+diff --git a/lib/test_bpf.c b/lib/test_bpf.c
+index 830a18ecffc88..68d125b409f20 100644
+--- a/lib/test_bpf.c
++++ b/lib/test_bpf.c
+@@ -8992,10 +8992,15 @@ static __init int test_bpf(void)
+ struct tail_call_test {
+ const char *descr;
+ struct bpf_insn insns[MAX_INSNS];
++ int flags;
+ int result;
+ int stack_depth;
+ };
+
++/* Flags that can be passed to tail call test cases */
++#define FLAG_NEED_STATE BIT(0)
++#define FLAG_RESULT_IN_STATE BIT(1)
++
+ /*
+ * Magic marker used in test snippets for tail calls below.
+ * BPF_LD/MOV to R2 and R2 with this immediate value is replaced
+@@ -9065,32 +9070,38 @@ static struct tail_call_test tail_call_tests[] = {
+ {
+ "Tail call error path, max count reached",
+ .insns = {
+- BPF_ALU64_IMM(BPF_ADD, R1, 1),
+- BPF_ALU64_REG(BPF_MOV, R0, R1),
++ BPF_LDX_MEM(BPF_W, R2, R1, 0),
++ BPF_ALU64_IMM(BPF_ADD, R2, 1),
++ BPF_STX_MEM(BPF_W, R1, R2, 0),
+ TAIL_CALL(0),
+ BPF_EXIT_INSN(),
+ },
+- .result = MAX_TAIL_CALL_CNT + 1,
++ .flags = FLAG_NEED_STATE | FLAG_RESULT_IN_STATE,
++ .result = (MAX_TAIL_CALL_CNT + 1 + 1) * MAX_TESTRUNS,
+ },
+ {
+ "Tail call error path, NULL target",
+ .insns = {
+- BPF_ALU64_IMM(BPF_MOV, R0, -1),
++ BPF_LDX_MEM(BPF_W, R2, R1, 0),
++ BPF_ALU64_IMM(BPF_ADD, R2, 1),
++ BPF_STX_MEM(BPF_W, R1, R2, 0),
+ TAIL_CALL(TAIL_CALL_NULL),
+- BPF_ALU64_IMM(BPF_MOV, R0, 1),
+ BPF_EXIT_INSN(),
+ },
+- .result = 1,
++ .flags = FLAG_NEED_STATE | FLAG_RESULT_IN_STATE,
++ .result = MAX_TESTRUNS,
+ },
+ {
+ "Tail call error path, index out of range",
+ .insns = {
+- BPF_ALU64_IMM(BPF_MOV, R0, -1),
++ BPF_LDX_MEM(BPF_W, R2, R1, 0),
++ BPF_ALU64_IMM(BPF_ADD, R2, 1),
++ BPF_STX_MEM(BPF_W, R1, R2, 0),
+ TAIL_CALL(TAIL_CALL_INVALID),
+- BPF_ALU64_IMM(BPF_MOV, R0, 1),
+ BPF_EXIT_INSN(),
+ },
+- .result = 1,
++ .flags = FLAG_NEED_STATE | FLAG_RESULT_IN_STATE,
++ .result = MAX_TESTRUNS,
+ },
+ };
+
+@@ -9196,6 +9207,8 @@ static __init int test_tail_calls(struct bpf_array *progs)
+ for (i = 0; i < ARRAY_SIZE(tail_call_tests); i++) {
+ struct tail_call_test *test = &tail_call_tests[i];
+ struct bpf_prog *fp = progs->ptrs[i];
++ int *data = NULL;
++ int state = 0;
+ u64 duration;
+ int ret;
+
+@@ -9212,7 +9225,11 @@ static __init int test_tail_calls(struct bpf_array *progs)
+ if (fp->jited)
+ jit_cnt++;
+
+- ret = __run_one(fp, NULL, MAX_TESTRUNS, &duration);
++ if (test->flags & FLAG_NEED_STATE)
++ data = &state;
++ ret = __run_one(fp, data, MAX_TESTRUNS, &duration);
++ if (test->flags & FLAG_RESULT_IN_STATE)
++ ret = state;
+ if (ret == test->result) {
+ pr_cont("%lld PASS", duration);
+ pass_cnt++;
+diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c
+index 7a6781e3f47b6..d548cf0e59fe6 100644
+--- a/lib/xz/xz_dec_lzma2.c
++++ b/lib/xz/xz_dec_lzma2.c
+@@ -387,7 +387,14 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
+
+ *left -= copy_size;
+
+- memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
++ /*
++ * If doing in-place decompression in single-call mode and the
++ * uncompressed size of the file is larger than the caller
++ * thought (i.e. it is invalid input!), the buffers below may
++ * overlap and cause undefined behavior with memcpy().
++ * With valid inputs memcpy() would be fine here.
++ */
++ memmove(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+ dict->pos += copy_size;
+
+ if (dict->full < dict->pos)
+@@ -397,7 +404,11 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+- memcpy(b->out + b->out_pos, b->in + b->in_pos,
++ /*
++ * Like above but for multi-call mode: use memmove()
++ * to avoid undefined behavior with invalid input.
++ */
++ memmove(b->out + b->out_pos, b->in + b->in_pos,
+ copy_size);
+ }
+
+@@ -421,6 +432,12 @@ static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
++ /*
++ * These buffers cannot overlap even if doing in-place
++ * decompression because in multi-call mode dict->buf
++ * has been allocated by us in this file; it's not
++ * provided by the caller like in single-call mode.
++ */
+ memcpy(b->out + b->out_pos, dict->buf + dict->start,
+ copy_size);
+ }
+diff --git a/lib/xz/xz_dec_stream.c b/lib/xz/xz_dec_stream.c
+index fea86deaaa01d..683570b93a8c4 100644
+--- a/lib/xz/xz_dec_stream.c
++++ b/lib/xz/xz_dec_stream.c
+@@ -402,12 +402,12 @@ static enum xz_ret dec_stream_header(struct xz_dec *s)
+ * we will accept other check types too, but then the check won't
+ * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
+ */
++ if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)
++ return XZ_OPTIONS_ERROR;
++
+ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+ #ifdef XZ_DEC_ANY_CHECK
+- if (s->check_type > XZ_CHECK_MAX)
+- return XZ_OPTIONS_ERROR;
+-
+ if (s->check_type > XZ_CHECK_CRC32)
+ return XZ_UNSUPPORTED_CHECK;
+ #else
+diff --git a/mm/Kconfig b/mm/Kconfig
+index d16ba9249bc53..c048dea7e3420 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -887,6 +887,9 @@ config MAPPING_DIRTY_HELPERS
+ config KMAP_LOCAL
+ bool
+
++config KMAP_LOCAL_NON_LINEAR_PTE_ARRAY
++ bool
++
+ # struct io_mapping based helper. Selected by drivers that need them
+ config IO_MAPPING
+ bool
+diff --git a/mm/backing-dev.c b/mm/backing-dev.c
+index 4a9d4e27d0d9b..02ff66f863587 100644
+--- a/mm/backing-dev.c
++++ b/mm/backing-dev.c
+@@ -947,6 +947,13 @@ void bdi_unregister(struct backing_dev_info *bdi)
+ wb_shutdown(&bdi->wb);
+ cgwb_bdi_unregister(bdi);
+
++ /*
++ * If this BDI's min ratio has been set, use bdi_set_min_ratio() to
++ * update the global bdi_min_ratio.
++ */
++ if (bdi->min_ratio)
++ bdi_set_min_ratio(bdi, 0);
++
+ if (bdi->dev) {
+ bdi_debug_unregister(bdi);
+ device_unregister(bdi->dev);
+diff --git a/mm/damon/core.c b/mm/damon/core.c
+index 30e9211f494a7..7a4912d6e65f2 100644
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -357,6 +357,15 @@ int damon_start(struct damon_ctx **ctxs, int nr_ctxs)
+ return err;
+ }
+
++static void kdamond_usleep(unsigned long usecs)
++{
++ /* See Documentation/timers/timers-howto.rst for the thresholds */
++ if (usecs > 20 * 1000)
++ schedule_timeout_idle(usecs_to_jiffies(usecs));
++ else
++ usleep_idle_range(usecs, usecs + 1);
++}
++
+ /*
+ * __damon_stop() - Stops monitoring of given context.
+ * @ctx: monitoring context
+@@ -370,8 +379,7 @@ static int __damon_stop(struct damon_ctx *ctx)
+ ctx->kdamond_stop = true;
+ mutex_unlock(&ctx->kdamond_lock);
+ while (damon_kdamond_running(ctx))
+- usleep_range(ctx->sample_interval,
+- ctx->sample_interval * 2);
++ kdamond_usleep(ctx->sample_interval);
+ return 0;
+ }
+ mutex_unlock(&ctx->kdamond_lock);
+@@ -670,7 +678,7 @@ static int kdamond_fn(void *data)
+ ctx->callback.after_sampling(ctx))
+ set_kdamond_stop(ctx);
+
+- usleep_range(ctx->sample_interval, ctx->sample_interval + 1);
++ kdamond_usleep(ctx->sample_interval);
+
+ if (ctx->primitive.check_accesses)
+ max_nr_accesses = ctx->primitive.check_accesses(ctx);
+diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c
+index faee070977d80..f94d19a690dfa 100644
+--- a/mm/damon/dbgfs.c
++++ b/mm/damon/dbgfs.c
+@@ -32,7 +32,7 @@ static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos)
+ if (*ppos)
+ return ERR_PTR(-EINVAL);
+
+- kbuf = kmalloc(count + 1, GFP_KERNEL);
++ kbuf = kmalloc(count + 1, GFP_KERNEL | __GFP_NOWARN);
+ if (!kbuf)
+ return ERR_PTR(-ENOMEM);
+
+@@ -247,7 +247,7 @@ static ssize_t dbgfs_kdamond_pid_read(struct file *file,
+ char *kbuf;
+ ssize_t len;
+
+- kbuf = kmalloc(count, GFP_KERNEL);
++ kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
+ if (!kbuf)
+ return -ENOMEM;
+
+@@ -538,12 +538,14 @@ static ssize_t dbgfs_monitor_on_write(struct file *file,
+ return -EINVAL;
+ }
+
++ mutex_lock(&damon_dbgfs_lock);
+ if (!strncmp(kbuf, "on", count))
+ err = damon_start(dbgfs_ctxs, dbgfs_nr_ctxs);
+ else if (!strncmp(kbuf, "off", count))
+ err = damon_stop(dbgfs_ctxs, dbgfs_nr_ctxs);
+ else
+ err = -EINVAL;
++ mutex_unlock(&damon_dbgfs_lock);
+
+ if (err)
+ ret = err;
+@@ -596,15 +598,16 @@ static int __init __damon_dbgfs_init(void)
+
+ static int __init damon_dbgfs_init(void)
+ {
+- int rc;
++ int rc = -ENOMEM;
+
++ mutex_lock(&damon_dbgfs_lock);
+ dbgfs_ctxs = kmalloc(sizeof(*dbgfs_ctxs), GFP_KERNEL);
+ if (!dbgfs_ctxs)
+- return -ENOMEM;
++ goto out;
+ dbgfs_ctxs[0] = dbgfs_new_ctx();
+ if (!dbgfs_ctxs[0]) {
+ kfree(dbgfs_ctxs);
+- return -ENOMEM;
++ goto out;
+ }
+ dbgfs_nr_ctxs = 1;
+
+@@ -615,6 +618,8 @@ static int __init damon_dbgfs_init(void)
+ pr_err("%s: dbgfs init failed\n", __func__);
+ }
+
++out:
++ mutex_unlock(&damon_dbgfs_lock);
+ return rc;
+ }
+
+diff --git a/mm/filemap.c b/mm/filemap.c
+index dae481293b5d9..82a17c35eb96b 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -2093,7 +2093,6 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t start,
+ if (!xa_is_value(page)) {
+ if (page->index < start)
+ goto put;
+- VM_BUG_ON_PAGE(page->index != xas.xa_index, page);
+ if (page->index + thp_nr_pages(page) - 1 > end)
+ goto put;
+ if (!trylock_page(page))
+diff --git a/mm/highmem.c b/mm/highmem.c
+index 4212ad0e4a195..1f0c8a52fd807 100644
+--- a/mm/highmem.c
++++ b/mm/highmem.c
+@@ -504,16 +504,22 @@ static inline int kmap_local_calc_idx(int idx)
+
+ static pte_t *__kmap_pte;
+
+-static pte_t *kmap_get_pte(void)
++static pte_t *kmap_get_pte(unsigned long vaddr, int idx)
+ {
++ if (IS_ENABLED(CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY))
++ /*
++ * Set by the arch if __kmap_pte[-idx] does not produce
++ * the correct entry.
++ */
++ return virt_to_kpte(vaddr);
+ if (!__kmap_pte)
+ __kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
+- return __kmap_pte;
++ return &__kmap_pte[-idx];
+ }
+
+ void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot)
+ {
+- pte_t pteval, *kmap_pte = kmap_get_pte();
++ pte_t pteval, *kmap_pte;
+ unsigned long vaddr;
+ int idx;
+
+@@ -525,9 +531,10 @@ void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot)
+ preempt_disable();
+ idx = arch_kmap_local_map_idx(kmap_local_idx_push(), pfn);
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- BUG_ON(!pte_none(*(kmap_pte - idx)));
++ kmap_pte = kmap_get_pte(vaddr, idx);
++ BUG_ON(!pte_none(*kmap_pte));
+ pteval = pfn_pte(pfn, prot);
+- arch_kmap_local_set_pte(&init_mm, vaddr, kmap_pte - idx, pteval);
++ arch_kmap_local_set_pte(&init_mm, vaddr, kmap_pte, pteval);
+ arch_kmap_local_post_map(vaddr, pteval);
+ current->kmap_ctrl.pteval[kmap_local_idx()] = pteval;
+ preempt_enable();
+@@ -560,7 +567,7 @@ EXPORT_SYMBOL(__kmap_local_page_prot);
+ void kunmap_local_indexed(void *vaddr)
+ {
+ unsigned long addr = (unsigned long) vaddr & PAGE_MASK;
+- pte_t *kmap_pte = kmap_get_pte();
++ pte_t *kmap_pte;
+ int idx;
+
+ if (addr < __fix_to_virt(FIX_KMAP_END) ||
+@@ -585,8 +592,9 @@ void kunmap_local_indexed(void *vaddr)
+ idx = arch_kmap_local_unmap_idx(kmap_local_idx(), addr);
+ WARN_ON_ONCE(addr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
++ kmap_pte = kmap_get_pte(addr, idx);
+ arch_kmap_local_pre_unmap(addr);
+- pte_clear(&init_mm, addr, kmap_pte - idx);
++ pte_clear(&init_mm, addr, kmap_pte);
+ arch_kmap_local_post_unmap(addr);
+ current->kmap_ctrl.pteval[kmap_local_idx()] = __pte(0);
+ kmap_local_idx_pop();
+@@ -608,7 +616,7 @@ EXPORT_SYMBOL(kunmap_local_indexed);
+ void __kmap_local_sched_out(void)
+ {
+ struct task_struct *tsk = current;
+- pte_t *kmap_pte = kmap_get_pte();
++ pte_t *kmap_pte;
+ int i;
+
+ /* Clear kmaps */
+@@ -635,8 +643,9 @@ void __kmap_local_sched_out(void)
+ idx = arch_kmap_local_map_idx(i, pte_pfn(pteval));
+
+ addr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
++ kmap_pte = kmap_get_pte(addr, idx);
+ arch_kmap_local_pre_unmap(addr);
+- pte_clear(&init_mm, addr, kmap_pte - idx);
++ pte_clear(&init_mm, addr, kmap_pte);
+ arch_kmap_local_post_unmap(addr);
+ }
+ }
+@@ -644,7 +653,7 @@ void __kmap_local_sched_out(void)
+ void __kmap_local_sched_in(void)
+ {
+ struct task_struct *tsk = current;
+- pte_t *kmap_pte = kmap_get_pte();
++ pte_t *kmap_pte;
+ int i;
+
+ /* Restore kmaps */
+@@ -664,7 +673,8 @@ void __kmap_local_sched_in(void)
+ /* See comment in __kmap_local_sched_out() */
+ idx = arch_kmap_local_map_idx(i, pte_pfn(pteval));
+ addr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- set_pte_at(&init_mm, addr, kmap_pte - idx, pteval);
++ kmap_pte = kmap_get_pte(addr, idx);
++ set_pte_at(&init_mm, addr, kmap_pte, pteval);
+ arch_kmap_local_post_map(addr, pteval);
+ }
+ }
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index 95dc7b83381f9..f5ed98843557b 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -4439,6 +4439,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ struct hstate *h = hstate_vma(vma);
+ unsigned long sz = huge_page_size(h);
+ struct mmu_notifier_range range;
++ bool force_flush = false;
+
+ WARN_ON(!is_vm_hugetlb_page(vma));
+ BUG_ON(start & ~huge_page_mask(h));
+@@ -4467,10 +4468,8 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ ptl = huge_pte_lock(h, mm, ptep);
+ if (huge_pmd_unshare(mm, vma, &address, ptep)) {
+ spin_unlock(ptl);
+- /*
+- * We just unmapped a page of PMDs by clearing a PUD.
+- * The caller's TLB flush range should cover this area.
+- */
++ tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
++ force_flush = true;
+ continue;
+ }
+
+@@ -4527,6 +4526,22 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ }
+ mmu_notifier_invalidate_range_end(&range);
+ tlb_end_vma(tlb, vma);
++
++ /*
++ * If we unshared PMDs, the TLB flush was not recorded in mmu_gather. We
++ * could defer the flush until now, since by holding i_mmap_rwsem we
++ * guaranteed that the last refernece would not be dropped. But we must
++ * do the flushing before we return, as otherwise i_mmap_rwsem will be
++ * dropped and the last reference to the shared PMDs page might be
++ * dropped as well.
++ *
++ * In theory we could defer the freeing of the PMD pages as well, but
++ * huge_pmd_unshare() relies on the exact page_count for the PMD page to
++ * detect sharing, so we cannot defer the release of the page either.
++ * Instead, do flush now.
++ */
++ if (force_flush)
++ tlb_flush_mmu_tlbonly(tlb);
+ }
+
+ void __unmap_hugepage_range_final(struct mmu_gather *tlb,
+@@ -5236,13 +5251,14 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
+ int ret = -ENOMEM;
+ struct page *page;
+ int writable;
+- bool new_pagecache_page = false;
++ bool page_in_pagecache = false;
+
+ if (is_continue) {
+ ret = -EFAULT;
+ page = find_lock_page(mapping, idx);
+ if (!page)
+ goto out;
++ page_in_pagecache = true;
+ } else if (!*pagep) {
+ /* If a page already exists, then it's UFFDIO_COPY for
+ * a non-missing case. Return -EEXIST.
+@@ -5330,7 +5346,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
+ ret = huge_add_to_page_cache(page, mapping, idx);
+ if (ret)
+ goto out_release_nounlock;
+- new_pagecache_page = true;
++ page_in_pagecache = true;
+ }
+
+ ptl = huge_pte_lockptr(h, dst_mm, dst_pte);
+@@ -5394,7 +5410,7 @@ out_release_unlock:
+ if (vm_shared || is_continue)
+ unlock_page(page);
+ out_release_nounlock:
+- if (!new_pagecache_page)
++ if (!page_in_pagecache)
+ restore_reserve_on_error(h, dst_vma, dst_addr, page);
+ put_page(page);
+ goto out;
+diff --git a/mm/kfence/core.c b/mm/kfence/core.c
+index 7a97db8bc8e75..4b69236aea722 100644
+--- a/mm/kfence/core.c
++++ b/mm/kfence/core.c
+@@ -97,10 +97,11 @@ struct kfence_metadata kfence_metadata[CONFIG_KFENCE_NUM_OBJECTS];
+ static struct list_head kfence_freelist = LIST_HEAD_INIT(kfence_freelist);
+ static DEFINE_RAW_SPINLOCK(kfence_freelist_lock); /* Lock protecting freelist. */
+
+-#ifdef CONFIG_KFENCE_STATIC_KEYS
+-/* The static key to set up a KFENCE allocation. */
++/*
++ * The static key to set up a KFENCE allocation; or if static keys are not used
++ * to gate allocations, to avoid a load and compare if KFENCE is disabled.
++ */
+ DEFINE_STATIC_KEY_FALSE(kfence_allocation_key);
+-#endif
+
+ /* Gates the allocation, ensuring only one succeeds in a given period. */
+ atomic_t kfence_allocation_gate = ATOMIC_INIT(1);
+@@ -668,6 +669,8 @@ void __init kfence_init(void)
+ return;
+ }
+
++ if (!IS_ENABLED(CONFIG_KFENCE_STATIC_KEYS))
++ static_branch_enable(&kfence_allocation_key);
+ WRITE_ONCE(kfence_enabled, true);
+ queue_delayed_work(system_unbound_wq, &kfence_timer, 0);
+ pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE,
+@@ -752,12 +755,7 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags)
+ (s->flags & (SLAB_CACHE_DMA | SLAB_CACHE_DMA32)))
+ return NULL;
+
+- /*
+- * allocation_gate only needs to become non-zero, so it doesn't make
+- * sense to continue writing to it and pay the associated contention
+- * cost, in case we have a large number of concurrent allocations.
+- */
+- if (atomic_read(&kfence_allocation_gate) || atomic_inc_return(&kfence_allocation_gate) > 1)
++ if (atomic_inc_return(&kfence_allocation_gate) > 1)
+ return NULL;
+ #ifdef CONFIG_KFENCE_STATIC_KEYS
+ /*
+diff --git a/mm/memcontrol.c b/mm/memcontrol.c
+index 6da5020a8656d..87e41c3cac101 100644
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -239,7 +239,7 @@ enum res_type {
+ iter != NULL; \
+ iter = mem_cgroup_iter(NULL, iter, NULL))
+
+-static inline bool should_force_charge(void)
++static inline bool task_is_dying(void)
+ {
+ return tsk_is_oom_victim(current) || fatal_signal_pending(current) ||
+ (current->flags & PF_EXITING);
+@@ -1575,7 +1575,7 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
+ * A few threads which were not waiting at mutex_lock_killable() can
+ * fail to bail out. Therefore, check again after holding oom_lock.
+ */
+- ret = should_force_charge() || out_of_memory(&oc);
++ ret = task_is_dying() || out_of_memory(&oc);
+
+ unlock:
+ mutex_unlock(&oom_lock);
+@@ -2530,6 +2530,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
+ struct page_counter *counter;
+ enum oom_status oom_status;
+ unsigned long nr_reclaimed;
++ bool passed_oom = false;
+ bool may_swap = true;
+ bool drained = false;
+ unsigned long pflags;
+@@ -2564,15 +2565,6 @@ retry:
+ if (gfp_mask & __GFP_ATOMIC)
+ goto force;
+
+- /*
+- * Unlike in global OOM situations, memcg is not in a physical
+- * memory shortage. Allow dying and OOM-killed tasks to
+- * bypass the last charges so that they can exit quickly and
+- * free their memory.
+- */
+- if (unlikely(should_force_charge()))
+- goto force;
+-
+ /*
+ * Prevent unbounded recursion when reclaim operations need to
+ * allocate memory. This might exceed the limits temporarily,
+@@ -2630,8 +2622,9 @@ retry:
+ if (gfp_mask & __GFP_RETRY_MAYFAIL)
+ goto nomem;
+
+- if (fatal_signal_pending(current))
+- goto force;
++ /* Avoid endless loop for tasks bypassed by the oom killer */
++ if (passed_oom && task_is_dying())
++ goto nomem;
+
+ /*
+ * keep retrying as long as the memcg oom killer is able to make
+@@ -2640,14 +2633,10 @@ retry:
+ */
+ oom_status = mem_cgroup_oom(mem_over_limit, gfp_mask,
+ get_order(nr_pages * PAGE_SIZE));
+- switch (oom_status) {
+- case OOM_SUCCESS:
++ if (oom_status == OOM_SUCCESS) {
++ passed_oom = true;
+ nr_retries = MAX_RECLAIM_RETRIES;
+ goto retry;
+- case OOM_FAILED:
+- goto force;
+- default:
+- goto nomem;
+ }
+ nomem:
+ if (!(gfp_mask & __GFP_NOFAIL))
+diff --git a/mm/oom_kill.c b/mm/oom_kill.c
+index 989f35a2bbb1d..bfa9e348c3a3a 100644
+--- a/mm/oom_kill.c
++++ b/mm/oom_kill.c
+@@ -1120,27 +1120,24 @@ bool out_of_memory(struct oom_control *oc)
+ }
+
+ /*
+- * The pagefault handler calls here because it is out of memory, so kill a
+- * memory-hogging task. If oom_lock is held by somebody else, a parallel oom
+- * killing is already in progress so do nothing.
++ * The pagefault handler calls here because some allocation has failed. We have
++ * to take care of the memcg OOM here because this is the only safe context without
++ * any locks held but let the oom killer triggered from the allocation context care
++ * about the global OOM.
+ */
+ void pagefault_out_of_memory(void)
+ {
+- struct oom_control oc = {
+- .zonelist = NULL,
+- .nodemask = NULL,
+- .memcg = NULL,
+- .gfp_mask = 0,
+- .order = 0,
+- };
++ static DEFINE_RATELIMIT_STATE(pfoom_rs, DEFAULT_RATELIMIT_INTERVAL,
++ DEFAULT_RATELIMIT_BURST);
+
+ if (mem_cgroup_oom_synchronize(true))
+ return;
+
+- if (!mutex_trylock(&oom_lock))
++ if (fatal_signal_pending(current))
+ return;
+- out_of_memory(&oc);
+- mutex_unlock(&oom_lock);
++
++ if (__ratelimit(&pfoom_rs))
++ pr_warn("Huh VM_FAULT_OOM leaked out to the #PF handler. Retrying PF\n");
+ }
+
+ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
+diff --git a/mm/slab.h b/mm/slab.h
+index 58c01a34e5b86..56ad7eea3ddfb 100644
+--- a/mm/slab.h
++++ b/mm/slab.h
+@@ -147,7 +147,7 @@ static inline slab_flags_t kmem_cache_flags(unsigned int object_size,
+ #define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \
+ SLAB_TEMPORARY | SLAB_ACCOUNT)
+ #else
+-#define SLAB_CACHE_FLAGS (0)
++#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE)
+ #endif
+
+ /* Common flags available with current configuration */
+diff --git a/mm/slub.c b/mm/slub.c
+index d8f77346376d8..ca6ba6bdf27b1 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -5072,6 +5072,7 @@ struct loc_track {
+ unsigned long max;
+ unsigned long count;
+ struct location *loc;
++ loff_t idx;
+ };
+
+ static struct dentry *slab_debugfs_root;
+@@ -6035,11 +6036,11 @@ __initcall(slab_sysfs_init);
+ #if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
+ static int slab_debugfs_show(struct seq_file *seq, void *v)
+ {
+-
+- struct location *l;
+- unsigned int idx = *(unsigned int *)v;
+ struct loc_track *t = seq->private;
++ struct location *l;
++ unsigned long idx;
+
++ idx = (unsigned long) t->idx;
+ if (idx < t->count) {
+ l = &t->loc[idx];
+
+@@ -6088,16 +6089,18 @@ static void *slab_debugfs_next(struct seq_file *seq, void *v, loff_t *ppos)
+ {
+ struct loc_track *t = seq->private;
+
+- v = ppos;
+- ++*ppos;
++ t->idx = ++(*ppos);
+ if (*ppos <= t->count)
+- return v;
++ return ppos;
+
+ return NULL;
+ }
+
+ static void *slab_debugfs_start(struct seq_file *seq, loff_t *ppos)
+ {
++ struct loc_track *t = seq->private;
++
++ t->idx = *ppos;
+ return ppos;
+ }
+
+diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
+index 68e8831068f4b..b897ce3b399a1 100644
+--- a/mm/zsmalloc.c
++++ b/mm/zsmalloc.c
+@@ -1830,10 +1830,11 @@ static inline void zs_pool_dec_isolated(struct zs_pool *pool)
+ VM_BUG_ON(atomic_long_read(&pool->isolated_pages) <= 0);
+ atomic_long_dec(&pool->isolated_pages);
+ /*
+- * There's no possibility of racing, since wait_for_isolated_drain()
+- * checks the isolated count under &class->lock after enqueuing
+- * on migration_wait.
++ * Checking pool->destroying must happen after atomic_long_dec()
++ * for pool->isolated_pages above. Paired with the smp_mb() in
++ * zs_unregister_migration().
+ */
++ smp_mb__after_atomic();
+ if (atomic_long_read(&pool->isolated_pages) == 0 && pool->destroying)
+ wake_up_all(&pool->migration_wait);
+ }
+diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
+index 55275ef9a31a7..abaa5d96ded24 100644
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -123,9 +123,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
+ }
+
+ vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
+-
+- /* Get rid of the vlan's reference to real_dev */
+- dev_put(real_dev);
+ }
+
+ int vlan_check_real_dev(struct net_device *real_dev,
+@@ -187,9 +184,6 @@ int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack)
+ if (err)
+ goto out_unregister_netdev;
+
+- /* Account for reference in struct vlan_dev_priv */
+- dev_hold(real_dev);
+-
+ vlan_stacked_transfer_operstate(real_dev, dev, vlan);
+ linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
+
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index 0c21d1fec8522..8602885c8a8e0 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -615,6 +615,9 @@ static int vlan_dev_init(struct net_device *dev)
+ if (!vlan->vlan_pcpu_stats)
+ return -ENOMEM;
+
++ /* Get vlan's reference to real_dev */
++ dev_hold(real_dev);
++
+ return 0;
+ }
+
+@@ -843,6 +846,9 @@ static void vlan_dev_free(struct net_device *dev)
+
+ free_percpu(vlan->vlan_pcpu_stats);
+ vlan->vlan_pcpu_stats = NULL;
++
++ /* Get rid of the vlan's reference to real_dev */
++ dev_put(vlan->real_dev);
+ }
+
+ void vlan_setup(struct net_device *dev)
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 213f12ed76cd8..7973267ec8464 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -541,6 +541,8 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
+ kfree(ename);
+ } else {
+ err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode);
++ if (err)
++ goto out_err;
+ err = -ecode;
+
+ p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
+index c99d65ef13b1e..160c016a5dfb9 100644
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -1508,6 +1508,9 @@ static void l2cap_sock_close_cb(struct l2cap_chan *chan)
+ {
+ struct sock *sk = chan->data;
+
++ if (!sk)
++ return;
++
+ l2cap_sock_kill(sk);
+ }
+
+@@ -1516,6 +1519,9 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
+ struct sock *sk = chan->data;
+ struct sock *parent;
+
++ if (!sk)
++ return;
++
+ BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
+
+ /* This callback can be called both for server (BT_LISTEN)
+@@ -1707,8 +1713,10 @@ static void l2cap_sock_destruct(struct sock *sk)
+ {
+ BT_DBG("sk %p", sk);
+
+- if (l2cap_pi(sk)->chan)
++ if (l2cap_pi(sk)->chan) {
++ l2cap_pi(sk)->chan->data = NULL;
+ l2cap_chan_put(l2cap_pi(sk)->chan);
++ }
+
+ if (l2cap_pi(sk)->rx_busy_skb) {
+ kfree_skb(l2cap_pi(sk)->rx_busy_skb);
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 98a8815865128..6e047e178c0ab 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -133,6 +133,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
+ return NULL;
+
+ spin_lock_init(&conn->lock);
++ INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
+
+ hcon->sco_data = conn;
+ conn->hcon = hcon;
+@@ -187,20 +188,21 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
+ /* Kill socket */
+ sco_conn_lock(conn);
+ sk = conn->sk;
++ if (sk)
++ sock_hold(sk);
+ sco_conn_unlock(conn);
+
+ if (sk) {
+- sock_hold(sk);
+ lock_sock(sk);
+ sco_sock_clear_timer(sk);
+ sco_chan_del(sk, err);
+ release_sock(sk);
+ sock_put(sk);
+-
+- /* Ensure no more work items will run before freeing conn. */
+- cancel_delayed_work_sync(&conn->timeout_work);
+ }
+
++ /* Ensure no more work items will run before freeing conn. */
++ cancel_delayed_work_sync(&conn->timeout_work);
++
+ hcon->sco_data = NULL;
+ kfree(conn);
+ }
+@@ -213,8 +215,6 @@ static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ sco_pi(sk)->conn = conn;
+ conn->sk = sk;
+
+- INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
+-
+ if (parent)
+ bt_accept_enqueue(parent, sk, true);
+ }
+@@ -280,7 +280,8 @@ static int sco_connect(struct hci_dev *hdev, struct sock *sk)
+ return err;
+ }
+
+-static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
++static int sco_send_frame(struct sock *sk, void *buf, int len,
++ unsigned int msg_flags)
+ {
+ struct sco_conn *conn = sco_pi(sk)->conn;
+ struct sk_buff *skb;
+@@ -292,15 +293,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+
+ BT_DBG("sk %p len %d", sk, len);
+
+- skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
++ skb = bt_skb_send_alloc(sk, len, msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return err;
+
+- if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+- kfree_skb(skb);
+- return -EFAULT;
+- }
+-
++ memcpy(skb_put(skb, len), buf, len);
+ hci_send_sco(conn->hcon, skb);
+
+ return len;
+@@ -725,6 +722,7 @@ static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
+ size_t len)
+ {
+ struct sock *sk = sock->sk;
++ void *buf;
+ int err;
+
+ BT_DBG("sock %p, sk %p", sock, sk);
+@@ -736,14 +734,24 @@ static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
++ buf = kmalloc(len, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (memcpy_from_msg(buf, msg, len)) {
++ kfree(buf);
++ return -EFAULT;
++ }
++
+ lock_sock(sk);
+
+ if (sk->sk_state == BT_CONNECTED)
+- err = sco_send_frame(sk, msg, len);
++ err = sco_send_frame(sk, buf, len, msg->msg_flags);
+ else
+ err = -ENOTCONN;
+
+ release_sock(sk);
++ kfree(buf);
+ return err;
+ }
+
+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
+index 37ca76406f1e8..fd5e7e74573ce 100644
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -1911,11 +1911,13 @@ static inline int br_cfm_status_fill_info(struct sk_buff *skb,
+
+ static inline int br_cfm_mep_count(struct net_bridge *br, u32 *count)
+ {
++ *count = 0;
+ return -EOPNOTSUPP;
+ }
+
+ static inline int br_cfm_peer_mep_count(struct net_bridge *br, u32 *count)
+ {
++ *count = 0;
+ return -EOPNOTSUPP;
+ }
+ #endif
+diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
+index 9bc55ecb37f9f..8452b0fbb78c9 100644
+--- a/net/can/j1939/main.c
++++ b/net/can/j1939/main.c
+@@ -75,6 +75,13 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data)
+ skcb->addr.pgn = (cf->can_id >> 8) & J1939_PGN_MAX;
+ /* set default message type */
+ skcb->addr.type = J1939_TP;
++
++ if (!j1939_address_is_valid(skcb->addr.sa)) {
++ netdev_err_once(priv->ndev, "%s: sa is broadcast address, ignoring!\n",
++ __func__);
++ goto done;
++ }
++
+ if (j1939_pgn_is_pdu1(skcb->addr.pgn)) {
+ /* Type 1: with destination address */
+ skcb->addr.da = skcb->addr.pgn;
+diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
+index 6c0a0ebdd024c..a271688780a2c 100644
+--- a/net/can/j1939/transport.c
++++ b/net/can/j1939/transport.c
+@@ -2023,6 +2023,11 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
+ extd = J1939_ETP;
+ fallthrough;
+ case J1939_TP_CMD_BAM:
++ if (cmd == J1939_TP_CMD_BAM && !j1939_cb_is_broadcast(skcb)) {
++ netdev_err_once(priv->ndev, "%s: BAM to unicast (%02x), ignoring!\n",
++ __func__, skcb->addr.sa);
++ return;
++ }
+ fallthrough;
+ case J1939_TP_CMD_RTS:
+ if (skcb->addr.type != extd)
+@@ -2085,6 +2090,12 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
+ break;
+
+ case J1939_ETP_CMD_ABORT: /* && J1939_TP_CMD_ABORT */
++ if (j1939_cb_is_broadcast(skcb)) {
++ netdev_err_once(priv->ndev, "%s: abort to broadcast (%02x), ignoring!\n",
++ __func__, skcb->addr.sa);
++ return;
++ }
++
+ if (j1939_tp_im_transmitter(skcb))
+ j1939_xtp_rx_abort(priv, skb, true);
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index eb3a366bf212c..91f53eeb0e79f 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2921,6 +2921,8 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+ if (dev->num_tc)
+ netif_setup_tc(dev, txq);
+
++ dev_qdisc_change_real_num_tx(dev, txq);
++
+ dev->real_num_tx_queues = txq;
+
+ if (disabling) {
+@@ -4193,7 +4195,10 @@ static int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
+ if (dev->flags & IFF_UP) {
+ int cpu = smp_processor_id(); /* ok because BHs are off */
+
+- if (txq->xmit_lock_owner != cpu) {
++ /* Other cpus might concurrently change txq->xmit_lock_owner
++ * to -1 or to their cpu id, but not to our id.
++ */
++ if (READ_ONCE(txq->xmit_lock_owner) != cpu) {
+ if (dev_xmit_recursion())
+ goto recursion_alert;
+
+diff --git a/net/core/devlink.c b/net/core/devlink.c
+index a856ae401ea5c..6931713e363fd 100644
+--- a/net/core/devlink.c
++++ b/net/core/devlink.c
+@@ -4031,14 +4031,6 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
+ return err;
+ }
+
+- if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
+- info->attrs[DEVLINK_ATTR_NETNS_FD] ||
+- info->attrs[DEVLINK_ATTR_NETNS_ID]) {
+- dest_net = devlink_netns_get(skb, info);
+- if (IS_ERR(dest_net))
+- return PTR_ERR(dest_net);
+- }
+-
+ if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
+ action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
+ else
+@@ -4081,6 +4073,14 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
+ return -EINVAL;
+ }
+ }
++ if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
++ info->attrs[DEVLINK_ATTR_NETNS_FD] ||
++ info->attrs[DEVLINK_ATTR_NETNS_ID]) {
++ dest_net = devlink_netns_get(skb, info);
++ if (IS_ERR(dest_net))
++ return PTR_ERR(dest_net);
++ }
++
+ err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack);
+
+ if (dest_net)
+diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
+index be74ab4551c20..0ccfd5fa5cb9b 100644
+--- a/net/core/dst_cache.c
++++ b/net/core/dst_cache.c
+@@ -162,3 +162,22 @@ void dst_cache_destroy(struct dst_cache *dst_cache)
+ free_percpu(dst_cache->cache);
+ }
+ EXPORT_SYMBOL_GPL(dst_cache_destroy);
++
++void dst_cache_reset_now(struct dst_cache *dst_cache)
++{
++ int i;
++
++ if (!dst_cache->cache)
++ return;
++
++ dst_cache->reset_ts = jiffies;
++ for_each_possible_cpu(i) {
++ struct dst_cache_pcpu *idst = per_cpu_ptr(dst_cache->cache, i);
++ struct dst_entry *dst = idst->dst;
++
++ idst->cookie = 0;
++ idst->dst = NULL;
++ dst_release(dst);
++ }
++}
++EXPORT_SYMBOL_GPL(dst_cache_reset_now);
+diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
+index 79df7cd9dbc16..1bb567a3b329c 100644
+--- a/net/core/fib_rules.c
++++ b/net/core/fib_rules.c
+@@ -323,7 +323,7 @@ jumped:
+ if (!err && ops->suppress && INDIRECT_CALL_MT(ops->suppress,
+ fib6_rule_suppress,
+ fib4_rule_suppress,
+- rule, arg))
++ rule, flags, arg))
+ continue;
+
+ if (err != -EAGAIN) {
+diff --git a/net/core/filter.c b/net/core/filter.c
+index 2e32cee2c4690..1e6831880d1fd 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -7162,6 +7162,8 @@ sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
+ #endif
+ case BPF_FUNC_sk_storage_get:
+ return &bpf_sk_storage_get_cg_sock_proto;
++ case BPF_FUNC_ktime_get_coarse_ns:
++ return &bpf_ktime_get_coarse_ns_proto;
+ default:
+ return bpf_base_func_proto(func_id);
+ }
+@@ -9735,22 +9737,46 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
+ static struct bpf_insn *bpf_convert_data_end_access(const struct bpf_insn *si,
+ struct bpf_insn *insn)
+ {
+- /* si->dst_reg = skb->data */
++ int reg;
++ int temp_reg_off = offsetof(struct sk_buff, cb) +
++ offsetof(struct sk_skb_cb, temp_reg);
++
++ if (si->src_reg == si->dst_reg) {
++ /* We need an extra register, choose and save a register. */
++ reg = BPF_REG_9;
++ if (si->src_reg == reg || si->dst_reg == reg)
++ reg--;
++ if (si->src_reg == reg || si->dst_reg == reg)
++ reg--;
++ *insn++ = BPF_STX_MEM(BPF_DW, si->src_reg, reg, temp_reg_off);
++ } else {
++ reg = si->dst_reg;
++ }
++
++ /* reg = skb->data */
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data),
+- si->dst_reg, si->src_reg,
++ reg, si->src_reg,
+ offsetof(struct sk_buff, data));
+ /* AX = skb->len */
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, len),
+ BPF_REG_AX, si->src_reg,
+ offsetof(struct sk_buff, len));
+- /* si->dst_reg = skb->data + skb->len */
+- *insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
++ /* reg = skb->data + skb->len */
++ *insn++ = BPF_ALU64_REG(BPF_ADD, reg, BPF_REG_AX);
+ /* AX = skb->data_len */
+ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data_len),
+ BPF_REG_AX, si->src_reg,
+ offsetof(struct sk_buff, data_len));
+- /* si->dst_reg = skb->data + skb->len - skb->data_len */
+- *insn++ = BPF_ALU64_REG(BPF_SUB, si->dst_reg, BPF_REG_AX);
++
++ /* reg = skb->data + skb->len - skb->data_len */
++ *insn++ = BPF_ALU64_REG(BPF_SUB, reg, BPF_REG_AX);
++
++ if (si->src_reg == si->dst_reg) {
++ /* Restore the saved register */
++ *insn++ = BPF_MOV64_REG(BPF_REG_AX, si->src_reg);
++ *insn++ = BPF_MOV64_REG(si->dst_reg, reg);
++ *insn++ = BPF_LDX_MEM(BPF_DW, reg, BPF_REG_AX, temp_reg_off);
++ }
+
+ return insn;
+ }
+@@ -9761,11 +9787,33 @@ static u32 sk_skb_convert_ctx_access(enum bpf_access_type type,
+ struct bpf_prog *prog, u32 *target_size)
+ {
+ struct bpf_insn *insn = insn_buf;
++ int off;
+
+ switch (si->off) {
+ case offsetof(struct __sk_buff, data_end):
+ insn = bpf_convert_data_end_access(si, insn);
+ break;
++ case offsetof(struct __sk_buff, cb[0]) ...
++ offsetofend(struct __sk_buff, cb[4]) - 1:
++ BUILD_BUG_ON(sizeof_field(struct sk_skb_cb, data) < 20);
++ BUILD_BUG_ON((offsetof(struct sk_buff, cb) +
++ offsetof(struct sk_skb_cb, data)) %
++ sizeof(__u64));
++
++ prog->cb_access = 1;
++ off = si->off;
++ off -= offsetof(struct __sk_buff, cb[0]);
++ off += offsetof(struct sk_buff, cb);
++ off += offsetof(struct sk_skb_cb, data);
++ if (type == BPF_WRITE)
++ *insn++ = BPF_STX_MEM(BPF_SIZE(si->code), si->dst_reg,
++ si->src_reg, off);
++ else
++ *insn++ = BPF_LDX_MEM(BPF_SIZE(si->code), si->dst_reg,
++ si->src_reg, off);
++ break;
++
++
+ default:
+ return bpf_convert_ctx_access(type, si, insn_buf, prog,
+ target_size);
+@@ -10260,6 +10308,8 @@ sk_reuseport_func_proto(enum bpf_func_id func_id,
+ return &sk_reuseport_load_bytes_relative_proto;
+ case BPF_FUNC_get_socket_cookie:
+ return &bpf_get_socket_ptr_cookie_proto;
++ case BPF_FUNC_ktime_get_coarse_ns:
++ return &bpf_ktime_get_coarse_ns_proto;
+ default:
+ return bpf_base_func_proto(func_id);
+ }
+@@ -10741,6 +10791,8 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id)
+ case BPF_FUNC_skc_to_udp6_sock:
+ func = &bpf_skc_to_udp6_sock_proto;
+ break;
++ case BPF_FUNC_ktime_get_coarse_ns:
++ return &bpf_ktime_get_coarse_ns_proto;
+ default:
+ return bpf_base_func_proto(func_id);
+ }
+diff --git a/net/core/neighbour.c b/net/core/neighbour.c
+index 2d5bc3a75faec..ff049733cceeb 100644
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -379,7 +379,7 @@ EXPORT_SYMBOL(neigh_ifdown);
+
+ static struct neighbour *neigh_alloc(struct neigh_table *tbl,
+ struct net_device *dev,
+- bool exempt_from_gc)
++ u8 flags, bool exempt_from_gc)
+ {
+ struct neighbour *n = NULL;
+ unsigned long now = jiffies;
+@@ -412,6 +412,7 @@ do_alloc:
+ n->updated = n->used = now;
+ n->nud_state = NUD_NONE;
+ n->output = neigh_blackhole;
++ n->flags = flags;
+ seqlock_init(&n->hh.hh_lock);
+ n->parms = neigh_parms_clone(&tbl->parms);
+ timer_setup(&n->timer, neigh_timer_handler, 0);
+@@ -575,19 +576,18 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
+ }
+ EXPORT_SYMBOL(neigh_lookup_nodev);
+
+-static struct neighbour *___neigh_create(struct neigh_table *tbl,
+- const void *pkey,
+- struct net_device *dev,
+- bool exempt_from_gc, bool want_ref)
++static struct neighbour *
++___neigh_create(struct neigh_table *tbl, const void *pkey,
++ struct net_device *dev, u8 flags,
++ bool exempt_from_gc, bool want_ref)
+ {
+- struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
+- u32 hash_val;
+- unsigned int key_len = tbl->key_len;
+- int error;
++ u32 hash_val, key_len = tbl->key_len;
++ struct neighbour *n1, *rc, *n;
+ struct neigh_hash_table *nht;
++ int error;
+
++ n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
+ trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
+-
+ if (!n) {
+ rc = ERR_PTR(-ENOBUFS);
+ goto out;
+@@ -674,7 +674,7 @@ out_neigh_release:
+ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
+ struct net_device *dev, bool want_ref)
+ {
+- return ___neigh_create(tbl, pkey, dev, false, want_ref);
++ return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
+ }
+ EXPORT_SYMBOL(__neigh_create);
+
+@@ -733,11 +733,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
+
+ ASSERT_RTNL();
+
+- n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
++ n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
+ if (!n)
+ goto out;
+
+- n->protocol = 0;
+ write_pnet(&n->net, net);
+ memcpy(n->key, pkey, key_len);
+ n->dev = dev;
+@@ -1217,7 +1216,7 @@ static void neigh_update_hhs(struct neighbour *neigh)
+ lladdr instead of overriding it
+ if it is different.
+ NEIGH_UPDATE_F_ADMIN means that the change is administrative.
+-
++ NEIGH_UPDATE_F_USE means that the entry is user triggered.
+ NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
+ NTF_ROUTER flag.
+ NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
+@@ -1255,6 +1254,12 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
+ goto out;
+
+ ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
++ if (flags & NEIGH_UPDATE_F_USE) {
++ new = old & ~NUD_PERMANENT;
++ neigh->nud_state = new;
++ err = 0;
++ goto out;
++ }
+
+ if (!(new & NUD_VALID)) {
+ neigh_del_timer(neigh);
+@@ -1942,7 +1947,9 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
+
+ exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
+ ndm->ndm_flags & NTF_EXT_LEARNED;
+- neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
++ neigh = ___neigh_create(tbl, dst, dev,
++ ndm->ndm_flags & NTF_EXT_LEARNED,
++ exempt_from_gc, true);
+ if (IS_ERR(neigh)) {
+ err = PTR_ERR(neigh);
+ goto out;
+@@ -1961,22 +1968,20 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
+
+ if (protocol)
+ neigh->protocol = protocol;
+-
+ if (ndm->ndm_flags & NTF_EXT_LEARNED)
+ flags |= NEIGH_UPDATE_F_EXT_LEARNED;
+-
+ if (ndm->ndm_flags & NTF_ROUTER)
+ flags |= NEIGH_UPDATE_F_ISROUTER;
++ if (ndm->ndm_flags & NTF_USE)
++ flags |= NEIGH_UPDATE_F_USE;
+
+- if (ndm->ndm_flags & NTF_USE) {
++ err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
++ NETLINK_CB(skb).portid, extack);
++ if (!err && ndm->ndm_flags & NTF_USE) {
+ neigh_event_send(neigh, NULL);
+ err = 0;
+- } else
+- err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
+- NETLINK_CB(skb).portid, extack);
+-
++ }
+ neigh_release(neigh);
+-
+ out:
+ return err;
+ }
+diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
+index b2e49eb7001d6..dfa5ecff7f738 100644
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -175,6 +175,14 @@ static int change_carrier(struct net_device *dev, unsigned long new_carrier)
+ static ssize_t carrier_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+ {
++ struct net_device *netdev = to_net_dev(dev);
++
++ /* The check is also done in change_carrier; this helps returning early
++ * without hitting the trylock/restart in netdev_store.
++ */
++ if (!netdev->netdev_ops->ndo_change_carrier)
++ return -EOPNOTSUPP;
++
+ return netdev_store(dev, attr, buf, len, change_carrier);
+ }
+
+@@ -196,6 +204,12 @@ static ssize_t speed_show(struct device *dev,
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
++ /* The check is also done in __ethtool_get_link_ksettings; this helps
++ * returning early without hitting the trylock/restart below.
++ */
++ if (!netdev->ethtool_ops->get_link_ksettings)
++ return ret;
++
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+@@ -216,6 +230,12 @@ static ssize_t duplex_show(struct device *dev,
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
++ /* The check is also done in __ethtool_get_link_ksettings; this helps
++ * returning early without hitting the trylock/restart below.
++ */
++ if (!netdev->ethtool_ops->get_link_ksettings)
++ return ret;
++
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+@@ -468,6 +488,14 @@ static ssize_t proto_down_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+ {
++ struct net_device *netdev = to_net_dev(dev);
++
++ /* The check is also done in change_proto_down; this helps returning
++ * early without hitting the trylock/restart in netdev_store.
++ */
++ if (!netdev->netdev_ops->ndo_change_proto_down)
++ return -EOPNOTSUPP;
++
+ return netdev_store(dev, attr, buf, len, change_proto_down);
+ }
+ NETDEVICE_SHOW_RW(proto_down, fmt_dec);
+@@ -478,6 +506,12 @@ static ssize_t phys_port_id_show(struct device *dev,
+ struct net_device *netdev = to_net_dev(dev);
+ ssize_t ret = -EINVAL;
+
++ /* The check is also done in dev_get_phys_port_id; this helps returning
++ * early without hitting the trylock/restart below.
++ */
++ if (!netdev->netdev_ops->ndo_get_phys_port_id)
++ return -EOPNOTSUPP;
++
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+@@ -500,6 +534,13 @@ static ssize_t phys_port_name_show(struct device *dev,
+ struct net_device *netdev = to_net_dev(dev);
+ ssize_t ret = -EINVAL;
+
++ /* The checks are also done in dev_get_phys_port_name; this helps
++ * returning early without hitting the trylock/restart below.
++ */
++ if (!netdev->netdev_ops->ndo_get_phys_port_name &&
++ !netdev->netdev_ops->ndo_get_devlink_port)
++ return -EOPNOTSUPP;
++
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+@@ -522,6 +563,14 @@ static ssize_t phys_switch_id_show(struct device *dev,
+ struct net_device *netdev = to_net_dev(dev);
+ ssize_t ret = -EINVAL;
+
++ /* The checks are also done in dev_get_phys_port_name; this helps
++ * returning early without hitting the trylock/restart below. This works
++ * because recurse is false when calling dev_get_port_parent_id.
++ */
++ if (!netdev->netdev_ops->ndo_get_port_parent_id &&
++ !netdev->netdev_ops->ndo_get_devlink_port)
++ return -EOPNOTSUPP;
++
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+@@ -1226,6 +1275,12 @@ static ssize_t tx_maxrate_store(struct netdev_queue *queue,
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
++ /* The check is also done later; this helps returning early without
++ * hitting the trylock/restart below.
++ */
++ if (!dev->netdev_ops->ndo_set_tx_maxrate)
++ return -EOPNOTSUPP;
++
+ err = kstrtou32(buf, 10, &rate);
+ if (err < 0)
+ return err;
+diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
+index a448a9b5bb2d6..202fa5eacd0f9 100644
+--- a/net/core/net_namespace.c
++++ b/net/core/net_namespace.c
+@@ -473,7 +473,9 @@ struct net *copy_net_ns(unsigned long flags,
+
+ if (rv < 0) {
+ put_userns:
++#ifdef CONFIG_KEYS
+ key_remove_domain(net->key_domain);
++#endif
+ put_user_ns(user_ns);
+ net_free(net);
+ dec_ucounts:
+@@ -605,7 +607,9 @@ static void cleanup_net(struct work_struct *work)
+ list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
+ list_del_init(&net->exit_list);
+ dec_net_namespaces(net->ucounts);
++#ifdef CONFIG_KEYS
+ key_remove_domain(net->key_domain);
++#endif
+ put_user_ns(net->user_ns);
+ net_free(net);
+ }
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index fe9358437380c..f7e003571a356 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -832,7 +832,7 @@ void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt)
+ ntohs(skb->protocol), skb->pkt_type, skb->skb_iif);
+
+ if (dev)
+- printk("%sdev name=%s feat=0x%pNF\n",
++ printk("%sdev name=%s feat=%pNF\n",
+ level, dev->name, &dev->features);
+ if (sk)
+ printk("%ssk family=%hu type=%u proto=%u\n",
+@@ -3449,19 +3449,7 @@ EXPORT_SYMBOL(skb_split);
+ */
+ static int skb_prepare_for_shift(struct sk_buff *skb)
+ {
+- int ret = 0;
+-
+- if (skb_cloned(skb)) {
+- /* Save and restore truesize: pskb_expand_head() may reallocate
+- * memory where ksize(kmalloc(S)) != ksize(kmalloc(S)), but we
+- * cannot change truesize at this point.
+- */
+- unsigned int save_truesize = skb->truesize;
+-
+- ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+- skb->truesize = save_truesize;
+- }
+- return ret;
++ return skb_unclone_keeptruesize(skb, GFP_ATOMIC);
+ }
+
+ /**
+diff --git a/net/core/skmsg.c b/net/core/skmsg.c
+index a86ef7e844f8c..8eb671c827f90 100644
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -508,6 +508,7 @@ static struct sk_msg *sk_psock_create_ingress_msg(struct sock *sk,
+ }
+
+ static int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,
++ u32 off, u32 len,
+ struct sk_psock *psock,
+ struct sock *sk,
+ struct sk_msg *msg)
+@@ -521,11 +522,11 @@ static int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,
+ */
+ if (skb_linearize(skb))
+ return -EAGAIN;
+- num_sge = skb_to_sgvec(skb, msg->sg.data, 0, skb->len);
++ num_sge = skb_to_sgvec(skb, msg->sg.data, off, len);
+ if (unlikely(num_sge < 0))
+ return num_sge;
+
+- copied = skb->len;
++ copied = len;
+ msg->sg.start = 0;
+ msg->sg.size = copied;
+ msg->sg.end = num_sge;
+@@ -536,9 +537,11 @@ static int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,
+ return copied;
+ }
+
+-static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb);
++static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb,
++ u32 off, u32 len);
+
+-static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
++static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb,
++ u32 off, u32 len)
+ {
+ struct sock *sk = psock->sk;
+ struct sk_msg *msg;
+@@ -549,7 +552,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
+ * correctly.
+ */
+ if (unlikely(skb->sk == sk))
+- return sk_psock_skb_ingress_self(psock, skb);
++ return sk_psock_skb_ingress_self(psock, skb, off, len);
+ msg = sk_psock_create_ingress_msg(sk, skb);
+ if (!msg)
+ return -EAGAIN;
+@@ -561,7 +564,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
+ * into user buffers.
+ */
+ skb_set_owner_r(skb, sk);
+- err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg);
++ err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg);
+ if (err < 0)
+ kfree(msg);
+ return err;
+@@ -571,7 +574,8 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
+ * skb. In this case we do not need to check memory limits or skb_set_owner_r
+ * because the skb is already accounted for here.
+ */
+-static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb)
++static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb,
++ u32 off, u32 len)
+ {
+ struct sk_msg *msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC);
+ struct sock *sk = psock->sk;
+@@ -581,7 +585,7 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb
+ return -EAGAIN;
+ sk_msg_init(msg);
+ skb_set_owner_r(skb, sk);
+- err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg);
++ err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg);
+ if (err < 0)
+ kfree(msg);
+ return err;
+@@ -595,7 +599,7 @@ static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
+ return -EAGAIN;
+ return skb_send_sock(psock->sk, skb, off, len);
+ }
+- return sk_psock_skb_ingress(psock, skb);
++ return sk_psock_skb_ingress(psock, skb, off, len);
+ }
+
+ static void sk_psock_skb_state(struct sk_psock *psock,
+@@ -638,6 +642,12 @@ static void sk_psock_backlog(struct work_struct *work)
+ while ((skb = skb_dequeue(&psock->ingress_skb))) {
+ len = skb->len;
+ off = 0;
++ if (skb_bpf_strparser(skb)) {
++ struct strp_msg *stm = strp_msg(skb);
++
++ off = stm->offset;
++ len = stm->full_len;
++ }
+ start:
+ ingress = skb_bpf_ingress(skb);
+ skb_bpf_redirect_clear(skb);
+@@ -877,6 +887,7 @@ static int sk_psock_skb_redirect(struct sk_psock *from, struct sk_buff *skb)
+ * return code, but then didn't set a redirect interface.
+ */
+ if (unlikely(!sk_other)) {
++ skb_bpf_redirect_clear(skb);
+ sock_drop(from->sk, skb);
+ return -EIO;
+ }
+@@ -944,6 +955,7 @@ static int sk_psock_verdict_apply(struct sk_psock *psock, struct sk_buff *skb,
+ {
+ struct sock *sk_other;
+ int err = 0;
++ u32 len, off;
+
+ switch (verdict) {
+ case __SK_PASS:
+@@ -951,6 +963,7 @@ static int sk_psock_verdict_apply(struct sk_psock *psock, struct sk_buff *skb,
+ sk_other = psock->sk;
+ if (sock_flag(sk_other, SOCK_DEAD) ||
+ !sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
++ skb_bpf_redirect_clear(skb);
+ goto out_free;
+ }
+
+@@ -963,7 +976,15 @@ static int sk_psock_verdict_apply(struct sk_psock *psock, struct sk_buff *skb,
+ * retrying later from workqueue.
+ */
+ if (skb_queue_empty(&psock->ingress_skb)) {
+- err = sk_psock_skb_ingress_self(psock, skb);
++ len = skb->len;
++ off = 0;
++ if (skb_bpf_strparser(skb)) {
++ struct strp_msg *stm = strp_msg(skb);
++
++ off = stm->offset;
++ len = stm->full_len;
++ }
++ err = sk_psock_skb_ingress_self(psock, skb, off, len);
+ }
+ if (err < 0) {
+ spin_lock_bh(&psock->ingress_lock);
+@@ -1029,6 +1050,8 @@ static void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb)
+ skb_dst_drop(skb);
+ skb_bpf_redirect_clear(skb);
+ ret = bpf_prog_run_pin_on_cpu(prog, skb);
++ if (ret == SK_PASS)
++ skb_bpf_set_strparser(skb);
+ ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
+ skb->sk = NULL;
+ }
+@@ -1101,6 +1124,8 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
+
+ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
+ {
++ psock_set_prog(&psock->progs.stream_parser, NULL);
++
+ if (!psock->saved_data_ready)
+ return;
+
+@@ -1189,6 +1214,9 @@ void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
+
+ void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
+ {
++ psock_set_prog(&psock->progs.stream_verdict, NULL);
++ psock_set_prog(&psock->progs.skb_verdict, NULL);
++
+ if (!psock->saved_data_ready)
+ return;
+
+diff --git a/net/core/sock.c b/net/core/sock.c
+index c1601f75ec4b3..1b31e10181629 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -2043,8 +2043,10 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
+ newsk->sk_prot_creator = prot;
+
+ /* SANITY */
+- if (likely(newsk->sk_net_refcnt))
++ if (likely(newsk->sk_net_refcnt)) {
+ get_net(sock_net(newsk));
++ sock_inuse_add(sock_net(newsk), 1);
++ }
+ sk_node_init(&newsk->sk_node);
+ sock_lock_init(newsk);
+ bh_lock_sock(newsk);
+@@ -2115,8 +2117,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
+ newsk->sk_err_soft = 0;
+ newsk->sk_priority = 0;
+ newsk->sk_incoming_cpu = raw_smp_processor_id();
+- if (likely(newsk->sk_net_refcnt))
+- sock_inuse_add(sock_net(newsk), 1);
+
+ /* Before updating sk_refcnt, we must commit prior changes to memory
+ * (Documentation/RCU/rculist_nulls.rst for details)
+diff --git a/net/core/sock_map.c b/net/core/sock_map.c
+index e252b8ec2b85e..c89f527411e84 100644
+--- a/net/core/sock_map.c
++++ b/net/core/sock_map.c
+@@ -167,8 +167,11 @@ static void sock_map_del_link(struct sock *sk,
+ write_lock_bh(&sk->sk_callback_lock);
+ if (strp_stop)
+ sk_psock_stop_strp(sk, psock);
+- else
++ if (verdict_stop)
+ sk_psock_stop_verdict(sk, psock);
++
++ if (psock->psock_update_sk_prot)
++ psock->psock_update_sk_prot(sk, psock, false);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ }
+@@ -282,6 +285,12 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
+
+ if (msg_parser)
+ psock_set_prog(&psock->progs.msg_parser, msg_parser);
++ if (stream_parser)
++ psock_set_prog(&psock->progs.stream_parser, stream_parser);
++ if (stream_verdict)
++ psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
++ if (skb_verdict)
++ psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
+
+ ret = sock_map_init_proto(sk, psock);
+ if (ret < 0)
+@@ -292,14 +301,10 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
+ ret = sk_psock_init_strp(sk, psock);
+ if (ret)
+ goto out_unlock_drop;
+- psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
+- psock_set_prog(&psock->progs.stream_parser, stream_parser);
+ sk_psock_start_strp(sk, psock);
+ } else if (!stream_parser && stream_verdict && !psock->saved_data_ready) {
+- psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
+ sk_psock_start_verdict(sk,psock);
+ } else if (!stream_verdict && skb_verdict && !psock->saved_data_ready) {
+- psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
+ sk_psock_start_verdict(sk, psock);
+ }
+ write_unlock_bh(&sk->sk_callback_lock);
+diff --git a/net/core/stream.c b/net/core/stream.c
+index 4f1d4aa5fb38d..a166a32b411fa 100644
+--- a/net/core/stream.c
++++ b/net/core/stream.c
+@@ -195,9 +195,6 @@ void sk_stream_kill_queues(struct sock *sk)
+ /* First the read buffer. */
+ __skb_queue_purge(&sk->sk_receive_queue);
+
+- /* Next, the error queue. */
+- __skb_queue_purge(&sk->sk_error_queue);
+-
+ /* Next, the write queue. */
+ WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
+
+diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
+index c5c1d2b8045e8..5183e627468d8 100644
+--- a/net/dccp/dccp.h
++++ b/net/dccp/dccp.h
+@@ -48,7 +48,7 @@ extern bool dccp_debug;
+
+ extern struct inet_hashinfo dccp_hashinfo;
+
+-extern struct percpu_counter dccp_orphan_count;
++DECLARE_PER_CPU(unsigned int, dccp_orphan_count);
+
+ void dccp_time_wait(struct sock *sk, int state, int timeo);
+
+diff --git a/net/dccp/proto.c b/net/dccp/proto.c
+index abb5c596a8176..fc44dadc778bb 100644
+--- a/net/dccp/proto.c
++++ b/net/dccp/proto.c
+@@ -42,8 +42,8 @@ DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
+
+ EXPORT_SYMBOL_GPL(dccp_statistics);
+
+-struct percpu_counter dccp_orphan_count;
+-EXPORT_SYMBOL_GPL(dccp_orphan_count);
++DEFINE_PER_CPU(unsigned int, dccp_orphan_count);
++EXPORT_PER_CPU_SYMBOL_GPL(dccp_orphan_count);
+
+ struct inet_hashinfo dccp_hashinfo;
+ EXPORT_SYMBOL_GPL(dccp_hashinfo);
+@@ -1055,7 +1055,7 @@ adjudge_to_death:
+ bh_lock_sock(sk);
+ WARN_ON(sock_owned_by_user(sk));
+
+- percpu_counter_inc(sk->sk_prot->orphan_count);
++ this_cpu_inc(dccp_orphan_count);
+
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
+@@ -1115,13 +1115,10 @@ static int __init dccp_init(void)
+
+ BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
+ sizeof_field(struct sk_buff, cb));
+- rc = percpu_counter_init(&dccp_orphan_count, 0, GFP_KERNEL);
+- if (rc)
+- goto out_fail;
+ inet_hashinfo_init(&dccp_hashinfo);
+ rc = inet_hashinfo2_init_mod(&dccp_hashinfo);
+ if (rc)
+- goto out_free_percpu;
++ goto out_fail;
+ rc = -ENOBUFS;
+ dccp_hashinfo.bind_bucket_cachep =
+ kmem_cache_create("dccp_bind_bucket",
+@@ -1226,8 +1223,6 @@ out_free_bind_bucket_cachep:
+ kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
+ out_free_hashinfo2:
+ inet_hashinfo2_free_mod(&dccp_hashinfo);
+-out_free_percpu:
+- percpu_counter_destroy(&dccp_orphan_count);
+ out_fail:
+ dccp_hashinfo.bhash = NULL;
+ dccp_hashinfo.ehash = NULL;
+@@ -1250,7 +1245,6 @@ static void __exit dccp_fini(void)
+ dccp_ackvec_exit();
+ dccp_sysctl_exit();
+ inet_hashinfo2_free_mod(&dccp_hashinfo);
+- percpu_counter_destroy(&dccp_orphan_count);
+ }
+
+ module_init(dccp_init);
+diff --git a/net/dsa/switch.c b/net/dsa/switch.c
+index 6466d0539af9f..44558fbdc65b3 100644
+--- a/net/dsa/switch.c
++++ b/net/dsa/switch.c
+@@ -264,7 +264,7 @@ static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port,
+
+ err = ds->ops->port_mdb_del(ds, port, mdb);
+ if (err) {
+- refcount_inc(&a->refcount);
++ refcount_set(&a->refcount, 1);
+ return err;
+ }
+
+@@ -329,7 +329,7 @@ static int dsa_switch_do_fdb_del(struct dsa_switch *ds, int port,
+
+ err = ds->ops->port_fdb_del(ds, port, addr, vid);
+ if (err) {
+- refcount_inc(&a->refcount);
++ refcount_set(&a->refcount, 1);
+ return err;
+ }
+
+diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
+index 605b51ca69210..6e0518aa3a4d2 100644
+--- a/net/dsa/tag_ocelot.c
++++ b/net/dsa/tag_ocelot.c
+@@ -62,6 +62,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
+ struct dsa_port *dp;
+ u8 *extraction;
+ u16 vlan_tpid;
++ u64 rew_val;
+
+ /* Revert skb->data by the amount consumed by the DSA master,
+ * so it points to the beginning of the frame.
+@@ -91,6 +92,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
+ ocelot_xfh_get_qos_class(extraction, &qos_class);
+ ocelot_xfh_get_tag_type(extraction, &tag_type);
+ ocelot_xfh_get_vlan_tci(extraction, &vlan_tci);
++ ocelot_xfh_get_rew_val(extraction, &rew_val);
+
+ skb->dev = dsa_master_find_slave(netdev, 0, src_port);
+ if (!skb->dev)
+@@ -104,6 +106,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
+
+ dsa_default_offload_fwd_mark(skb);
+ skb->priority = qos_class;
++ OCELOT_SKB_CB(skb)->tstamp_lo = rew_val;
+
+ /* Ocelot switches copy frames unmodified to the CPU. However, it is
+ * possible for the user to request a VLAN modification through
+diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
+index f2abc31528883..e4983f473a3c5 100644
+--- a/net/ethtool/ioctl.c
++++ b/net/ethtool/ioctl.c
+@@ -1697,7 +1697,7 @@ static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce coalesce;
+ int ret;
+
+- if (!dev->ethtool_ops->set_coalesce && !dev->ethtool_ops->get_coalesce)
++ if (!dev->ethtool_ops->set_coalesce || !dev->ethtool_ops->get_coalesce)
+ return -EOPNOTSUPP;
+
+ ret = dev->ethtool_ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
+diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
+index 1797a0a900195..b3729bdafb602 100644
+--- a/net/ethtool/netlink.c
++++ b/net/ethtool/netlink.c
+@@ -40,7 +40,8 @@ int ethnl_ops_begin(struct net_device *dev)
+ if (dev->dev.parent)
+ pm_runtime_get_sync(dev->dev.parent);
+
+- if (!netif_device_present(dev)) {
++ if (!netif_device_present(dev) ||
++ dev->reg_state == NETREG_UNREGISTERING) {
+ ret = -ENODEV;
+ goto err;
+ }
+diff --git a/net/ethtool/pause.c b/net/ethtool/pause.c
+index 9009f412151e7..ee1e5806bc93a 100644
+--- a/net/ethtool/pause.c
++++ b/net/ethtool/pause.c
+@@ -56,8 +56,7 @@ static int pause_reply_size(const struct ethnl_req_info *req_base,
+
+ if (req_base->flags & ETHTOOL_FLAG_STATS)
+ n += nla_total_size(0) + /* _PAUSE_STATS */
+- nla_total_size_64bit(sizeof(u64)) *
+- (ETHTOOL_A_PAUSE_STAT_MAX - 2);
++ nla_total_size_64bit(sizeof(u64)) * ETHTOOL_PAUSE_STAT_CNT;
+ return n;
+ }
+
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 1d816a5fd3eb9..64062b7ce61df 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -773,26 +773,28 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr,
+ DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr);
+
+ sin->sin_family = AF_INET;
++ lock_sock(sk);
+ if (peer) {
+ if (!inet->inet_dport ||
+ (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
+- peer == 1))
++ peer == 1)) {
++ release_sock(sk);
+ return -ENOTCONN;
++ }
+ sin->sin_port = inet->inet_dport;
+ sin->sin_addr.s_addr = inet->inet_daddr;
+- BPF_CGROUP_RUN_SA_PROG_LOCK(sk, (struct sockaddr *)sin,
+- CGROUP_INET4_GETPEERNAME,
+- NULL);
++ BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
++ CGROUP_INET4_GETPEERNAME);
+ } else {
+ __be32 addr = inet->inet_rcv_saddr;
+ if (!addr)
+ addr = inet->inet_saddr;
+ sin->sin_port = inet->inet_sport;
+ sin->sin_addr.s_addr = addr;
+- BPF_CGROUP_RUN_SA_PROG_LOCK(sk, (struct sockaddr *)sin,
+- CGROUP_INET4_GETSOCKNAME,
+- NULL);
++ BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
++ CGROUP_INET4_GETSOCKNAME);
+ }
++ release_sock(sk);
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ return sizeof(*sin);
+ }
+diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
+index 0dcee9df13268..d3a2dbd13ea6b 100644
+--- a/net/ipv4/bpf_tcp_ca.c
++++ b/net/ipv4/bpf_tcp_ca.c
+@@ -212,6 +212,8 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id,
+ offsetof(struct tcp_congestion_ops, release))
+ return &bpf_sk_getsockopt_proto;
+ return NULL;
++ case BPF_FUNC_ktime_get_coarse_ns:
++ return &bpf_ktime_get_coarse_ns_proto;
+ default:
+ return bpf_base_func_proto(func_id);
+ }
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index f4468980b6757..4744c7839de53 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -2587,7 +2587,7 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
+ free:
+ kfree(t);
+ out:
+- return -ENOBUFS;
++ return -ENOMEM;
+ }
+
+ static void __devinet_sysctl_unregister(struct net *net,
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 9fe13e4f5d08a..4d61ddd8a0ecf 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -1582,7 +1582,7 @@ static int __net_init fib_net_init(struct net *net)
+ int error;
+
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+- net->ipv4.fib_num_tclassid_users = 0;
++ atomic_set(&net->ipv4.fib_num_tclassid_users, 0);
+ #endif
+ error = ip_fib_net_init(net);
+ if (error < 0)
+diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
+index ce54a30c2ef1e..d279cb8ac1584 100644
+--- a/net/ipv4/fib_rules.c
++++ b/net/ipv4/fib_rules.c
+@@ -141,6 +141,7 @@ INDIRECT_CALLABLE_SCOPE int fib4_rule_action(struct fib_rule *rule,
+ }
+
+ INDIRECT_CALLABLE_SCOPE bool fib4_rule_suppress(struct fib_rule *rule,
++ int flags,
+ struct fib_lookup_arg *arg)
+ {
+ struct fib_result *result = (struct fib_result *) arg->result;
+@@ -263,7 +264,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+ if (tb[FRA_FLOW]) {
+ rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
+ if (rule4->tclassid)
+- net->ipv4.fib_num_tclassid_users++;
++ atomic_inc(&net->ipv4.fib_num_tclassid_users);
+ }
+ #endif
+
+@@ -295,7 +296,7 @@ static int fib4_rule_delete(struct fib_rule *rule)
+
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ if (((struct fib4_rule *)rule)->tclassid)
+- net->ipv4.fib_num_tclassid_users--;
++ atomic_dec(&net->ipv4.fib_num_tclassid_users);
+ #endif
+ net->ipv4.fib_has_custom_rules = true;
+
+diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
+index 3364cb9c67e01..fde7797b58069 100644
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -220,7 +220,7 @@ void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
+ {
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ if (fib_nh->nh_tclassid)
+- net->ipv4.fib_num_tclassid_users--;
++ atomic_dec(&net->ipv4.fib_num_tclassid_users);
+ #endif
+ fib_nh_common_release(&fib_nh->nh_common);
+ }
+@@ -632,7 +632,7 @@ int fib_nh_init(struct net *net, struct fib_nh *nh,
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ nh->nh_tclassid = cfg->fc_flow;
+ if (nh->nh_tclassid)
+- net->ipv4.fib_num_tclassid_users++;
++ atomic_inc(&net->ipv4.fib_num_tclassid_users);
+ #endif
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ nh->fib_nh_weight = nh_weight;
+diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
+index f25d02ad4a8af..62a67fdc344cd 100644
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -721,7 +721,7 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
+
+ sk_node_init(&nreq_sk->sk_node);
+ nreq_sk->sk_tx_queue_mapping = req_sk->sk_tx_queue_mapping;
+-#ifdef CONFIG_XPS
++#ifdef CONFIG_SOCK_RX_QUEUE_MAPPING
+ nreq_sk->sk_rx_queue_mapping = req_sk->sk_rx_queue_mapping;
+ #endif
+ nreq_sk->sk_incoming_cpu = req_sk->sk_incoming_cpu;
+@@ -1015,7 +1015,7 @@ void inet_csk_destroy_sock(struct sock *sk)
+
+ sk_refcnt_debug_release(sk);
+
+- percpu_counter_dec(sk->sk_prot->orphan_count);
++ this_cpu_dec(*sk->sk_prot->orphan_count);
+
+ sock_put(sk);
+ }
+@@ -1074,7 +1074,7 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req,
+
+ sock_orphan(child);
+
+- percpu_counter_inc(sk->sk_prot->orphan_count);
++ this_cpu_inc(*sk->sk_prot->orphan_count);
+
+ if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) {
+ BUG_ON(rcu_access_pointer(tcp_sk(child)->fastopen_rsk) != req);
+diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
+index ef7897226f08e..ae70e07c52445 100644
+--- a/net/ipv4/inet_diag.c
++++ b/net/ipv4/inet_diag.c
+@@ -261,6 +261,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
+ r->idiag_state = sk->sk_state;
+ r->idiag_timer = 0;
+ r->idiag_retrans = 0;
++ r->idiag_expires = 0;
+
+ if (inet_diag_msg_attrs_fill(sk, skb, r, ext,
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
+@@ -314,9 +315,6 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
+ r->idiag_retrans = icsk->icsk_probes_out;
+ r->idiag_expires =
+ jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies);
+- } else {
+- r->idiag_timer = 0;
+- r->idiag_expires = 0;
+ }
+
+ if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) {
+diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
+index bfb522e513461..75737267746f8 100644
+--- a/net/ipv4/inet_hashtables.c
++++ b/net/ipv4/inet_hashtables.c
+@@ -598,7 +598,7 @@ bool inet_ehash_nolisten(struct sock *sk, struct sock *osk, bool *found_dup_sk)
+ if (ok) {
+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+ } else {
+- percpu_counter_inc(sk->sk_prot->orphan_count);
++ this_cpu_inc(*sk->sk_prot->orphan_count);
+ inet_sk_set_state(sk, TCP_CLOSE);
+ sock_set_flag(sk, SOCK_DEAD);
+ inet_csk_destroy_sock(sk);
+diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
+index 9e8100728d464..5dbd4b5505eba 100644
+--- a/net/ipv4/nexthop.c
++++ b/net/ipv4/nexthop.c
+@@ -1899,15 +1899,36 @@ static void remove_nexthop(struct net *net, struct nexthop *nh,
+ /* if any FIB entries reference this nexthop, any dst entries
+ * need to be regenerated
+ */
+-static void nh_rt_cache_flush(struct net *net, struct nexthop *nh)
++static void nh_rt_cache_flush(struct net *net, struct nexthop *nh,
++ struct nexthop *replaced_nh)
+ {
+ struct fib6_info *f6i;
++ struct nh_group *nhg;
++ int i;
+
+ if (!list_empty(&nh->fi_list))
+ rt_cache_flush(net);
+
+ list_for_each_entry(f6i, &nh->f6i_list, nh_list)
+ ipv6_stub->fib6_update_sernum(net, f6i);
++
++ /* if an IPv6 group was replaced, we have to release all old
++ * dsts to make sure all refcounts are released
++ */
++ if (!replaced_nh->is_group)
++ return;
++
++ /* new dsts must use only the new nexthop group */
++ synchronize_net();
++
++ nhg = rtnl_dereference(replaced_nh->nh_grp);
++ for (i = 0; i < nhg->num_nh; i++) {
++ struct nh_grp_entry *nhge = &nhg->nh_entries[i];
++ struct nh_info *nhi = rtnl_dereference(nhge->nh->nh_info);
++
++ if (nhi->family == AF_INET6)
++ ipv6_stub->fib6_nh_release_dsts(&nhi->fib6_nh);
++ }
+ }
+
+ static int replace_nexthop_grp(struct net *net, struct nexthop *old,
+@@ -2247,7 +2268,7 @@ static int replace_nexthop(struct net *net, struct nexthop *old,
+ err = replace_nexthop_single(net, old, new, extack);
+
+ if (!err) {
+- nh_rt_cache_flush(net, old);
++ nh_rt_cache_flush(net, old, new);
+
+ __remove_nexthop(net, new, NULL);
+ nexthop_put(new);
+@@ -2544,11 +2565,15 @@ static int nh_create_ipv6(struct net *net, struct nexthop *nh,
+ /* sets nh_dev if successful */
+ err = ipv6_stub->fib6_nh_init(net, fib6_nh, &fib6_cfg, GFP_KERNEL,
+ extack);
+- if (err)
++ if (err) {
++ /* IPv6 is not enabled, don't call fib6_nh_release */
++ if (err == -EAFNOSUPPORT)
++ goto out;
+ ipv6_stub->fib6_nh_release(fib6_nh);
+- else
++ } else {
+ nh->nh_flags = fib6_nh->fib_nh_flags;
+-
++ }
++out:
+ return err;
+ }
+
+diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
+index b0d3a09dc84e7..f30273afb5399 100644
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -53,7 +53,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
+ struct net *net = seq->private;
+ int orphans, sockets;
+
+- orphans = percpu_counter_sum_positive(&tcp_orphan_count);
++ orphans = tcp_orphan_count_sum();
+ sockets = proto_sockets_allocated_sum_positive(&tcp_prot);
+
+ socket_seq_show(seq);
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index f5c336f8b0c8e..844c6e5a82891 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -287,8 +287,8 @@ enum {
+ TCP_CMSG_TS = 2
+ };
+
+-struct percpu_counter tcp_orphan_count;
+-EXPORT_SYMBOL_GPL(tcp_orphan_count);
++DEFINE_PER_CPU(unsigned int, tcp_orphan_count);
++EXPORT_PER_CPU_SYMBOL_GPL(tcp_orphan_count);
+
+ long sysctl_tcp_mem[3] __read_mostly;
+ EXPORT_SYMBOL(sysctl_tcp_mem);
+@@ -952,7 +952,7 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
+ */
+ void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
+ {
+- if (skb && !skb->len) {
++ if (skb && TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
+ tcp_unlink_write_queue(skb, sk);
+ if (tcp_write_queue_empty(sk))
+ tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
+@@ -1776,6 +1776,9 @@ static skb_frag_t *skb_advance_to_frag(struct sk_buff *skb, u32 offset_skb,
+ {
+ skb_frag_t *frag;
+
++ if (unlikely(offset_skb >= skb->len))
++ return NULL;
++
+ offset_skb -= skb_headlen(skb);
+ if ((int)offset_skb < 0 || skb_has_frag_list(skb))
+ return NULL;
+@@ -2687,11 +2690,36 @@ void tcp_shutdown(struct sock *sk, int how)
+ }
+ EXPORT_SYMBOL(tcp_shutdown);
+
++int tcp_orphan_count_sum(void)
++{
++ int i, total = 0;
++
++ for_each_possible_cpu(i)
++ total += per_cpu(tcp_orphan_count, i);
++
++ return max(total, 0);
++}
++
++static int tcp_orphan_cache;
++static struct timer_list tcp_orphan_timer;
++#define TCP_ORPHAN_TIMER_PERIOD msecs_to_jiffies(100)
++
++static void tcp_orphan_update(struct timer_list *unused)
++{
++ WRITE_ONCE(tcp_orphan_cache, tcp_orphan_count_sum());
++ mod_timer(&tcp_orphan_timer, jiffies + TCP_ORPHAN_TIMER_PERIOD);
++}
++
++static bool tcp_too_many_orphans(int shift)
++{
++ return READ_ONCE(tcp_orphan_cache) << shift > sysctl_tcp_max_orphans;
++}
++
+ bool tcp_check_oom(struct sock *sk, int shift)
+ {
+ bool too_many_orphans, out_of_socket_memory;
+
+- too_many_orphans = tcp_too_many_orphans(sk, shift);
++ too_many_orphans = tcp_too_many_orphans(shift);
+ out_of_socket_memory = tcp_out_of_memory(sk);
+
+ if (too_many_orphans)
+@@ -2800,7 +2828,7 @@ adjudge_to_death:
+ /* remove backlog if any, without releasing ownership. */
+ __release_sock(sk);
+
+- percpu_counter_inc(sk->sk_prot->orphan_count);
++ this_cpu_inc(tcp_orphan_count);
+
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
+@@ -4502,7 +4530,10 @@ void __init tcp_init(void)
+ sizeof_field(struct sk_buff, cb));
+
+ percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL);
+- percpu_counter_init(&tcp_orphan_count, 0, GFP_KERNEL);
++
++ timer_setup(&tcp_orphan_timer, tcp_orphan_update, TIMER_DEFERRABLE);
++ mod_timer(&tcp_orphan_timer, jiffies + TCP_ORPHAN_TIMER_PERIOD);
++
+ inet_hashinfo_init(&tcp_hashinfo);
+ inet_hashinfo2_init(&tcp_hashinfo, "tcp_listen_portaddr_hash",
+ thash_entries, 21, /* one slot per 2 MB*/
+diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
+index 5f4d6f45d87f7..f70aa0932bd6c 100644
+--- a/net/ipv4/tcp_bpf.c
++++ b/net/ipv4/tcp_bpf.c
+@@ -172,6 +172,41 @@ static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
+ return ret;
+ }
+
++static int tcp_bpf_recvmsg_parser(struct sock *sk,
++ struct msghdr *msg,
++ size_t len,
++ int nonblock,
++ int flags,
++ int *addr_len)
++{
++ struct sk_psock *psock;
++ int copied;
++
++ if (unlikely(flags & MSG_ERRQUEUE))
++ return inet_recv_error(sk, msg, len, addr_len);
++
++ psock = sk_psock_get(sk);
++ if (unlikely(!psock))
++ return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
++
++ lock_sock(sk);
++msg_bytes_ready:
++ copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
++ if (!copied) {
++ long timeo;
++ int data;
++
++ timeo = sock_rcvtimeo(sk, nonblock);
++ data = tcp_msg_wait_data(sk, psock, timeo);
++ if (data && !sk_psock_queue_empty(psock))
++ goto msg_bytes_ready;
++ copied = -EAGAIN;
++ }
++ release_sock(sk);
++ sk_psock_put(sk, psock);
++ return copied;
++}
++
+ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
+ int nonblock, int flags, int *addr_len)
+ {
+@@ -464,6 +499,8 @@ enum {
+ enum {
+ TCP_BPF_BASE,
+ TCP_BPF_TX,
++ TCP_BPF_RX,
++ TCP_BPF_TXRX,
+ TCP_BPF_NUM_CFGS,
+ };
+
+@@ -475,7 +512,6 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS],
+ struct proto *base)
+ {
+ prot[TCP_BPF_BASE] = *base;
+- prot[TCP_BPF_BASE].unhash = sock_map_unhash;
+ prot[TCP_BPF_BASE].close = sock_map_close;
+ prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg;
+ prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable;
+@@ -483,6 +519,12 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS],
+ prot[TCP_BPF_TX] = prot[TCP_BPF_BASE];
+ prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg;
+ prot[TCP_BPF_TX].sendpage = tcp_bpf_sendpage;
++
++ prot[TCP_BPF_RX] = prot[TCP_BPF_BASE];
++ prot[TCP_BPF_RX].recvmsg = tcp_bpf_recvmsg_parser;
++
++ prot[TCP_BPF_TXRX] = prot[TCP_BPF_TX];
++ prot[TCP_BPF_TXRX].recvmsg = tcp_bpf_recvmsg_parser;
+ }
+
+ static void tcp_bpf_check_v6_needs_rebuild(struct proto *ops)
+@@ -520,6 +562,10 @@ int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
+ int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4;
+ int config = psock->progs.msg_parser ? TCP_BPF_TX : TCP_BPF_BASE;
+
++ if (psock->progs.stream_verdict || psock->progs.skb_verdict) {
++ config = (config == TCP_BPF_TX) ? TCP_BPF_TXRX : TCP_BPF_RX;
++ }
++
+ if (restore) {
+ if (inet_csk_has_ulp(sk)) {
+ /* TLS does not have an unhash proto in SW cases,
+diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
+index 4a30deaa9a37f..8d2d4d652f6d4 100644
+--- a/net/ipv4/tcp_cubic.c
++++ b/net/ipv4/tcp_cubic.c
+@@ -328,8 +328,6 @@ static void cubictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
+ return;
+
+ if (tcp_in_slow_start(tp)) {
+- if (hystart && after(ack, ca->end_seq))
+- bictcp_hystart_reset(sk);
+ acked = tcp_slow_start(tp, acked);
+ if (!acked)
+ return;
+@@ -389,6 +387,9 @@ static void hystart_update(struct sock *sk, u32 delay)
+ struct bictcp *ca = inet_csk_ca(sk);
+ u32 threshold;
+
++ if (after(tp->snd_una, ca->end_seq))
++ bictcp_hystart_reset(sk);
++
+ if (hystart_detect & HYSTART_ACK_TRAIN) {
+ u32 now = bictcp_clock_us(sk);
+
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index 6d72f3ea48c4e..0492f6942778d 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -1562,7 +1562,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
+ return -ENOMEM;
+ }
+
+- if (skb_unclone(skb, gfp))
++ if (skb_unclone_keeptruesize(skb, gfp))
+ return -ENOMEM;
+
+ /* Get a new skb... force flag on. */
+@@ -1672,7 +1672,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
+ {
+ u32 delta_truesize;
+
+- if (skb_unclone(skb, GFP_ATOMIC))
++ if (skb_unclone_keeptruesize(skb, GFP_ATOMIC))
+ return -ENOMEM;
+
+ delta_truesize = __pskb_trim_head(skb, len);
+@@ -3184,7 +3184,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
+ cur_mss, GFP_ATOMIC))
+ return -ENOMEM; /* We'll try again later. */
+ } else {
+- if (skb_unclone(skb, GFP_ATOMIC))
++ if (skb_unclone_keeptruesize(skb, GFP_ATOMIC))
+ return -ENOMEM;
+
+ diff = tcp_skb_pcount(skb);
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 2fffcf2b54f3f..3f6823bdd31e5 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -917,7 +917,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+- if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) {
++ if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+@@ -1808,6 +1808,17 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc,
+ skb = skb_recv_udp(sk, 0, 1, &err);
+ if (!skb)
+ return err;
++
++ if (udp_lib_checksum_complete(skb)) {
++ __UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS,
++ IS_UDPLITE(sk));
++ __UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS,
++ IS_UDPLITE(sk));
++ atomic_inc(&sk->sk_drops);
++ kfree_skb(skb);
++ continue;
++ }
++
+ used = recv_actor(desc, skb, 0, skb->len);
+ if (used <= 0) {
+ if (!copied)
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index c6a90b7bbb70e..846037e73723f 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3110,6 +3110,9 @@ static void add_v4_addrs(struct inet6_dev *idev)
+ memcpy(&addr.s6_addr32[3], idev->dev->dev_addr + offset, 4);
+
+ if (idev->dev->flags&IFF_POINTOPOINT) {
++ if (idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_NONE)
++ return;
++
+ addr.s6_addr32[0] = htonl(0xfe800000);
+ scope = IFA_LINK;
+ plen = 64;
+diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
+index b5878bb8e419d..dab4a047590b7 100644
+--- a/net/ipv6/af_inet6.c
++++ b/net/ipv6/af_inet6.c
+@@ -521,31 +521,32 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
+ sin->sin6_family = AF_INET6;
+ sin->sin6_flowinfo = 0;
+ sin->sin6_scope_id = 0;
++ lock_sock(sk);
+ if (peer) {
+- if (!inet->inet_dport)
+- return -ENOTCONN;
+- if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
+- peer == 1)
++ if (!inet->inet_dport ||
++ (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
++ peer == 1)) {
++ release_sock(sk);
+ return -ENOTCONN;
++ }
+ sin->sin6_port = inet->inet_dport;
+ sin->sin6_addr = sk->sk_v6_daddr;
+ if (np->sndflow)
+ sin->sin6_flowinfo = np->flow_label;
+- BPF_CGROUP_RUN_SA_PROG_LOCK(sk, (struct sockaddr *)sin,
+- CGROUP_INET6_GETPEERNAME,
+- NULL);
++ BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
++ CGROUP_INET6_GETPEERNAME);
+ } else {
+ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr))
+ sin->sin6_addr = np->saddr;
+ else
+ sin->sin6_addr = sk->sk_v6_rcv_saddr;
+ sin->sin6_port = inet->inet_sport;
+- BPF_CGROUP_RUN_SA_PROG_LOCK(sk, (struct sockaddr *)sin,
+- CGROUP_INET6_GETSOCKNAME,
+- NULL);
++ BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
++ CGROUP_INET6_GETSOCKNAME);
+ }
+ sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr,
+ sk->sk_bound_dev_if);
++ release_sock(sk);
+ return sizeof(*sin);
+ }
+ EXPORT_SYMBOL(inet6_getname);
+@@ -1025,6 +1026,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
+ .ip6_mtu_from_fib6 = ip6_mtu_from_fib6,
+ .fib6_nh_init = fib6_nh_init,
+ .fib6_nh_release = fib6_nh_release,
++ .fib6_nh_release_dsts = fib6_nh_release_dsts,
+ .fib6_update_sernum = fib6_update_sernum_stub,
+ .fib6_rt_update = fib6_rt_update,
+ .ip6_del_rt = ip6_del_rt,
+diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
+index ed2f061b87685..f0bac6f7ab6bb 100644
+--- a/net/ipv6/esp6.c
++++ b/net/ipv6/esp6.c
+@@ -808,6 +808,12 @@ int esp6_input_done2(struct sk_buff *skb, int err)
+ struct tcphdr *th;
+
+ offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
++
++ if (offset < 0) {
++ err = -EINVAL;
++ goto out;
++ }
++
+ uh = (void *)(skb->data + offset);
+ th = (void *)(skb->data + offset);
+ hdr_len += offset;
+diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
+index 40f3e4f9f33a2..dcedfe29d9d93 100644
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -267,6 +267,7 @@ INDIRECT_CALLABLE_SCOPE int fib6_rule_action(struct fib_rule *rule,
+ }
+
+ INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress(struct fib_rule *rule,
++ int flags,
+ struct fib_lookup_arg *arg)
+ {
+ struct fib6_result *res = arg->result;
+@@ -294,8 +295,7 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress(struct fib_rule *rule,
+ return false;
+
+ suppress_route:
+- if (!(arg->flags & FIB_LOOKUP_NOREF))
+- ip6_rt_put(rt);
++ ip6_rt_put_flags(rt, flags);
+ return true;
+ }
+
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 2f044a49afa8c..ff4e83e2a5068 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -174,7 +174,7 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff
+ #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
+ /* Policy lookup after SNAT yielded a new policy */
+ if (skb_dst(skb)->xfrm) {
+- IPCB(skb)->flags |= IPSKB_REROUTED;
++ IP6CB(skb)->flags |= IP6SKB_REROUTED;
+ return dst_output(net, sk, skb);
+ }
+ #endif
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 9b9ef09382ab9..79cb5e5a4948b 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -3680,6 +3680,25 @@ void fib6_nh_release(struct fib6_nh *fib6_nh)
+ fib_nh_common_release(&fib6_nh->nh_common);
+ }
+
++void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
++{
++ int cpu;
++
++ if (!fib6_nh->rt6i_pcpu)
++ return;
++
++ for_each_possible_cpu(cpu) {
++ struct rt6_info *pcpu_rt, **ppcpu_rt;
++
++ ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu);
++ pcpu_rt = xchg(ppcpu_rt, NULL);
++ if (pcpu_rt) {
++ dst_dev_put(&pcpu_rt->dst);
++ dst_release(&pcpu_rt->dst);
++ }
++ }
++}
++
+ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
+ gfp_t gfp_flags,
+ struct netlink_ext_ack *extack)
+diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
+index 3adc5d9211ad6..d64855010948d 100644
+--- a/net/ipv6/seg6_iptunnel.c
++++ b/net/ipv6/seg6_iptunnel.c
+@@ -161,6 +161,14 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
+ hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
+
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
++
++ /* the control block has been erased, so we have to set the
++ * iif once again.
++ * We read the receiving interface index directly from the
++ * skb->skb_iif as it is done in the IPv4 receiving path (i.e.:
++ * ip_rcv_core(...)).
++ */
++ IP6CB(skb)->iif = skb->skb_iif;
+ }
+
+ hdr->nexthdr = NEXTHDR_ROUTING;
+diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
+index ef0c7a7c18e23..626cb53aa57ab 100644
+--- a/net/ipv6/sit.c
++++ b/net/ipv6/sit.c
+@@ -1933,7 +1933,6 @@ static int __net_init sit_init_net(struct net *net)
+ return 0;
+
+ err_reg_dev:
+- ipip6_dev_free(sitn->fb_tunnel_dev);
+ free_netdev(sitn->fb_tunnel_dev);
+ err_alloc_dev:
+ return err;
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index 8d785232b4796..be6dc64ece29f 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -1435,7 +1435,6 @@ do_udp_sendmsg:
+ if (!fl6.flowi6_oif)
+ fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex;
+
+- fl6.flowi6_mark = ipc6.sockc.mark;
+ fl6.flowi6_uid = sk->sk_uid;
+
+ if (msg->msg_controllen) {
+@@ -1471,6 +1470,7 @@ do_udp_sendmsg:
+ ipc6.opt = opt;
+
+ fl6.flowi6_proto = sk->sk_protocol;
++ fl6.flowi6_mark = ipc6.sockc.mark;
+ fl6.daddr = *daddr;
+ if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
+ fl6.saddr = np->saddr;
+diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
+index cce28e3b22323..ef729b1e39ea3 100644
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -9,7 +9,7 @@
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015-2017 Intel Deutschland GmbH
+- * Copyright (C) 2018-2020 Intel Corporation
++ * Copyright (C) 2018-2021 Intel Corporation
+ */
+
+ /**
+@@ -191,7 +191,8 @@ static void ieee80211_add_addbaext(struct ieee80211_sub_if_data *sdata,
+ sband = ieee80211_get_sband(sdata);
+ if (!sband)
+ return;
+- he_cap = ieee80211_get_he_iftype_cap(sband, sdata->vif.type);
++ he_cap = ieee80211_get_he_iftype_cap(sband,
++ ieee80211_vif_type_p2p(&sdata->vif));
+ if (!he_cap)
+ return;
+
+diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
+index 430a585875388..74a878f213d3e 100644
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -9,7 +9,7 @@
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015-2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2020 Intel Corporation
++ * Copyright (C) 2018 - 2021 Intel Corporation
+ */
+
+ #include <linux/ieee80211.h>
+@@ -106,7 +106,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+ mgmt->u.action.u.addba_req.start_seq_num =
+ cpu_to_le16(start_seq_num << 4);
+
+- ieee80211_tx_skb(sdata, skb);
++ ieee80211_tx_skb_tid(sdata, skb, tid);
+ }
+
+ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
+@@ -213,6 +213,8 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
+ struct txq_info *txqi;
+
++ lockdep_assert_held(&sta->ampdu_mlme.mtx);
++
+ if (!txq)
+ return;
+
+@@ -290,7 +292,6 @@ static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
+ ieee80211_assign_tid_tx(sta, tid, NULL);
+
+ ieee80211_agg_splice_finish(sta->sdata, tid);
+- ieee80211_agg_start_txq(sta, tid, false);
+
+ kfree_rcu(tid_tx, rcu_head);
+ }
+@@ -480,8 +481,7 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
+
+ /* send AddBA request */
+ ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+- tid_tx->dialog_token,
+- sta->tid_seq[tid] >> 4,
++ tid_tx->dialog_token, tid_tx->ssn,
+ buf_size, tid_tx->timeout);
+
+ WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
+@@ -523,6 +523,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
+
+ params.ssn = sta->tid_seq[tid] >> 4;
+ ret = drv_ampdu_action(local, sdata, &params);
++ tid_tx->ssn = params.ssn;
+ if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
+ return;
+ } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
+@@ -889,6 +890,7 @@ void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
+ {
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ bool send_delba = false;
++ bool start_txq = false;
+
+ ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
+ sta->sta.addr, tid);
+@@ -906,10 +908,14 @@ void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
+ send_delba = true;
+
+ ieee80211_remove_tid_tx(sta, tid);
++ start_txq = true;
+
+ unlock_sta:
+ spin_unlock_bh(&sta->lock);
+
++ if (start_txq)
++ ieee80211_agg_start_txq(sta, tid, false);
++
+ if (send_delba)
+ ieee80211_send_delba(sdata, sta->sta.addr, tid,
+ WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index d69b31c20fe28..d3f62fd12f0b5 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -80,7 +80,8 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
+ }
+
+ /* also validate MU-MIMO change */
+- monitor_sdata = rtnl_dereference(local->monitor_sdata);
++ monitor_sdata = wiphy_dereference(local->hw.wiphy,
++ local->monitor_sdata);
+
+ if (!monitor_sdata &&
+ (params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
+@@ -810,7 +811,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+
+ mutex_lock(&local->mtx);
+ if (local->use_chanctx) {
+- sdata = rtnl_dereference(local->monitor_sdata);
++ sdata = wiphy_dereference(local->hw.wiphy,
++ local->monitor_sdata);
+ if (sdata) {
+ ieee80211_vif_release_channel(sdata);
+ ret = ieee80211_vif_use_channel(sdata, chandef,
+@@ -2669,7 +2671,8 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
+ sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+- sdata = rtnl_dereference(local->monitor_sdata);
++ sdata = wiphy_dereference(local->hw.wiphy,
++ local->monitor_sdata);
+ if (!sdata)
+ return -EOPNOTSUPP;
+ }
+@@ -2729,7 +2732,8 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
+ mutex_unlock(&local->iflist_mtx);
+
+ if (has_monitor) {
+- sdata = rtnl_dereference(local->monitor_sdata);
++ sdata = wiphy_dereference(local->hw.wiphy,
++ local->monitor_sdata);
+ if (sdata) {
+ sdata->user_power_level = local->user_power_level;
+ if (txp_type != sdata->vif.bss_conf.txpower_type)
+diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
+index cd3731cbf6c68..c336267f4599c 100644
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -1219,8 +1219,11 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
+ {
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
+
+- if (local->in_reconfig)
++ /* In reconfig don't transmit now, but mark for waking later */
++ if (local->in_reconfig) {
++ set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txq->flags);
+ return;
++ }
+
+ if (!check_sdata_in_driver(sdata))
+ return;
+diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
+index 62c95597704b4..041859b5b71d0 100644
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -588,7 +588,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ */
+ if (local->suspended) {
+ WARN_ON(local->wowlan);
+- WARN_ON(rtnl_dereference(local->monitor_sdata));
++ WARN_ON(rcu_access_pointer(local->monitor_sdata));
+ return;
+ }
+
+@@ -932,6 +932,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
+ return 0;
+
+ ASSERT_RTNL();
++ lockdep_assert_wiphy(local->hw.wiphy);
+
+ if (local->monitor_sdata)
+ return 0;
+@@ -999,6 +1000,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
+ return;
+
+ ASSERT_RTNL();
++ lockdep_assert_wiphy(local->hw.wiphy);
+
+ mutex_lock(&local->iflist_mtx);
+
+diff --git a/net/mac80211/led.h b/net/mac80211/led.h
+index fb3aaa3c56069..b71a1428d883c 100644
+--- a/net/mac80211/led.h
++++ b/net/mac80211/led.h
+@@ -72,19 +72,19 @@ static inline void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
+ #endif
+
+ static inline void
+-ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes)
++ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, int bytes)
+ {
+ #ifdef CONFIG_MAC80211_LEDS
+- if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
++ if (atomic_read(&local->tpt_led_active))
+ local->tpt_led_trigger->tx_bytes += bytes;
+ #endif
+ }
+
+ static inline void
+-ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes)
++ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, int bytes)
+ {
+ #ifdef CONFIG_MAC80211_LEDS
+- if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
++ if (atomic_read(&local->tpt_led_active))
+ local->tpt_led_trigger->rx_bytes += bytes;
+ #endif
+ }
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index c0ea3b1aa9e1c..dd42d83dbe33e 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -2446,11 +2446,18 @@ static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
+ u16 tx_time)
+ {
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+- u16 tid = ieee80211_get_tid(hdr);
+- int ac = ieee80211_ac_from_tid(tid);
+- struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
++ u16 tid;
++ int ac;
++ struct ieee80211_sta_tx_tspec *tx_tspec;
+ unsigned long now = jiffies;
+
++ if (!ieee80211_is_data_qos(hdr->frame_control))
++ return;
++
++ tid = ieee80211_get_tid(hdr);
++ ac = ieee80211_ac_from_tid(tid);
++ tx_tspec = &ifmgd->tx_tspec[ac];
++
+ if (likely(!tx_tspec->admitted_time))
+ return;
+
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index c4071b015c188..1958e4d59b524 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -364,7 +364,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
+ * the compiler to think we have walked past the end of the
+ * struct member.
+ */
+- pos = (void *)&rthdr->it_optional[it_present - rthdr->it_optional];
++ pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
+
+ /* the order of the following fields is important */
+
+@@ -1952,7 +1952,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+ int keyid = rx->sta->ptk_idx;
+ sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
+
+- if (ieee80211_has_protected(fc)) {
++ if (ieee80211_has_protected(fc) &&
++ !(status->flag & RX_FLAG_IV_STRIPPED)) {
+ cs = rx->sta->cipher_scheme;
+ keyid = ieee80211_get_keyid(rx->skb, cs);
+
+@@ -4873,6 +4874,7 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
+ struct ieee80211_rate *rate = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ WARN_ON_ONCE(softirq_count() == 0);
+
+@@ -4969,9 +4971,9 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
+ if (!(status->flag & RX_FLAG_8023))
+ skb = ieee80211_rx_monitor(local, skb, rate);
+ if (skb) {
+- ieee80211_tpt_led_trig_rx(local,
+- ((struct ieee80211_hdr *)skb->data)->frame_control,
+- skb->len);
++ if ((status->flag & RX_FLAG_8023) ||
++ ieee80211_is_data_present(hdr->frame_control))
++ ieee80211_tpt_led_trig_rx(local, skb->len);
+
+ if (status->flag & RX_FLAG_8023)
+ __ieee80211_rx_handle_8023(hw, pubsta, skb, list);
+diff --git a/net/mac80211/s1g.c b/net/mac80211/s1g.c
+index 7e35ab5b61664..4141bc80cdfd6 100644
+--- a/net/mac80211/s1g.c
++++ b/net/mac80211/s1g.c
+@@ -104,9 +104,11 @@ ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
+
+ /* broadcast TWT not supported yet */
+ if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) {
+- le16p_replace_bits(&twt_agrt->req_type,
+- TWT_SETUP_CMD_REJECT,
+- IEEE80211_TWT_REQTYPE_SETUP_CMD);
++ twt_agrt->req_type &=
++ ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
++ twt_agrt->req_type |=
++ le16_encode_bits(TWT_SETUP_CMD_REJECT,
++ IEEE80211_TWT_REQTYPE_SETUP_CMD);
+ goto out;
+ }
+
+diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
+index ba27967820084..e7443fc4669c8 100644
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -199,6 +199,7 @@ struct tid_ampdu_tx {
+ u8 stop_initiator;
+ bool tx_stop;
+ u16 buf_size;
++ u16 ssn;
+
+ u16 failed_bar_ssn;
+ bool bar_pending;
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index 8921088a5df65..a499b07fee336 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1720,21 +1720,19 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
+ * Returns false if the frame couldn't be transmitted but was queued instead.
+ */
+ static bool __ieee80211_tx(struct ieee80211_local *local,
+- struct sk_buff_head *skbs, int led_len,
+- struct sta_info *sta, bool txpending)
++ struct sk_buff_head *skbs, struct sta_info *sta,
++ bool txpending)
+ {
+ struct ieee80211_tx_info *info;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_vif *vif;
+ struct sk_buff *skb;
+ bool result;
+- __le16 fc;
+
+ if (WARN_ON(skb_queue_empty(skbs)))
+ return true;
+
+ skb = skb_peek(skbs);
+- fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
+ info = IEEE80211_SKB_CB(skb);
+ sdata = vif_to_sdata(info->control.vif);
+ if (sta && !sta->uploaded)
+@@ -1768,8 +1766,6 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
+
+ result = ieee80211_tx_frags(local, vif, sta, skbs, txpending);
+
+- ieee80211_tpt_led_trig_tx(local, fc, led_len);
+-
+ WARN_ON_ONCE(!skb_queue_empty(skbs));
+
+ return result;
+@@ -1825,15 +1821,15 @@ static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ ieee80211_tx_result res = TX_CONTINUE;
+
++ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
++ CALL_TXH(ieee80211_tx_h_rate_ctrl);
++
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
+ __skb_queue_tail(&tx->skbs, tx->skb);
+ tx->skb = NULL;
+ goto txh_done;
+ }
+
+- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
+- CALL_TXH(ieee80211_tx_h_rate_ctrl);
+-
+ CALL_TXH(ieee80211_tx_h_michael_mic_add);
+ CALL_TXH(ieee80211_tx_h_sequence);
+ CALL_TXH(ieee80211_tx_h_fragment);
+@@ -1919,7 +1915,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ ieee80211_tx_result res_prepare;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ bool result = true;
+- int led_len;
+
+ if (unlikely(skb->len < 10)) {
+ dev_kfree_skb(skb);
+@@ -1927,7 +1922,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ }
+
+ /* initialises tx */
+- led_len = skb->len;
+ res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
+
+ if (unlikely(res_prepare == TX_DROP)) {
+@@ -1950,8 +1944,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ return true;
+
+ if (!invoke_tx_handlers_late(&tx))
+- result = __ieee80211_tx(local, &tx.skbs, led_len,
+- tx.sta, txpending);
++ result = __ieee80211_tx(local, &tx.skbs, tx.sta, txpending);
+
+ return result;
+ }
+@@ -4174,6 +4167,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+ struct sk_buff *next;
++ int len = skb->len;
+
+ if (unlikely(skb->len < ETH_HLEN)) {
+ kfree_skb(skb);
+@@ -4220,10 +4214,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
+ }
+ } else {
+ /* we cannot process non-linear frames on this path */
+- if (skb_linearize(skb)) {
+- kfree_skb(skb);
+- goto out;
+- }
++ if (skb_linearize(skb))
++ goto out_free;
+
+ /* the frame could be fragmented, software-encrypted, and other
+ * things so we cannot really handle checksum offload with it -
+@@ -4257,7 +4249,10 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
+ goto out;
+ out_free:
+ kfree_skb(skb);
++ len = 0;
+ out:
++ if (len)
++ ieee80211_tpt_led_trig_tx(local, len);
+ rcu_read_unlock();
+ }
+
+@@ -4395,8 +4390,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
+ }
+
+ static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
+- struct sk_buff *skb, int led_len,
+- struct sta_info *sta,
++ struct sk_buff *skb, struct sta_info *sta,
+ bool txpending)
+ {
+ struct ieee80211_local *local = sdata->local;
+@@ -4409,6 +4403,8 @@ static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
+ if (sta)
+ sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
+
++ ieee80211_tpt_led_trig_tx(local, skb->len);
++
+ if (ieee80211_queue_skb(local, sdata, sta, skb))
+ return true;
+
+@@ -4497,7 +4493,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
+ if (key)
+ info->control.hw_key = &key->conf;
+
+- ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
++ ieee80211_tx_8023(sdata, skb, sta, false);
+
+ return;
+
+@@ -4636,7 +4632,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
+ if (IS_ERR(sta) || (sta && !sta->uploaded))
+ sta = NULL;
+
+- result = ieee80211_tx_8023(sdata, skb, skb->len, sta, true);
++ result = ieee80211_tx_8023(sdata, skb, sta, true);
+ } else {
+ struct sk_buff_head skbs;
+
+@@ -4646,7 +4642,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
+ hdr = (struct ieee80211_hdr *)skb->data;
+ sta = sta_info_get(sdata, hdr->addr1);
+
+- result = __ieee80211_tx(local, &skbs, skb->len, sta, true);
++ result = __ieee80211_tx(local, &skbs, sta, true);
+ }
+
+ return result;
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index 49cb96d251695..2fe71ed9137b0 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -796,7 +796,7 @@ static void __iterate_interfaces(struct ieee80211_local *local,
+
+ sdata = rcu_dereference_check(local->monitor_sdata,
+ lockdep_is_held(&local->iflist_mtx) ||
+- lockdep_rtnl_is_held());
++ lockdep_is_held(&local->hw.wiphy->mtx));
+ if (sdata &&
+ (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
+ sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+@@ -943,7 +943,12 @@ static void ieee80211_parse_extension_element(u32 *crc,
+ struct ieee802_11_elems *elems)
+ {
+ const void *data = elem->data + 1;
+- u8 len = elem->datalen - 1;
++ u8 len;
++
++ if (!elem->datalen)
++ return;
++
++ len = elem->datalen - 1;
+
+ switch (elem->data[0]) {
+ case WLAN_EID_EXT_HE_MU_EDCA:
+@@ -2379,7 +2384,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
+
+ /* add interfaces */
+- sdata = rtnl_dereference(local->monitor_sdata);
++ sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
+ if (sdata) {
+ /* in HW restart it exists already */
+ WARN_ON(local->resuming);
+@@ -2424,7 +2429,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
+ WARN_ON(drv_add_chanctx(local, ctx));
+ mutex_unlock(&local->chanctx_mtx);
+
+- sdata = rtnl_dereference(local->monitor_sdata);
++ sdata = wiphy_dereference(local->hw.wiphy,
++ local->monitor_sdata);
+ if (sdata && ieee80211_sdata_running(sdata))
+ ieee80211_assign_chanctx(local, sdata);
+ }
+diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
+index 9ea6004abe1be..62c6733e07923 100644
+--- a/net/mac80211/wme.c
++++ b/net/mac80211/wme.c
+@@ -143,7 +143,6 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
+ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, struct sk_buff *skb)
+ {
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mac80211_qos_map *qos_map;
+ bool qos;
+
+@@ -156,7 +155,7 @@ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+ else
+ qos = false;
+
+- if (!qos || (info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER)) {
++ if (!qos) {
+ skb->priority = 0; /* required for correct WPA/11i MIC */
+ return IEEE80211_AC_BE;
+ }
+diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c
+index a9526ac29dffe..85cc1a28cbe9f 100644
+--- a/net/mctp/af_mctp.c
++++ b/net/mctp/af_mctp.c
+@@ -30,6 +30,12 @@ static int mctp_release(struct socket *sock)
+ return 0;
+ }
+
++/* Generic sockaddr checks, padding checks only so far */
++static bool mctp_sockaddr_is_ok(const struct sockaddr_mctp *addr)
++{
++ return !addr->__smctp_pad0 && !addr->__smctp_pad1;
++}
++
+ static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
+ {
+ struct sock *sk = sock->sk;
+@@ -49,6 +55,9 @@ static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
+ /* it's a valid sockaddr for MCTP, cast and do protocol checks */
+ smctp = (struct sockaddr_mctp *)addr;
+
++ if (!mctp_sockaddr_is_ok(smctp))
++ return -EINVAL;
++
+ lock_sock(sk);
+
+ /* TODO: allow rebind */
+@@ -83,6 +92,8 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+ return -EINVAL;
+ if (addr->smctp_family != AF_MCTP)
+ return -EINVAL;
++ if (!mctp_sockaddr_is_ok(addr))
++ return -EINVAL;
+ if (addr->smctp_tag & ~(MCTP_TAG_MASK | MCTP_TAG_OWNER))
+ return -EINVAL;
+
+@@ -172,11 +183,13 @@ static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+
+ addr = msg->msg_name;
+ addr->smctp_family = AF_MCTP;
++ addr->__smctp_pad0 = 0;
+ addr->smctp_network = cb->net;
+ addr->smctp_addr.s_addr = hdr->src;
+ addr->smctp_type = type;
+ addr->smctp_tag = hdr->flags_seq_tag &
+ (MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
++ addr->__smctp_pad1 = 0;
+ msg->msg_namelen = sizeof(*addr);
+ }
+
+diff --git a/net/mctp/route.c b/net/mctp/route.c
+index 5ca186d53cb0f..fb1bf4ec85296 100644
+--- a/net/mctp/route.c
++++ b/net/mctp/route.c
+@@ -760,7 +760,7 @@ static int mctp_route_add(struct mctp_dev *mdev, mctp_eid_t daddr_start,
+ }
+
+ static int mctp_route_remove(struct mctp_dev *mdev, mctp_eid_t daddr_start,
+- unsigned int daddr_extent)
++ unsigned int daddr_extent, unsigned char type)
+ {
+ struct net *net = dev_net(mdev->dev);
+ struct mctp_route *rt, *tmp;
+@@ -777,7 +777,8 @@ static int mctp_route_remove(struct mctp_dev *mdev, mctp_eid_t daddr_start,
+
+ list_for_each_entry_safe(rt, tmp, &net->mctp.routes, list) {
+ if (rt->dev == mdev &&
+- rt->min == daddr_start && rt->max == daddr_end) {
++ rt->min == daddr_start && rt->max == daddr_end &&
++ rt->type == type) {
+ list_del_rcu(&rt->list);
+ /* TODO: immediate RTM_DELROUTE */
+ mctp_route_release(rt);
+@@ -795,7 +796,7 @@ int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
+
+ int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr)
+ {
+- return mctp_route_remove(mdev, addr, 0);
++ return mctp_route_remove(mdev, addr, 0, RTN_LOCAL);
+ }
+
+ /* removes all entries for a given device */
+@@ -975,7 +976,7 @@ static int mctp_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
+ if (rtm->rtm_type != RTN_UNICAST)
+ return -EINVAL;
+
+- rc = mctp_route_remove(mdev, daddr_start, rtm->rtm_dst_len);
++ rc = mctp_route_remove(mdev, daddr_start, rtm->rtm_dst_len, RTN_UNICAST);
+ return rc;
+ }
+
+diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
+index ffeb2df8be7ae..6e587feb705c4 100644
+--- a/net/mpls/af_mpls.c
++++ b/net/mpls/af_mpls.c
+@@ -1491,22 +1491,52 @@ static void mpls_dev_destroy_rcu(struct rcu_head *head)
+ kfree(mdev);
+ }
+
+-static void mpls_ifdown(struct net_device *dev, int event)
++static int mpls_ifdown(struct net_device *dev, int event)
+ {
+ struct mpls_route __rcu **platform_label;
+ struct net *net = dev_net(dev);
+- u8 alive, deleted;
+ unsigned index;
+
+ platform_label = rtnl_dereference(net->mpls.platform_label);
+ for (index = 0; index < net->mpls.platform_labels; index++) {
+ struct mpls_route *rt = rtnl_dereference(platform_label[index]);
++ bool nh_del = false;
++ u8 alive = 0;
+
+ if (!rt)
+ continue;
+
+- alive = 0;
+- deleted = 0;
++ if (event == NETDEV_UNREGISTER) {
++ u8 deleted = 0;
++
++ for_nexthops(rt) {
++ struct net_device *nh_dev =
++ rtnl_dereference(nh->nh_dev);
++
++ if (!nh_dev || nh_dev == dev)
++ deleted++;
++ if (nh_dev == dev)
++ nh_del = true;
++ } endfor_nexthops(rt);
++
++ /* if there are no more nexthops, delete the route */
++ if (deleted == rt->rt_nhn) {
++ mpls_route_update(net, index, NULL, NULL);
++ continue;
++ }
++
++ if (nh_del) {
++ size_t size = sizeof(*rt) + rt->rt_nhn *
++ rt->rt_nh_size;
++ struct mpls_route *orig = rt;
++
++ rt = kmalloc(size, GFP_KERNEL);
++ if (!rt)
++ return -ENOMEM;
++ memcpy(rt, orig, size);
++ }
++ }
++
+ change_nexthops(rt) {
+ unsigned int nh_flags = nh->nh_flags;
+
+@@ -1530,16 +1560,15 @@ static void mpls_ifdown(struct net_device *dev, int event)
+ next:
+ if (!(nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)))
+ alive++;
+- if (!rtnl_dereference(nh->nh_dev))
+- deleted++;
+ } endfor_nexthops(rt);
+
+ WRITE_ONCE(rt->rt_nhn_alive, alive);
+
+- /* if there are no more nexthops, delete the route */
+- if (event == NETDEV_UNREGISTER && deleted == rt->rt_nhn)
+- mpls_route_update(net, index, NULL, NULL);
++ if (nh_del)
++ mpls_route_update(net, index, rt, NULL);
+ }
++
++ return 0;
+ }
+
+ static void mpls_ifup(struct net_device *dev, unsigned int flags)
+@@ -1597,8 +1626,12 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
+ return NOTIFY_OK;
+
+ switch (event) {
++ int err;
++
+ case NETDEV_DOWN:
+- mpls_ifdown(dev, event);
++ err = mpls_ifdown(dev, event);
++ if (err)
++ return notifier_from_errno(err);
+ break;
+ case NETDEV_UP:
+ flags = dev_get_flags(dev);
+@@ -1609,13 +1642,18 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
+ break;
+ case NETDEV_CHANGE:
+ flags = dev_get_flags(dev);
+- if (flags & (IFF_RUNNING | IFF_LOWER_UP))
++ if (flags & (IFF_RUNNING | IFF_LOWER_UP)) {
+ mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);
+- else
+- mpls_ifdown(dev, event);
++ } else {
++ err = mpls_ifdown(dev, event);
++ if (err)
++ return notifier_from_errno(err);
++ }
+ break;
+ case NETDEV_UNREGISTER:
+- mpls_ifdown(dev, event);
++ err = mpls_ifdown(dev, event);
++ if (err)
++ return notifier_from_errno(err);
+ mdev = mpls_dev_get(dev);
+ if (mdev) {
+ mpls_dev_sysctl_unregister(dev, mdev);
+@@ -1626,8 +1664,6 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
+ case NETDEV_CHANGENAME:
+ mdev = mpls_dev_get(dev);
+ if (mdev) {
+- int err;
+-
+ mpls_dev_sysctl_unregister(dev, mdev);
+ err = mpls_dev_sysctl_register(dev, mdev);
+ if (err)
+diff --git a/net/mptcp/options.c b/net/mptcp/options.c
+index f0f22eb4fd5f7..0966855a7c251 100644
+--- a/net/mptcp/options.c
++++ b/net/mptcp/options.c
+@@ -422,28 +422,6 @@ bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb,
+ return false;
+ }
+
+-/* MP_JOIN client subflow must wait for 4th ack before sending any data:
+- * TCP can't schedule delack timer before the subflow is fully established.
+- * MPTCP uses the delack timer to do 3rd ack retransmissions
+- */
+-static void schedule_3rdack_retransmission(struct sock *sk)
+-{
+- struct inet_connection_sock *icsk = inet_csk(sk);
+- struct tcp_sock *tp = tcp_sk(sk);
+- unsigned long timeout;
+-
+- /* reschedule with a timeout above RTT, as we must look only for drop */
+- if (tp->srtt_us)
+- timeout = tp->srtt_us << 1;
+- else
+- timeout = TCP_TIMEOUT_INIT;
+-
+- WARN_ON_ONCE(icsk->icsk_ack.pending & ICSK_ACK_TIMER);
+- icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
+- icsk->icsk_ack.timeout = timeout;
+- sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
+-}
+-
+ static void clear_3rdack_retransmission(struct sock *sk)
+ {
+ struct inet_connection_sock *icsk = inet_csk(sk);
+@@ -526,7 +504,15 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
+ *size = TCPOLEN_MPTCP_MPJ_ACK;
+ pr_debug("subflow=%p", subflow);
+
+- schedule_3rdack_retransmission(sk);
++ /* we can use the full delegate action helper only from BH context
++ * If we are in process context - sk is flushing the backlog at
++ * socket lock release time - just set the appropriate flag, will
++ * be handled by the release callback
++ */
++ if (sock_owned_by_user(sk))
++ set_bit(MPTCP_DELEGATE_ACK, &subflow->delegated_status);
++ else
++ mptcp_subflow_delegate(subflow, MPTCP_DELEGATE_ACK);
+ return true;
+ }
+ return false;
+@@ -1019,11 +1005,9 @@ static void ack_update_msk(struct mptcp_sock *msk,
+ old_snd_una = msk->snd_una;
+ new_snd_una = mptcp_expand_seq(old_snd_una, mp_opt->data_ack, mp_opt->ack64);
+
+- /* ACK for data not even sent yet and even above recovery bound? Ignore.*/
+- if (unlikely(after64(new_snd_una, snd_nxt))) {
+- if (!msk->recovery || after64(new_snd_una, msk->recovery_snd_nxt))
+- new_snd_una = old_snd_una;
+- }
++ /* ACK for data not even sent yet? Ignore.*/
++ if (unlikely(after64(new_snd_una, snd_nxt)))
++ new_snd_una = old_snd_una;
+
+ new_wnd_end = new_snd_una + tcp_sk(ssk)->snd_wnd;
+
+diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
+index 050eea231528b..b79251a36dcbc 100644
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -700,6 +700,9 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
+
+ msk_owned_by_me(msk);
+
++ if (sk->sk_state == TCP_LISTEN)
++ return;
++
+ if (!rm_list->nr)
+ return;
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index d073b21113828..4c889552cde77 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1505,6 +1505,32 @@ static void mptcp_push_release(struct sock *sk, struct sock *ssk,
+ release_sock(ssk);
+ }
+
++static void mptcp_update_post_push(struct mptcp_sock *msk,
++ struct mptcp_data_frag *dfrag,
++ u32 sent)
++{
++ u64 snd_nxt_new = dfrag->data_seq;
++
++ dfrag->already_sent += sent;
++
++ msk->snd_burst -= sent;
++ msk->tx_pending_data -= sent;
++
++ snd_nxt_new += dfrag->already_sent;
++
++ /* snd_nxt_new can be smaller than snd_nxt in case mptcp
++ * is recovering after a failover. In that event, this re-sends
++ * old segments.
++ *
++ * Thus compute snd_nxt_new candidate based on
++ * the dfrag->data_seq that was sent and the data
++ * that has been handed to the subflow for transmission
++ * and skip update in case it was old dfrag.
++ */
++ if (likely(after64(snd_nxt_new, msk->snd_nxt)))
++ msk->snd_nxt = snd_nxt_new;
++}
++
+ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
+ {
+ struct sock *prev_ssk = NULL, *ssk = NULL;
+@@ -1523,7 +1549,7 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
+ int ret = 0;
+
+ prev_ssk = ssk;
+- mptcp_flush_join_list(msk);
++ __mptcp_flush_join_list(msk);
+ ssk = mptcp_subflow_get_send(msk);
+
+ /* First check. If the ssk has changed since
+@@ -1548,12 +1574,10 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
+ }
+
+ info.sent += ret;
+- dfrag->already_sent += ret;
+- msk->snd_nxt += ret;
+- msk->snd_burst -= ret;
+- msk->tx_pending_data -= ret;
+ copied += ret;
+ len -= ret;
++
++ mptcp_update_post_push(msk, dfrag, ret);
+ }
+ WRITE_ONCE(msk->first_pending, mptcp_send_next(sk));
+ }
+@@ -1597,7 +1621,8 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk)
+ if (!xmit_ssk)
+ goto out;
+ if (xmit_ssk != ssk) {
+- mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk));
++ mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk),
++ MPTCP_DELEGATE_SEND);
+ goto out;
+ }
+
+@@ -1606,13 +1631,11 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk)
+ goto out;
+
+ info.sent += ret;
+- dfrag->already_sent += ret;
+- msk->snd_nxt += ret;
+- msk->snd_burst -= ret;
+- msk->tx_pending_data -= ret;
+ copied += ret;
+ len -= ret;
+ first = false;
++
++ mptcp_update_post_push(msk, dfrag, ret);
+ }
+ WRITE_ONCE(msk->first_pending, mptcp_send_next(sk));
+ }
+@@ -2183,15 +2206,12 @@ bool __mptcp_retransmit_pending_data(struct sock *sk)
+ return false;
+ }
+
+- /* will accept ack for reijected data before re-sending them */
+- if (!msk->recovery || after64(msk->snd_nxt, msk->recovery_snd_nxt))
+- msk->recovery_snd_nxt = msk->snd_nxt;
++ msk->recovery_snd_nxt = msk->snd_nxt;
+ msk->recovery = true;
+ mptcp_data_unlock(sk);
+
+ msk->first_pending = rtx_head;
+ msk->tx_pending_data += msk->snd_nxt - rtx_head->data_seq;
+- msk->snd_nxt = rtx_head->data_seq;
+ msk->snd_burst = 0;
+
+ /* be sure to clear the "sent status" on all re-injected fragments */
+@@ -2881,7 +2901,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
+ */
+ if (WARN_ON_ONCE(!new_mptcp_sock)) {
+ tcp_sk(newsk)->is_mptcp = 0;
+- return newsk;
++ goto out;
+ }
+
+ /* acquire the 2nd reference for the owning socket */
+@@ -2893,6 +2913,8 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
+ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK);
+ }
+
++out:
++ newsk->sk_kern_sock = kern;
+ return newsk;
+ }
+
+@@ -2940,7 +2962,7 @@ void __mptcp_check_push(struct sock *sk, struct sock *ssk)
+ if (xmit_ssk == ssk)
+ __mptcp_subflow_push_pending(sk, ssk);
+ else if (xmit_ssk)
+- mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk));
++ mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk), MPTCP_DELEGATE_SEND);
+ } else {
+ set_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags);
+ }
+@@ -2994,18 +3016,50 @@ static void mptcp_release_cb(struct sock *sk)
+ __mptcp_update_rmem(sk);
+ }
+
++/* MP_JOIN client subflow must wait for 4th ack before sending any data:
++ * TCP can't schedule delack timer before the subflow is fully established.
++ * MPTCP uses the delack timer to do 3rd ack retransmissions
++ */
++static void schedule_3rdack_retransmission(struct sock *ssk)
++{
++ struct inet_connection_sock *icsk = inet_csk(ssk);
++ struct tcp_sock *tp = tcp_sk(ssk);
++ unsigned long timeout;
++
++ if (mptcp_subflow_ctx(ssk)->fully_established)
++ return;
++
++ /* reschedule with a timeout above RTT, as we must look only for drop */
++ if (tp->srtt_us)
++ timeout = usecs_to_jiffies(tp->srtt_us >> (3 - 1));
++ else
++ timeout = TCP_TIMEOUT_INIT;
++ timeout += jiffies;
++
++ WARN_ON_ONCE(icsk->icsk_ack.pending & ICSK_ACK_TIMER);
++ icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
++ icsk->icsk_ack.timeout = timeout;
++ sk_reset_timer(ssk, &icsk->icsk_delack_timer, timeout);
++}
++
+ void mptcp_subflow_process_delegated(struct sock *ssk)
+ {
+ struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
+ struct sock *sk = subflow->conn;
+
+- mptcp_data_lock(sk);
+- if (!sock_owned_by_user(sk))
+- __mptcp_subflow_push_pending(sk, ssk);
+- else
+- set_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags);
+- mptcp_data_unlock(sk);
+- mptcp_subflow_delegated_done(subflow);
++ if (test_bit(MPTCP_DELEGATE_SEND, &subflow->delegated_status)) {
++ mptcp_data_lock(sk);
++ if (!sock_owned_by_user(sk))
++ __mptcp_subflow_push_pending(sk, ssk);
++ else
++ set_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags);
++ mptcp_data_unlock(sk);
++ mptcp_subflow_delegated_done(subflow, MPTCP_DELEGATE_SEND);
++ }
++ if (test_bit(MPTCP_DELEGATE_ACK, &subflow->delegated_status)) {
++ schedule_3rdack_retransmission(ssk);
++ mptcp_subflow_delegated_done(subflow, MPTCP_DELEGATE_ACK);
++ }
+ }
+
+ static int mptcp_hash(struct sock *sk)
+diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
+index dc984676c5eb1..82c5dc4d6b49d 100644
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -401,6 +401,7 @@ struct mptcp_delegated_action {
+ DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
+
+ #define MPTCP_DELEGATE_SEND 0
++#define MPTCP_DELEGATE_ACK 1
+
+ /* MPTCP subflow context */
+ struct mptcp_subflow_context {
+@@ -506,23 +507,23 @@ static inline void mptcp_add_pending_subflow(struct mptcp_sock *msk,
+
+ void mptcp_subflow_process_delegated(struct sock *ssk);
+
+-static inline void mptcp_subflow_delegate(struct mptcp_subflow_context *subflow)
++static inline void mptcp_subflow_delegate(struct mptcp_subflow_context *subflow, int action)
+ {
+ struct mptcp_delegated_action *delegated;
+ bool schedule;
+
++ /* the caller held the subflow bh socket lock */
++ lockdep_assert_in_softirq();
++
+ /* The implied barrier pairs with mptcp_subflow_delegated_done(), and
+ * ensures the below list check sees list updates done prior to status
+ * bit changes
+ */
+- if (!test_and_set_bit(MPTCP_DELEGATE_SEND, &subflow->delegated_status)) {
++ if (!test_and_set_bit(action, &subflow->delegated_status)) {
+ /* still on delegated list from previous scheduling */
+ if (!list_empty(&subflow->delegated_node))
+ return;
+
+- /* the caller held the subflow bh socket lock */
+- lockdep_assert_in_softirq();
+-
+ delegated = this_cpu_ptr(&mptcp_delegated_actions);
+ schedule = list_empty(&delegated->head);
+ list_add_tail(&subflow->delegated_node, &delegated->head);
+@@ -547,16 +548,16 @@ mptcp_subflow_delegated_next(struct mptcp_delegated_action *delegated)
+
+ static inline bool mptcp_subflow_has_delegated_action(const struct mptcp_subflow_context *subflow)
+ {
+- return test_bit(MPTCP_DELEGATE_SEND, &subflow->delegated_status);
++ return !!READ_ONCE(subflow->delegated_status);
+ }
+
+-static inline void mptcp_subflow_delegated_done(struct mptcp_subflow_context *subflow)
++static inline void mptcp_subflow_delegated_done(struct mptcp_subflow_context *subflow, int action)
+ {
+ /* pairs with mptcp_subflow_delegate, ensures delegate_node is updated before
+ * touching the status bit
+ */
+ smp_wmb();
+- clear_bit(MPTCP_DELEGATE_SEND, &subflow->delegated_status);
++ clear_bit(action, &subflow->delegated_status);
+ }
+
+ int mptcp_is_enabled(const struct net *net);
+diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
+index 8c03afac5ca03..4bb305342fcc7 100644
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -523,7 +523,6 @@ static bool mptcp_supported_sockopt(int level, int optname)
+ case TCP_NODELAY:
+ case TCP_THIN_LINEAR_TIMEOUTS:
+ case TCP_CONGESTION:
+- case TCP_ULP:
+ case TCP_CORK:
+ case TCP_KEEPIDLE:
+ case TCP_KEEPINTVL:
+diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
+index ba9ae482141b0..dda8b76b77988 100644
+--- a/net/ncsi/ncsi-cmd.c
++++ b/net/ncsi/ncsi-cmd.c
+@@ -18,6 +18,8 @@
+ #include "internal.h"
+ #include "ncsi-pkt.h"
+
++static const int padding_bytes = 26;
++
+ u32 ncsi_calculate_checksum(unsigned char *data, int len)
+ {
+ u32 checksum = 0;
+@@ -213,12 +215,17 @@ static int ncsi_cmd_handler_oem(struct sk_buff *skb,
+ {
+ struct ncsi_cmd_oem_pkt *cmd;
+ unsigned int len;
++ int payload;
++ /* NC-SI spec DSP_0222_1.2.0, section 8.2.2.2
++ * requires payload to be padded with 0 to
++ * 32-bit boundary before the checksum field.
++ * Ensure the padding bytes are accounted for in
++ * skb allocation
++ */
+
++ payload = ALIGN(nca->payload, 4);
+ len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
+- if (nca->payload < 26)
+- len += 26;
+- else
+- len += nca->payload;
++ len += max(payload, padding_bytes);
+
+ cmd = skb_put_zero(skb, len);
+ memcpy(&cmd->mfr_id, nca->data, nca->payload);
+@@ -272,6 +279,7 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
+ struct net_device *dev = nd->dev;
+ int hlen = LL_RESERVED_SPACE(dev);
+ int tlen = dev->needed_tailroom;
++ int payload;
+ int len = hlen + tlen;
+ struct sk_buff *skb;
+ struct ncsi_request *nr;
+@@ -281,14 +289,14 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
+ return NULL;
+
+ /* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
++ * Payload needs padding so that the checksum field following payload is
++ * aligned to 32-bit boundary.
+ * The packet needs padding if its payload is less than 26 bytes to
+ * meet 64 bytes minimal ethernet frame length.
+ */
+ len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
+- if (nca->payload < 26)
+- len += 26;
+- else
+- len += nca->payload;
++ payload = ALIGN(nca->payload, 4);
++ len += max(payload, padding_bytes);
+
+ /* Allocate skb */
+ skb = alloc_skb(len, GFP_ATOMIC);
+diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
+index 128690c512dff..393058a43aa73 100644
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -1964,7 +1964,6 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
+ struct ip_vs_proto_data *pd;
+ struct ip_vs_conn *cp;
+ int ret, pkts;
+- int conn_reuse_mode;
+ struct sock *sk;
+
+ /* Already marked as IPVS request or reply? */
+@@ -2041,15 +2040,16 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
+ cp = INDIRECT_CALL_1(pp->conn_in_get, ip_vs_conn_in_get_proto,
+ ipvs, af, skb, &iph);
+
+- conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
+- if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {
++ if (!iph.fragoffs && is_new_conn(skb, &iph) && cp) {
++ int conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
+ bool old_ct = false, resched = false;
+
+ if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
+ unlikely(!atomic_read(&cp->dest->weight))) {
+ resched = true;
+ old_ct = ip_vs_conn_uses_old_conntrack(cp, skb);
+- } else if (is_new_conn_expected(cp, conn_reuse_mode)) {
++ } else if (conn_reuse_mode &&
++ is_new_conn_expected(cp, conn_reuse_mode)) {
+ old_ct = ip_vs_conn_uses_old_conntrack(cp, skb);
+ if (!atomic_read(&cp->n_control)) {
+ resched = true;
+diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
+index 770a63103c7a4..4712a90a1820c 100644
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -684,7 +684,7 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
+
+ tstamp = nf_conn_tstamp_find(ct);
+ if (tstamp) {
+- s32 timeout = ct->timeout - nfct_time_stamp;
++ s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
+
+ tstamp->stop = ktime_get_real_ns();
+ if (timeout < 0)
+@@ -1036,7 +1036,7 @@ static int nf_ct_resolve_clash_harder(struct sk_buff *skb, u32 repl_idx)
+ }
+
+ /* We want the clashing entry to go away real soon: 1 second timeout. */
+- loser_ct->timeout = nfct_time_stamp + HZ;
++ WRITE_ONCE(loser_ct->timeout, nfct_time_stamp + HZ);
+
+ /* IPS_NAT_CLASH removes the entry automatically on the first
+ * reply. Also prevents UDP tracker from moving the entry to
+@@ -1560,7 +1560,7 @@ __nf_conntrack_alloc(struct net *net,
+ /* save hash for reusing when confirming */
+ *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash;
+ ct->status = 0;
+- ct->timeout = 0;
++ WRITE_ONCE(ct->timeout, 0);
+ write_pnet(&ct->ct_net, net);
+ memset(&ct->__nfct_init_offset, 0,
+ offsetof(struct nf_conn, proto) -
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index f1e5443fe7c74..81d03acf68d4d 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -1011,11 +1011,9 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
+ CTA_TUPLE_REPLY,
+ filter->family,
+ &filter->zone,
+- filter->orig_flags);
+- if (err < 0) {
+- err = -EINVAL;
++ filter->reply_flags);
++ if (err < 0)
+ goto err_filter;
+- }
+ }
+
+ return filter;
+@@ -2000,7 +1998,7 @@ static int ctnetlink_change_timeout(struct nf_conn *ct,
+
+ if (timeout > INT_MAX)
+ timeout = INT_MAX;
+- ct->timeout = nfct_time_stamp + (u32)timeout;
++ WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout);
+
+ if (test_bit(IPS_DYING_BIT, &ct->status))
+ return -ETIME;
+diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
+index f8e3c0d2602f6..3b516cffc779b 100644
+--- a/net/netfilter/nf_conntrack_proto_udp.c
++++ b/net/netfilter/nf_conntrack_proto_udp.c
+@@ -104,10 +104,13 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
+ */
+ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+ unsigned long extra = timeouts[UDP_CT_UNREPLIED];
++ bool stream = false;
+
+ /* Still active after two seconds? Extend timeout. */
+- if (time_after(jiffies, ct->proto.udp.stream_ts))
++ if (time_after(jiffies, ct->proto.udp.stream_ts)) {
+ extra = timeouts[UDP_CT_REPLIED];
++ stream = true;
++ }
+
+ nf_ct_refresh_acct(ct, ctinfo, skb, extra);
+
+@@ -116,7 +119,7 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
+ return NF_ACCEPT;
+
+ /* Also, more likely to be important, and not a probe */
+- if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
++ if (stream && !test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
+ nf_conntrack_event_cache(IPCT_ASSURED, ct);
+ } else {
+ nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[UDP_CT_UNREPLIED]);
+diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
+index 87a7388b6c894..ed37bb9b4e588 100644
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -201,8 +201,8 @@ static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
+ if (timeout < 0)
+ timeout = 0;
+
+- if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
+- ct->timeout = nfct_time_stamp + timeout;
++ if (nf_flow_timeout_delta(READ_ONCE(ct->timeout)) > (__s32)timeout)
++ WRITE_ONCE(ct->timeout, nfct_time_stamp + timeout);
+ }
+
+ static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index d6bf1b2cd541b..b561e0a44a45f 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -65,11 +65,11 @@ static void nf_flow_rule_lwt_match(struct nf_flow_match *match,
+ sizeof(struct in6_addr));
+ if (memcmp(&key->enc_ipv6.src, &in6addr_any,
+ sizeof(struct in6_addr)))
+- memset(&key->enc_ipv6.src, 0xff,
++ memset(&mask->enc_ipv6.src, 0xff,
+ sizeof(struct in6_addr));
+ if (memcmp(&key->enc_ipv6.dst, &in6addr_any,
+ sizeof(struct in6_addr)))
+- memset(&key->enc_ipv6.dst, 0xff,
++ memset(&mask->enc_ipv6.dst, 0xff,
+ sizeof(struct in6_addr));
+ enc_keys |= BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS);
+ key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
+index 4c3fbaaeb1030..4acc4b8e9fe5a 100644
+--- a/net/netfilter/nfnetlink_queue.c
++++ b/net/netfilter/nfnetlink_queue.c
+@@ -560,7 +560,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
+ goto nla_put_failure;
+
+ if (indev && entskb->dev &&
+- entskb->mac_header != entskb->network_header) {
++ skb_mac_header_was_set(entskb)) {
+ struct nfqnl_msg_packet_hw phw;
+ int len;
+
+diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
+index 6ba3256fa8449..87f3af4645d9c 100644
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -198,17 +198,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
+ return -EBUSY;
+
+ priv->op = ntohl(nla_get_be32(tb[NFTA_DYNSET_OP]));
+- switch (priv->op) {
+- case NFT_DYNSET_OP_ADD:
+- case NFT_DYNSET_OP_DELETE:
+- break;
+- case NFT_DYNSET_OP_UPDATE:
+- if (!(set->flags & NFT_SET_TIMEOUT))
+- return -EOPNOTSUPP;
+- break;
+- default:
++ if (priv->op > NFT_DYNSET_OP_DELETE)
+ return -EOPNOTSUPP;
+- }
+
+ timeout = 0;
+ if (tb[NFTA_DYNSET_TIMEOUT] != NULL) {
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index af4ee874a067c..dbe1f2e7dd9ed 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -236,7 +236,7 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
+
+ tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
+ if (!tcph)
+- return;
++ goto err;
+
+ opt = (u8 *)tcph;
+ for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
+@@ -251,16 +251,16 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
+ continue;
+
+ if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
+- return;
++ goto err;
+
+ if (skb_ensure_writable(pkt->skb,
+ nft_thoff(pkt) + i + priv->len))
+- return;
++ goto err;
+
+ tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
+ &tcphdr_len);
+ if (!tcph)
+- return;
++ goto err;
+
+ offset = i + priv->offset;
+
+@@ -303,6 +303,9 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
+
+ return;
+ }
++ return;
++err:
++ regs->verdict.code = NFT_BREAK;
+ }
+
+ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
+diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c
+index e517663e0cd17..6f4116e729581 100644
+--- a/net/netfilter/nft_set_pipapo_avx2.c
++++ b/net/netfilter/nft_set_pipapo_avx2.c
+@@ -886,7 +886,7 @@ static int nft_pipapo_avx2_lookup_8b_6(unsigned long *map, unsigned long *fill,
+ NFT_PIPAPO_AVX2_BUCKET_LOAD8(4, lt, 4, pkt[4], bsize);
+
+ NFT_PIPAPO_AVX2_AND(5, 0, 1);
+- NFT_PIPAPO_AVX2_BUCKET_LOAD8(6, lt, 6, pkt[5], bsize);
++ NFT_PIPAPO_AVX2_BUCKET_LOAD8(6, lt, 5, pkt[5], bsize);
+ NFT_PIPAPO_AVX2_AND(7, 2, 3);
+
+ /* Stall */
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index ada47e59647a0..81ba8e51e01ff 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1871,6 +1871,11 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
++ if (len == 0) {
++ pr_warn_once("Zero length message leads to an empty skb\n");
++ return -ENODATA;
++ }
++
+ err = scm_send(sock, msg, &scm, true);
+ if (err < 0)
+ return err;
+diff --git a/net/nfc/core.c b/net/nfc/core.c
+index 3c645c1d99c9b..dc7a2404efdf9 100644
+--- a/net/nfc/core.c
++++ b/net/nfc/core.c
+@@ -94,13 +94,13 @@ int nfc_dev_up(struct nfc_dev *dev)
+
+ device_lock(&dev->dev);
+
+- if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
+- rc = -ERFKILL;
++ if (!device_is_registered(&dev->dev)) {
++ rc = -ENODEV;
+ goto error;
+ }
+
+- if (!device_is_registered(&dev->dev)) {
+- rc = -ENODEV;
++ if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
++ rc = -ERFKILL;
+ goto error;
+ }
+
+@@ -1125,11 +1125,7 @@ int nfc_register_device(struct nfc_dev *dev)
+ if (rc)
+ pr_err("Could not register llcp device\n");
+
+- rc = nfc_genl_device_added(dev);
+- if (rc)
+- pr_debug("The userspace won't be notified that the device %s was added\n",
+- dev_name(&dev->dev));
+-
++ device_lock(&dev->dev);
+ dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
+ RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
+ if (dev->rfkill) {
+@@ -1138,6 +1134,12 @@ int nfc_register_device(struct nfc_dev *dev)
+ dev->rfkill = NULL;
+ }
+ }
++ device_unlock(&dev->dev);
++
++ rc = nfc_genl_device_added(dev);
++ if (rc)
++ pr_debug("The userspace won't be notified that the device %s was added\n",
++ dev_name(&dev->dev));
+
+ return 0;
+ }
+@@ -1154,10 +1156,17 @@ void nfc_unregister_device(struct nfc_dev *dev)
+
+ pr_debug("dev_name=%s\n", dev_name(&dev->dev));
+
++ rc = nfc_genl_device_removed(dev);
++ if (rc)
++ pr_debug("The userspace won't be notified that the device %s "
++ "was removed\n", dev_name(&dev->dev));
++
++ device_lock(&dev->dev);
+ if (dev->rfkill) {
+ rfkill_unregister(dev->rfkill);
+ rfkill_destroy(dev->rfkill);
+ }
++ device_unlock(&dev->dev);
+
+ if (dev->ops->check_presence) {
+ device_lock(&dev->dev);
+@@ -1167,11 +1176,6 @@ void nfc_unregister_device(struct nfc_dev *dev)
+ cancel_work_sync(&dev->check_pres_work);
+ }
+
+- rc = nfc_genl_device_removed(dev);
+- if (rc)
+- pr_debug("The userspace won't be notified that the device %s "
+- "was removed\n", dev_name(&dev->dev));
+-
+ nfc_llcp_unregister_device(dev);
+
+ mutex_lock(&nfc_devlist_mutex);
+diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
+index 82ab39d80726e..e41e2e9e54984 100644
+--- a/net/nfc/nci/core.c
++++ b/net/nfc/nci/core.c
+@@ -144,12 +144,15 @@ inline int nci_request(struct nci_dev *ndev,
+ {
+ int rc;
+
+- if (!test_bit(NCI_UP, &ndev->flags))
+- return -ENETDOWN;
+-
+ /* Serialize all requests */
+ mutex_lock(&ndev->req_lock);
+- rc = __nci_request(ndev, req, opt, timeout);
++ /* check the state after obtaing the lock against any races
++ * from nci_close_device when the device gets removed.
++ */
++ if (test_bit(NCI_UP, &ndev->flags))
++ rc = __nci_request(ndev, req, opt, timeout);
++ else
++ rc = -ENETDOWN;
+ mutex_unlock(&ndev->req_lock);
+
+ return rc;
+@@ -473,6 +476,11 @@ static int nci_open_device(struct nci_dev *ndev)
+
+ mutex_lock(&ndev->req_lock);
+
++ if (test_bit(NCI_UNREG, &ndev->flags)) {
++ rc = -ENODEV;
++ goto done;
++ }
++
+ if (test_bit(NCI_UP, &ndev->flags)) {
+ rc = -EALREADY;
+ goto done;
+@@ -545,6 +553,10 @@ done:
+ static int nci_close_device(struct nci_dev *ndev)
+ {
+ nci_req_cancel(ndev, ENODEV);
++
++ /* This mutex needs to be held as a barrier for
++ * caller nci_unregister_device
++ */
+ mutex_lock(&ndev->req_lock);
+
+ if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
+@@ -582,8 +594,8 @@ static int nci_close_device(struct nci_dev *ndev)
+
+ del_timer_sync(&ndev->cmd_timer);
+
+- /* Clear flags */
+- ndev->flags = 0;
++ /* Clear flags except NCI_UNREG */
++ ndev->flags &= BIT(NCI_UNREG);
+
+ mutex_unlock(&ndev->req_lock);
+
+@@ -1270,6 +1282,12 @@ void nci_unregister_device(struct nci_dev *ndev)
+ {
+ struct nci_conn_info *conn_info, *n;
+
++ /* This set_bit is not protected with specialized barrier,
++ * However, it is fine because the mutex_lock(&ndev->req_lock);
++ * in nci_close_device() will help to emit one.
++ */
++ set_bit(NCI_UNREG, &ndev->flags);
++
+ nci_close_device(ndev);
+
+ destroy_workqueue(ndev->cmd_wq);
+diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
+index 49089c50872e6..8048a3dcc5f8b 100644
+--- a/net/nfc/netlink.c
++++ b/net/nfc/netlink.c
+@@ -636,8 +636,10 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
+ {
+ struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+
+- nfc_device_iter_exit(iter);
+- kfree(iter);
++ if (iter) {
++ nfc_device_iter_exit(iter);
++ kfree(iter);
++ }
+
+ return 0;
+ }
+@@ -1392,8 +1394,10 @@ static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
+ {
+ struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+
+- nfc_device_iter_exit(iter);
+- kfree(iter);
++ if (iter) {
++ nfc_device_iter_exit(iter);
++ kfree(iter);
++ }
+
+ return 0;
+ }
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 2a2bc64f75cfd..1bc7ef49e1487 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -4457,9 +4457,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ }
+
+ out_free_pg_vec:
+- bitmap_free(rx_owner_map);
+- if (pg_vec)
++ if (pg_vec) {
++ bitmap_free(rx_owner_map);
+ free_pg_vec(pg_vec, order, req->tp_block_nr);
++ }
+ out:
+ return err;
+ }
+diff --git a/net/rds/connection.c b/net/rds/connection.c
+index a3bc4b54d4910..b4cc699c5fad3 100644
+--- a/net/rds/connection.c
++++ b/net/rds/connection.c
+@@ -253,6 +253,7 @@ static struct rds_connection *__rds_conn_create(struct net *net,
+ * should end up here, but if it
+ * does, reset/destroy the connection.
+ */
++ kfree(conn->c_path);
+ kmem_cache_free(rds_conn_slab, conn);
+ conn = ERR_PTR(-EOPNOTSUPP);
+ goto out;
+diff --git a/net/rds/tcp.c b/net/rds/tcp.c
+index abf19c0e3ba0b..5327d130c4b56 100644
+--- a/net/rds/tcp.c
++++ b/net/rds/tcp.c
+@@ -500,7 +500,7 @@ void rds_tcp_tune(struct socket *sock)
+ sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+ }
+ if (rtn->rcvbuf_size > 0) {
+- sk->sk_sndbuf = rtn->rcvbuf_size;
++ sk->sk_rcvbuf = rtn->rcvbuf_size;
+ sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+ }
+ release_sock(sk);
+diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
+index dbea0bfee48e9..8120138dac018 100644
+--- a/net/rxrpc/conn_client.c
++++ b/net/rxrpc/conn_client.c
+@@ -135,16 +135,20 @@ struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *bundle)
+ return bundle;
+ }
+
++static void rxrpc_free_bundle(struct rxrpc_bundle *bundle)
++{
++ rxrpc_put_peer(bundle->params.peer);
++ kfree(bundle);
++}
++
+ void rxrpc_put_bundle(struct rxrpc_bundle *bundle)
+ {
+ unsigned int d = bundle->debug_id;
+ unsigned int u = atomic_dec_return(&bundle->usage);
+
+ _debug("PUT B=%x %u", d, u);
+- if (u == 0) {
+- rxrpc_put_peer(bundle->params.peer);
+- kfree(bundle);
+- }
++ if (u == 0)
++ rxrpc_free_bundle(bundle);
+ }
+
+ /*
+@@ -328,7 +332,7 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c
+ return candidate;
+
+ found_bundle_free:
+- kfree(candidate);
++ rxrpc_free_bundle(candidate);
+ found_bundle:
+ rxrpc_get_bundle(bundle);
+ spin_unlock(&local->client_bundles_lock);
+diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
+index 68396d0520525..0298fe2ad6d32 100644
+--- a/net/rxrpc/peer_object.c
++++ b/net/rxrpc/peer_object.c
+@@ -299,6 +299,12 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx,
+ return peer;
+ }
+
++static void rxrpc_free_peer(struct rxrpc_peer *peer)
++{
++ rxrpc_put_local(peer->local);
++ kfree_rcu(peer, rcu);
++}
++
+ /*
+ * Set up a new incoming peer. There shouldn't be any other matching peers
+ * since we've already done a search in the list from the non-reentrant context
+@@ -365,7 +371,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx,
+ spin_unlock_bh(&rxnet->peer_hash_lock);
+
+ if (peer)
+- kfree(candidate);
++ rxrpc_free_peer(candidate);
+ else
+ peer = candidate;
+ }
+@@ -420,8 +426,7 @@ static void __rxrpc_put_peer(struct rxrpc_peer *peer)
+ list_del_init(&peer->keepalive_link);
+ spin_unlock_bh(&rxnet->peer_hash_lock);
+
+- rxrpc_put_local(peer->local);
+- kfree_rcu(peer, rcu);
++ rxrpc_free_peer(peer);
+ }
+
+ /*
+@@ -457,8 +462,7 @@ void rxrpc_put_peer_locked(struct rxrpc_peer *peer)
+ if (n == 0) {
+ hash_del_rcu(&peer->hash_link);
+ list_del_init(&peer->keepalive_link);
+- rxrpc_put_local(peer->local);
+- kfree_rcu(peer, rcu);
++ rxrpc_free_peer(peer);
+ }
+ }
+
+diff --git a/net/rxrpc/rtt.c b/net/rxrpc/rtt.c
+index 4e565eeab4260..be61d6f5be8d1 100644
+--- a/net/rxrpc/rtt.c
++++ b/net/rxrpc/rtt.c
+@@ -22,7 +22,7 @@ static u32 rxrpc_rto_min_us(struct rxrpc_peer *peer)
+
+ static u32 __rxrpc_set_rto(const struct rxrpc_peer *peer)
+ {
+- return _usecs_to_jiffies((peer->srtt_us >> 3) + peer->rttvar_us);
++ return usecs_to_jiffies((peer->srtt_us >> 3) + peer->rttvar_us);
+ }
+
+ static u32 rxrpc_bound_rto(u32 rto)
+diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
+index d64b0eeccbe4d..efc963ab995a3 100644
+--- a/net/sched/act_mirred.c
++++ b/net/sched/act_mirred.c
+@@ -19,6 +19,7 @@
+ #include <linux/if_arp.h>
+ #include <net/net_namespace.h>
+ #include <net/netlink.h>
++#include <net/dst.h>
+ #include <net/pkt_sched.h>
+ #include <net/pkt_cls.h>
+ #include <linux/tc_act/tc_mirred.h>
+@@ -228,6 +229,7 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
+ bool want_ingress;
+ bool is_redirect;
+ bool expects_nh;
++ bool at_ingress;
+ int m_eaction;
+ int mac_len;
+ bool at_nh;
+@@ -263,7 +265,8 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
+ * ingress - that covers the TC S/W datapath.
+ */
+ is_redirect = tcf_mirred_is_act_redirect(m_eaction);
+- use_reinsert = skb_at_tc_ingress(skb) && is_redirect &&
++ at_ingress = skb_at_tc_ingress(skb);
++ use_reinsert = at_ingress && is_redirect &&
+ tcf_mirred_can_reinsert(retval);
+ if (!use_reinsert) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+@@ -271,10 +274,12 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
+ goto out;
+ }
+
++ want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
++
+ /* All mirred/redirected skbs should clear previous ct info */
+ nf_reset_ct(skb2);
+-
+- want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
++ if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */
++ skb_dst_drop(skb2);
+
+ expects_nh = want_ingress || !m_mac_header_xmit;
+ at_nh = skb->data == skb_network_header(skb);
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 2ef8f5a6205a9..e54f0a42270c1 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -3687,6 +3687,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
+ entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
+ break;
+ default:
++ err = -EOPNOTSUPP;
+ goto err_out_locked;
+ }
+ } else if (is_tcf_skbedit_ptype(act)) {
+diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
+index 3c2300d144681..857aaebd49f43 100644
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -2736,7 +2736,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
+ q->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
+ GFP_KERNEL);
+ if (!q->tins)
+- goto nomem;
++ return -ENOMEM;
+
+ for (i = 0; i < CAKE_MAX_TINS; i++) {
+ struct cake_tin_data *b = q->tins + i;
+@@ -2766,10 +2766,6 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
+ q->min_netlen = ~0;
+ q->min_adjlen = ~0;
+ return 0;
+-
+-nomem:
+- cake_destroy(sch);
+- return -ENOMEM;
+ }
+
+ static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
+diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
+index 1f857ffd1ac23..44fa2532a87c0 100644
+--- a/net/sched/sch_ets.c
++++ b/net/sched/sch_ets.c
+@@ -667,12 +667,14 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
+ q->classes[i].deficit = quanta[i];
+ }
+ }
++ for (i = q->nbands; i < oldbands; i++) {
++ if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
++ list_del(&q->classes[i].alist);
++ qdisc_tree_flush_backlog(q->classes[i].qdisc);
++ }
+ q->nstrict = nstrict;
+ memcpy(q->prio2band, priomap, sizeof(priomap));
+
+- for (i = q->nbands; i < oldbands; i++)
+- qdisc_tree_flush_backlog(q->classes[i].qdisc);
+-
+ for (i = 0; i < q->nbands; i++)
+ q->classes[i].quantum = quanta[i];
+
+diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
+index 830f3559f727a..d6aba6edd16e5 100644
+--- a/net/sched/sch_fq_pie.c
++++ b/net/sched/sch_fq_pie.c
+@@ -531,6 +531,7 @@ static void fq_pie_destroy(struct Qdisc *sch)
+ struct fq_pie_sched_data *q = qdisc_priv(sch);
+
+ tcf_block_put(q->block);
++ q->p_params.tupdate = 0;
+ del_timer_sync(&q->adapt_timer);
+ kvfree(q->flows);
+ }
+diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
+index a8dd06c74e318..66d2fbe9ef501 100644
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -1330,6 +1330,15 @@ static int qdisc_change_tx_queue_len(struct net_device *dev,
+ return 0;
+ }
+
++void dev_qdisc_change_real_num_tx(struct net_device *dev,
++ unsigned int new_real_tx)
++{
++ struct Qdisc *qdisc = dev->qdisc;
++
++ if (qdisc->ops->change_real_num_tx)
++ qdisc->ops->change_real_num_tx(qdisc, new_real_tx);
++}
++
+ int dev_qdisc_change_tx_queue_len(struct net_device *dev)
+ {
+ bool up = dev->flags & IFF_UP;
+diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
+index e79f1afe0cfd6..db18d8a860f9c 100644
+--- a/net/sched/sch_mq.c
++++ b/net/sched/sch_mq.c
+@@ -125,6 +125,29 @@ static void mq_attach(struct Qdisc *sch)
+ priv->qdiscs = NULL;
+ }
+
++static void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
++{
++#ifdef CONFIG_NET_SCHED
++ struct net_device *dev = qdisc_dev(sch);
++ struct Qdisc *qdisc;
++ unsigned int i;
++
++ for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
++ qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
++ /* Only update the default qdiscs we created,
++ * qdiscs with handles are always hashed.
++ */
++ if (qdisc != &noop_qdisc && !qdisc->handle)
++ qdisc_hash_del(qdisc);
++ }
++ for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
++ qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
++ if (qdisc != &noop_qdisc && !qdisc->handle)
++ qdisc_hash_add(qdisc, false);
++ }
++#endif
++}
++
+ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
+ {
+ struct net_device *dev = qdisc_dev(sch);
+@@ -288,6 +311,7 @@ struct Qdisc_ops mq_qdisc_ops __read_mostly = {
+ .init = mq_init,
+ .destroy = mq_destroy,
+ .attach = mq_attach,
++ .change_real_num_tx = mq_change_real_num_tx,
+ .dump = mq_dump,
+ .owner = THIS_MODULE,
+ };
+diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
+index 5eb3b1b7ae5e7..50e15add6068f 100644
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -306,6 +306,28 @@ static void mqprio_attach(struct Qdisc *sch)
+ priv->qdiscs = NULL;
+ }
+
++static void mqprio_change_real_num_tx(struct Qdisc *sch,
++ unsigned int new_real_tx)
++{
++ struct net_device *dev = qdisc_dev(sch);
++ struct Qdisc *qdisc;
++ unsigned int i;
++
++ for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
++ qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
++ /* Only update the default qdiscs we created,
++ * qdiscs with handles are always hashed.
++ */
++ if (qdisc != &noop_qdisc && !qdisc->handle)
++ qdisc_hash_del(qdisc);
++ }
++ for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
++ qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
++ if (qdisc != &noop_qdisc && !qdisc->handle)
++ qdisc_hash_add(qdisc, false);
++ }
++}
++
+ static struct netdev_queue *mqprio_queue_get(struct Qdisc *sch,
+ unsigned long cl)
+ {
+@@ -629,6 +651,7 @@ static struct Qdisc_ops mqprio_qdisc_ops __read_mostly = {
+ .init = mqprio_init,
+ .destroy = mqprio_destroy,
+ .attach = mqprio_attach,
++ .change_real_num_tx = mqprio_change_real_num_tx,
+ .dump = mqprio_dump,
+ .owner = THIS_MODULE,
+ };
+diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
+index b9fd18d986464..a66398fb2d6d0 100644
+--- a/net/sched/sch_taprio.c
++++ b/net/sched/sch_taprio.c
+@@ -95,18 +95,22 @@ static ktime_t sched_base_time(const struct sched_gate_list *sched)
+ return ns_to_ktime(sched->base_time);
+ }
+
+-static ktime_t taprio_get_time(struct taprio_sched *q)
++static ktime_t taprio_mono_to_any(const struct taprio_sched *q, ktime_t mono)
+ {
+- ktime_t mono = ktime_get();
++ /* This pairs with WRITE_ONCE() in taprio_parse_clockid() */
++ enum tk_offsets tk_offset = READ_ONCE(q->tk_offset);
+
+- switch (q->tk_offset) {
++ switch (tk_offset) {
+ case TK_OFFS_MAX:
+ return mono;
+ default:
+- return ktime_mono_to_any(mono, q->tk_offset);
++ return ktime_mono_to_any(mono, tk_offset);
+ }
++}
+
+- return KTIME_MAX;
++static ktime_t taprio_get_time(const struct taprio_sched *q)
++{
++ return taprio_mono_to_any(q, ktime_get());
+ }
+
+ static void taprio_free_sched_cb(struct rcu_head *head)
+@@ -319,7 +323,7 @@ static ktime_t get_tcp_tstamp(struct taprio_sched *q, struct sk_buff *skb)
+ return 0;
+ }
+
+- return ktime_mono_to_any(skb->skb_mstamp_ns, q->tk_offset);
++ return taprio_mono_to_any(q, skb->skb_mstamp_ns);
+ }
+
+ /* There are a few scenarios where we will have to modify the txtime from
+@@ -1352,6 +1356,7 @@ static int taprio_parse_clockid(struct Qdisc *sch, struct nlattr **tb,
+ }
+ } else if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]) {
+ int clockid = nla_get_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
++ enum tk_offsets tk_offset;
+
+ /* We only support static clockids and we don't allow
+ * for it to be modified after the first init.
+@@ -1366,22 +1371,24 @@ static int taprio_parse_clockid(struct Qdisc *sch, struct nlattr **tb,
+
+ switch (clockid) {
+ case CLOCK_REALTIME:
+- q->tk_offset = TK_OFFS_REAL;
++ tk_offset = TK_OFFS_REAL;
+ break;
+ case CLOCK_MONOTONIC:
+- q->tk_offset = TK_OFFS_MAX;
++ tk_offset = TK_OFFS_MAX;
+ break;
+ case CLOCK_BOOTTIME:
+- q->tk_offset = TK_OFFS_BOOT;
++ tk_offset = TK_OFFS_BOOT;
+ break;
+ case CLOCK_TAI:
+- q->tk_offset = TK_OFFS_TAI;
++ tk_offset = TK_OFFS_TAI;
+ break;
+ default:
+ NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
+ err = -EINVAL;
+ goto out;
+ }
++ /* This pairs with READ_ONCE() in taprio_mono_to_any */
++ WRITE_ONCE(q->tk_offset, tk_offset);
+
+ q->clockid = clockid;
+ } else {
+diff --git a/net/sctp/output.c b/net/sctp/output.c
+index 4dfb5ea82b05b..cdfdbd353c678 100644
+--- a/net/sctp/output.c
++++ b/net/sctp/output.c
+@@ -581,13 +581,16 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
+ chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list);
+ sk = chunk->skb->sk;
+
+- /* check gso */
+ if (packet->size > tp->pathmtu && !packet->ipfragok && !chunk->pmtu_probe) {
+- if (!sk_can_gso(sk)) {
+- pr_err_once("Trying to GSO but underlying device doesn't support it.");
+- goto out;
++ if (tp->pl.state == SCTP_PL_ERROR) { /* do IP fragmentation if in Error state */
++ packet->ipfragok = 1;
++ } else {
++ if (!sk_can_gso(sk)) { /* check gso */
++ pr_err_once("Trying to GSO but underlying device doesn't support it.");
++ goto out;
++ }
++ gso = 1;
+ }
+- gso = 1;
+ }
+
+ /* alloc head skb */
+diff --git a/net/sctp/transport.c b/net/sctp/transport.c
+index a3d3ca6dd63dd..133f1719bf1b7 100644
+--- a/net/sctp/transport.c
++++ b/net/sctp/transport.c
+@@ -269,7 +269,7 @@ bool sctp_transport_pl_send(struct sctp_transport *t)
+ if (t->pl.probe_size == SCTP_BASE_PLPMTU) { /* BASE_PLPMTU Confirmation Failed */
+ t->pl.state = SCTP_PL_ERROR; /* Base -> Error */
+
+- t->pl.pmtu = SCTP_MIN_PLPMTU;
++ t->pl.pmtu = SCTP_BASE_PLPMTU;
+ t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
+ sctp_assoc_sync_pmtu(t->asoc);
+ }
+@@ -366,8 +366,9 @@ static bool sctp_transport_pl_toobig(struct sctp_transport *t, u32 pmtu)
+ if (pmtu >= SCTP_MIN_PLPMTU && pmtu < SCTP_BASE_PLPMTU) {
+ t->pl.state = SCTP_PL_ERROR; /* Base -> Error */
+
+- t->pl.pmtu = SCTP_MIN_PLPMTU;
++ t->pl.pmtu = SCTP_BASE_PLPMTU;
+ t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
++ return true;
+ }
+ } else if (t->pl.state == SCTP_PL_SEARCH) {
+ if (pmtu >= SCTP_BASE_PLPMTU && pmtu < t->pl.pmtu) {
+@@ -378,11 +379,10 @@ static bool sctp_transport_pl_toobig(struct sctp_transport *t, u32 pmtu)
+ t->pl.probe_high = 0;
+ t->pl.pmtu = SCTP_BASE_PLPMTU;
+ t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
++ return true;
+ } else if (pmtu > t->pl.pmtu && pmtu < t->pl.probe_size) {
+ t->pl.probe_size = pmtu;
+ t->pl.probe_count = 0;
+-
+- return false;
+ }
+ } else if (t->pl.state == SCTP_PL_COMPLETE) {
+ if (pmtu >= SCTP_BASE_PLPMTU && pmtu < t->pl.pmtu) {
+@@ -393,10 +393,11 @@ static bool sctp_transport_pl_toobig(struct sctp_transport *t, u32 pmtu)
+ t->pl.probe_high = 0;
+ t->pl.pmtu = SCTP_BASE_PLPMTU;
+ t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
++ return true;
+ }
+ }
+
+- return true;
++ return false;
+ }
+
+ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 78b663dbfa1f9..eea6d4a854e90 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -148,14 +148,18 @@ static int __smc_release(struct smc_sock *smc)
+ sock_set_flag(sk, SOCK_DEAD);
+ sk->sk_shutdown |= SHUTDOWN_MASK;
+ } else {
+- if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)
+- sock_put(sk); /* passive closing */
+- if (sk->sk_state == SMC_LISTEN) {
+- /* wake up clcsock accept */
+- rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
++ if (sk->sk_state != SMC_CLOSED) {
++ if (sk->sk_state != SMC_LISTEN &&
++ sk->sk_state != SMC_INIT)
++ sock_put(sk); /* passive closing */
++ if (sk->sk_state == SMC_LISTEN) {
++ /* wake up clcsock accept */
++ rc = kernel_sock_shutdown(smc->clcsock,
++ SHUT_RDWR);
++ }
++ sk->sk_state = SMC_CLOSED;
++ sk->sk_state_change(sk);
+ }
+- sk->sk_state = SMC_CLOSED;
+- sk->sk_state_change(sk);
+ smc_restore_fallback_changes(smc);
+ }
+
+@@ -189,7 +193,9 @@ static int smc_release(struct socket *sock)
+ /* cleanup for a dangling non-blocking connect */
+ if (smc->connect_nonblock && sk->sk_state == SMC_INIT)
+ tcp_abort(smc->clcsock->sk, ECONNABORTED);
+- flush_work(&smc->connect_work);
++
++ if (cancel_work_sync(&smc->connect_work))
++ sock_put(&smc->sk); /* sock_hold in smc_connect for passive closing */
+
+ if (sk->sk_state == SMC_LISTEN)
+ /* smc_close_non_accepted() is called and acquires
+@@ -544,6 +550,10 @@ static void smc_stat_fallback(struct smc_sock *smc)
+
+ static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+ {
++ wait_queue_head_t *smc_wait = sk_sleep(&smc->sk);
++ wait_queue_head_t *clc_wait = sk_sleep(smc->clcsock->sk);
++ unsigned long flags;
++
+ smc->use_fallback = true;
+ smc->fallback_rsn = reason_code;
+ smc_stat_fallback(smc);
+@@ -552,6 +562,16 @@ static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+ smc->clcsock->file->private_data = smc->clcsock;
+ smc->clcsock->wq.fasync_list =
+ smc->sk.sk_socket->wq.fasync_list;
++
++ /* There may be some entries remaining in
++ * smc socket->wq, which should be removed
++ * to clcsocket->wq during the fallback.
++ */
++ spin_lock_irqsave(&smc_wait->lock, flags);
++ spin_lock_nested(&clc_wait->lock, SINGLE_DEPTH_NESTING);
++ list_splice_init(&smc_wait->head, &clc_wait->head);
++ spin_unlock(&clc_wait->lock);
++ spin_unlock_irqrestore(&smc_wait->lock, flags);
+ }
+ }
+
+@@ -1914,8 +1934,10 @@ static int smc_listen(struct socket *sock, int backlog)
+ smc->clcsock->sk->sk_user_data =
+ (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
+ rc = kernel_listen(smc->clcsock, backlog);
+- if (rc)
++ if (rc) {
++ smc->clcsock->sk->sk_data_ready = smc->clcsk_data_ready;
+ goto out;
++ }
+ sk->sk_max_ack_backlog = backlog;
+ sk->sk_ack_backlog = 0;
+ sk->sk_state = SMC_LISTEN;
+@@ -2148,8 +2170,10 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
+ static int smc_shutdown(struct socket *sock, int how)
+ {
+ struct sock *sk = sock->sk;
++ bool do_shutdown = true;
+ struct smc_sock *smc;
+ int rc = -EINVAL;
++ int old_state;
+ int rc1 = 0;
+
+ smc = smc_sk(sk);
+@@ -2176,7 +2200,11 @@ static int smc_shutdown(struct socket *sock, int how)
+ }
+ switch (how) {
+ case SHUT_RDWR: /* shutdown in both directions */
++ old_state = sk->sk_state;
+ rc = smc_close_active(smc);
++ if (old_state == SMC_ACTIVE &&
++ sk->sk_state == SMC_PEERCLOSEWAIT1)
++ do_shutdown = false;
+ break;
+ case SHUT_WR:
+ rc = smc_close_shutdown_write(smc);
+@@ -2186,7 +2214,7 @@ static int smc_shutdown(struct socket *sock, int how)
+ /* nothing more to do because peer is not involved */
+ break;
+ }
+- if (smc->clcsock)
++ if (do_shutdown && smc->clcsock)
+ rc1 = kernel_sock_shutdown(smc->clcsock, how);
+ /* map sock_shutdown_cmd constants to sk_shutdown value range */
+ sk->sk_shutdown |= how + 1;
+diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c
+index 0f9ffba07d268..84102db5bb314 100644
+--- a/net/smc/smc_close.c
++++ b/net/smc/smc_close.c
+@@ -195,6 +195,7 @@ int smc_close_active(struct smc_sock *smc)
+ int old_state;
+ long timeout;
+ int rc = 0;
++ int rc1 = 0;
+
+ timeout = current->flags & PF_EXITING ?
+ 0 : sock_flag(sk, SOCK_LINGER) ?
+@@ -228,6 +229,15 @@ again:
+ /* send close request */
+ rc = smc_close_final(conn);
+ sk->sk_state = SMC_PEERCLOSEWAIT1;
++
++ /* actively shutdown clcsock before peer close it,
++ * prevent peer from entering TIME_WAIT state.
++ */
++ if (smc->clcsock && smc->clcsock->sk) {
++ rc1 = kernel_sock_shutdown(smc->clcsock,
++ SHUT_RDWR);
++ rc = rc ? rc : rc1;
++ }
+ } else {
+ /* peer event has changed the state */
+ goto again;
+diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
+index d2206743dc714..5a9c22ee75fa4 100644
+--- a/net/smc/smc_core.c
++++ b/net/smc/smc_core.c
+@@ -582,18 +582,17 @@ int smcd_nl_get_lgr(struct sk_buff *skb, struct netlink_callback *cb)
+ void smc_lgr_cleanup_early(struct smc_connection *conn)
+ {
+ struct smc_link_group *lgr = conn->lgr;
+- struct list_head *lgr_list;
+ spinlock_t *lgr_lock;
+
+ if (!lgr)
+ return;
+
+ smc_conn_free(conn);
+- lgr_list = smc_lgr_list_head(lgr, &lgr_lock);
++ smc_lgr_list_head(lgr, &lgr_lock);
+ spin_lock_bh(lgr_lock);
+ /* do not use this link group for new connections */
+- if (!list_empty(lgr_list))
+- list_del_init(lgr_list);
++ if (!list_empty(&lgr->list))
++ list_del_init(&lgr->list);
+ spin_unlock_bh(lgr_lock);
+ __smc_lgr_terminate(lgr, true);
+ }
+@@ -665,13 +664,14 @@ static u8 smcr_next_link_id(struct smc_link_group *lgr)
+ int i;
+
+ while (1) {
++again:
+ link_id = ++lgr->next_link_id;
+ if (!link_id) /* skip zero as link_id */
+ link_id = ++lgr->next_link_id;
+ for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+ if (smc_link_usable(&lgr->lnk[i]) &&
+ lgr->lnk[i].link_id == link_id)
+- continue;
++ goto again;
+ }
+ break;
+ }
+@@ -1595,14 +1595,26 @@ static void smc_link_down_work(struct work_struct *work)
+ mutex_unlock(&lgr->llc_conf_mutex);
+ }
+
+-/* Determine vlan of internal TCP socket.
+- * @vlan_id: address to store the determined vlan id into
+- */
++static int smc_vlan_by_tcpsk_walk(struct net_device *lower_dev,
++ struct netdev_nested_priv *priv)
++{
++ unsigned short *vlan_id = (unsigned short *)priv->data;
++
++ if (is_vlan_dev(lower_dev)) {
++ *vlan_id = vlan_dev_vlan_id(lower_dev);
++ return 1;
++ }
++
++ return 0;
++}
++
++/* Determine vlan of internal TCP socket. */
+ int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini)
+ {
+ struct dst_entry *dst = sk_dst_get(clcsock->sk);
++ struct netdev_nested_priv priv;
+ struct net_device *ndev;
+- int i, nest_lvl, rc = 0;
++ int rc = 0;
+
+ ini->vlan_id = 0;
+ if (!dst) {
+@@ -1620,20 +1632,9 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini)
+ goto out_rel;
+ }
+
++ priv.data = (void *)&ini->vlan_id;
+ rtnl_lock();
+- nest_lvl = ndev->lower_level;
+- for (i = 0; i < nest_lvl; i++) {
+- struct list_head *lower = &ndev->adj_list.lower;
+-
+- if (list_empty(lower))
+- break;
+- lower = lower->next;
+- ndev = (struct net_device *)netdev_lower_get_next(ndev, &lower);
+- if (is_vlan_dev(ndev)) {
+- ini->vlan_id = vlan_dev_vlan_id(ndev);
+- break;
+- }
+- }
++ netdev_walk_all_lower_dev(ndev, smc_vlan_by_tcpsk_walk, &priv);
+ rtnl_unlock();
+
+ out_rel:
+diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
+index 9c0343568d2a0..1a72c67afed5e 100644
+--- a/net/strparser/strparser.c
++++ b/net/strparser/strparser.c
+@@ -27,18 +27,10 @@
+
+ static struct workqueue_struct *strp_wq;
+
+-struct _strp_msg {
+- /* Internal cb structure. struct strp_msg must be first for passing
+- * to upper layer.
+- */
+- struct strp_msg strp;
+- int accum_len;
+-};
+-
+ static inline struct _strp_msg *_strp_msg(struct sk_buff *skb)
+ {
+ return (struct _strp_msg *)((void *)skb->cb +
+- offsetof(struct qdisc_skb_cb, data));
++ offsetof(struct sk_skb_cb, strp));
+ }
+
+ /* Lower lock held */
+diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c
+index 6e4dbd577a39f..d435bffc61999 100644
+--- a/net/sunrpc/addr.c
++++ b/net/sunrpc/addr.c
+@@ -162,8 +162,10 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
+ const size_t buflen, const char *delim,
+ struct sockaddr_in6 *sin6)
+ {
+- char *p;
++ char p[IPV6_SCOPE_ID_LEN + 1];
+ size_t len;
++ u32 scope_id = 0;
++ struct net_device *dev;
+
+ if ((buf + buflen) == delim)
+ return 1;
+@@ -175,29 +177,23 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
+ return 0;
+
+ len = (buf + buflen) - delim - 1;
+- p = kmemdup_nul(delim + 1, len, GFP_KERNEL);
+- if (p) {
+- u32 scope_id = 0;
+- struct net_device *dev;
+-
+- dev = dev_get_by_name(net, p);
+- if (dev != NULL) {
+- scope_id = dev->ifindex;
+- dev_put(dev);
+- } else {
+- if (kstrtou32(p, 10, &scope_id) != 0) {
+- kfree(p);
+- return 0;
+- }
+- }
+-
+- kfree(p);
+-
+- sin6->sin6_scope_id = scope_id;
+- return 1;
++ if (len > IPV6_SCOPE_ID_LEN)
++ return 0;
++
++ memcpy(p, delim + 1, len);
++ p[len] = 0;
++
++ dev = dev_get_by_name(net, p);
++ if (dev != NULL) {
++ scope_id = dev->ifindex;
++ dev_put(dev);
++ } else {
++ if (kstrtou32(p, 10, &scope_id) != 0)
++ return 0;
+ }
+
+- return 0;
++ sin6->sin6_scope_id = scope_id;
++ return 1;
+ }
+
+ static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
+diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
+index cfd681700d1a1..d4aeee83763e6 100644
+--- a/net/sunrpc/xprt.c
++++ b/net/sunrpc/xprt.c
+@@ -1603,15 +1603,14 @@ xprt_transmit(struct rpc_task *task)
+ {
+ struct rpc_rqst *next, *req = task->tk_rqstp;
+ struct rpc_xprt *xprt = req->rq_xprt;
+- int counter, status;
++ int status;
+
+ spin_lock(&xprt->queue_lock);
+- counter = 0;
+- while (!list_empty(&xprt->xmit_queue)) {
+- if (++counter == 20)
++ for (;;) {
++ next = list_first_entry_or_null(&xprt->xmit_queue,
++ struct rpc_rqst, rq_xmit);
++ if (!next)
+ break;
+- next = list_first_entry(&xprt->xmit_queue,
+- struct rpc_rqst, rq_xmit);
+ xprt_pin_rqst(next);
+ spin_unlock(&xprt->queue_lock);
+ status = xprt_request_transmit(next, task);
+@@ -1619,13 +1618,16 @@ xprt_transmit(struct rpc_task *task)
+ status = 0;
+ spin_lock(&xprt->queue_lock);
+ xprt_unpin_rqst(next);
+- if (status == 0) {
+- if (!xprt_request_data_received(task) ||
+- test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
+- continue;
+- } else if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
+- task->tk_status = status;
+- break;
++ if (status < 0) {
++ if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
++ task->tk_status = status;
++ break;
++ }
++ /* Was @task transmitted, and has it received a reply? */
++ if (xprt_request_data_received(task) &&
++ !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
++ break;
++ cond_resched_lock(&xprt->queue_lock);
+ }
+ spin_unlock(&xprt->queue_lock);
+ }
+diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
+index dc60c32bb70df..d293614d5fc65 100644
+--- a/net/tipc/crypto.c
++++ b/net/tipc/crypto.c
+@@ -597,6 +597,10 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,
+ tmp->cloned = NULL;
+ tmp->authsize = TIPC_AES_GCM_TAG_SIZE;
+ tmp->key = kmemdup(ukey, tipc_aead_key_size(ukey), GFP_KERNEL);
++ if (!tmp->key) {
++ tipc_aead_free(&tmp->rcu);
++ return -ENOMEM;
++ }
+ memcpy(&tmp->salt, ukey->key + keylen, TIPC_AES_GCM_SALT_SIZE);
+ atomic_set(&tmp->users, 0);
+ atomic64_set(&tmp->seqno, 0);
+diff --git a/net/tipc/link.c b/net/tipc/link.c
+index 1b7a487c88419..09ae8448f394f 100644
+--- a/net/tipc/link.c
++++ b/net/tipc/link.c
+@@ -1298,8 +1298,11 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
+ return false;
+ #ifdef CONFIG_TIPC_CRYPTO
+ case MSG_CRYPTO:
+- tipc_crypto_msg_rcv(l->net, skb);
+- return true;
++ if (TIPC_SKB_CB(skb)->decrypted) {
++ tipc_crypto_msg_rcv(l->net, skb);
++ return true;
++ }
++ fallthrough;
+ #endif
+ default:
+ pr_warn("Dropping received illegal msg type\n");
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index 9ab81db8a6545..9aac9c60d786d 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -61,7 +61,7 @@ static DEFINE_MUTEX(tcpv6_prot_mutex);
+ static const struct proto *saved_tcpv4_prot;
+ static DEFINE_MUTEX(tcpv4_prot_mutex);
+ static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
+-static struct proto_ops tls_sw_proto_ops;
++static struct proto_ops tls_proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
+ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
+ const struct proto *base);
+
+@@ -71,6 +71,8 @@ void update_sk_prot(struct sock *sk, struct tls_context *ctx)
+
+ WRITE_ONCE(sk->sk_prot,
+ &tls_prots[ip_ver][ctx->tx_conf][ctx->rx_conf]);
++ WRITE_ONCE(sk->sk_socket->ops,
++ &tls_proto_ops[ip_ver][ctx->tx_conf][ctx->rx_conf]);
+ }
+
+ int wait_on_pending_writer(struct sock *sk, long *timeo)
+@@ -581,8 +583,6 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
+ if (tx) {
+ ctx->sk_write_space = sk->sk_write_space;
+ sk->sk_write_space = tls_write_space;
+- } else {
+- sk->sk_socket->ops = &tls_sw_proto_ops;
+ }
+ goto out;
+
+@@ -640,6 +640,39 @@ struct tls_context *tls_ctx_create(struct sock *sk)
+ return ctx;
+ }
+
++static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
++ const struct proto_ops *base)
++{
++ ops[TLS_BASE][TLS_BASE] = *base;
++
++ ops[TLS_SW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE];
++ ops[TLS_SW ][TLS_BASE].sendpage_locked = tls_sw_sendpage_locked;
++
++ ops[TLS_BASE][TLS_SW ] = ops[TLS_BASE][TLS_BASE];
++ ops[TLS_BASE][TLS_SW ].splice_read = tls_sw_splice_read;
++
++ ops[TLS_SW ][TLS_SW ] = ops[TLS_SW ][TLS_BASE];
++ ops[TLS_SW ][TLS_SW ].splice_read = tls_sw_splice_read;
++
++#ifdef CONFIG_TLS_DEVICE
++ ops[TLS_HW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE];
++ ops[TLS_HW ][TLS_BASE].sendpage_locked = NULL;
++
++ ops[TLS_HW ][TLS_SW ] = ops[TLS_BASE][TLS_SW ];
++ ops[TLS_HW ][TLS_SW ].sendpage_locked = NULL;
++
++ ops[TLS_BASE][TLS_HW ] = ops[TLS_BASE][TLS_SW ];
++
++ ops[TLS_SW ][TLS_HW ] = ops[TLS_SW ][TLS_SW ];
++
++ ops[TLS_HW ][TLS_HW ] = ops[TLS_HW ][TLS_SW ];
++ ops[TLS_HW ][TLS_HW ].sendpage_locked = NULL;
++#endif
++#ifdef CONFIG_TLS_TOE
++ ops[TLS_HW_RECORD][TLS_HW_RECORD] = *base;
++#endif
++}
++
+ static void tls_build_proto(struct sock *sk)
+ {
+ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
+@@ -651,6 +684,8 @@ static void tls_build_proto(struct sock *sk)
+ mutex_lock(&tcpv6_prot_mutex);
+ if (likely(prot != saved_tcpv6_prot)) {
+ build_protos(tls_prots[TLSV6], prot);
++ build_proto_ops(tls_proto_ops[TLSV6],
++ sk->sk_socket->ops);
+ smp_store_release(&saved_tcpv6_prot, prot);
+ }
+ mutex_unlock(&tcpv6_prot_mutex);
+@@ -661,6 +696,8 @@ static void tls_build_proto(struct sock *sk)
+ mutex_lock(&tcpv4_prot_mutex);
+ if (likely(prot != saved_tcpv4_prot)) {
+ build_protos(tls_prots[TLSV4], prot);
++ build_proto_ops(tls_proto_ops[TLSV4],
++ sk->sk_socket->ops);
+ smp_store_release(&saved_tcpv4_prot, prot);
+ }
+ mutex_unlock(&tcpv4_prot_mutex);
+@@ -871,10 +908,6 @@ static int __init tls_register(void)
+ if (err)
+ return err;
+
+- tls_sw_proto_ops = inet_stream_ops;
+- tls_sw_proto_ops.splice_read = tls_sw_splice_read;
+- tls_sw_proto_ops.sendpage_locked = tls_sw_sendpage_locked;
+-
+ tls_device_init();
+ tcp_register_ulp(&tcp_tls_ulp_ops);
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 1b08b877a8900..bd96ec26f4f99 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -515,7 +515,7 @@ static int tls_do_encryption(struct sock *sk,
+ memcpy(&rec->iv_data[iv_offset], tls_ctx->tx.iv,
+ prot->iv_size + prot->salt_size);
+
+- xor_iv_with_seq(prot, rec->iv_data, tls_ctx->tx.rec_seq);
++ xor_iv_with_seq(prot, rec->iv_data + iv_offset, tls_ctx->tx.rec_seq);
+
+ sge->offset += prot->prepend_size;
+ sge->length -= prot->prepend_size;
+@@ -1487,7 +1487,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
+ else
+ memcpy(iv + iv_offset, tls_ctx->rx.iv, prot->salt_size);
+
+- xor_iv_with_seq(prot, iv, tls_ctx->rx.rec_seq);
++ xor_iv_with_seq(prot, iv + iv_offset, tls_ctx->rx.rec_seq);
+
+ /* Prepare AAD */
+ tls_make_aad(aad, rxm->full_len - prot->overhead_size +
+@@ -1993,6 +1993,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
+ struct sock *sk = sock->sk;
+ struct sk_buff *skb;
+ ssize_t copied = 0;
++ bool from_queue;
+ int err = 0;
+ long timeo;
+ int chunk;
+@@ -2002,25 +2003,28 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
+
+ timeo = sock_rcvtimeo(sk, flags & SPLICE_F_NONBLOCK);
+
+- skb = tls_wait_data(sk, NULL, flags & SPLICE_F_NONBLOCK, timeo, &err);
+- if (!skb)
+- goto splice_read_end;
+-
+- if (!ctx->decrypted) {
+- err = decrypt_skb_update(sk, skb, NULL, &chunk, &zc, false);
+-
+- /* splice does not support reading control messages */
+- if (ctx->control != TLS_RECORD_TYPE_DATA) {
+- err = -EINVAL;
++ from_queue = !skb_queue_empty(&ctx->rx_list);
++ if (from_queue) {
++ skb = __skb_dequeue(&ctx->rx_list);
++ } else {
++ skb = tls_wait_data(sk, NULL, flags & SPLICE_F_NONBLOCK, timeo,
++ &err);
++ if (!skb)
+ goto splice_read_end;
+- }
+
++ err = decrypt_skb_update(sk, skb, NULL, &chunk, &zc, false);
+ if (err < 0) {
+ tls_err_abort(sk, -EBADMSG);
+ goto splice_read_end;
+ }
+- ctx->decrypted = 1;
+ }
++
++ /* splice does not support reading control messages */
++ if (ctx->control != TLS_RECORD_TYPE_DATA) {
++ err = -EINVAL;
++ goto splice_read_end;
++ }
++
+ rxm = strp_msg(skb);
+
+ chunk = min_t(unsigned int, rxm->full_len, len);
+@@ -2028,7 +2032,17 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
+ if (copied < 0)
+ goto splice_read_end;
+
+- tls_sw_advance_skb(sk, skb, copied);
++ if (!from_queue) {
++ ctx->recv_pkt = NULL;
++ __strp_unpause(&ctx->strp);
++ }
++ if (chunk < rxm->full_len) {
++ __skb_queue_head(&ctx->rx_list, skb);
++ rxm->offset += len;
++ rxm->full_len -= len;
++ } else {
++ consume_skb(skb);
++ }
+
+ splice_read_end:
+ release_sock(sk);
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 78e08e82c08c4..b0bfc78e421ce 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2882,9 +2882,6 @@ static int unix_shutdown(struct socket *sock, int mode)
+
+ unix_state_lock(sk);
+ sk->sk_shutdown |= mode;
+- if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) &&
+- mode == SHUTDOWN_MASK)
+- sk->sk_state = TCP_CLOSE;
+ other = unix_peer(sk);
+ if (other)
+ sock_hold(other);
+diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
+index e2c0cfb334d20..fa8c1b623fa21 100644
+--- a/net/vmw_vsock/af_vsock.c
++++ b/net/vmw_vsock/af_vsock.c
+@@ -1322,6 +1322,8 @@ static int vsock_connect(struct socket *sock, struct sockaddr *addr,
+ * non-blocking call.
+ */
+ err = -EALREADY;
++ if (flags & O_NONBLOCK)
++ goto out;
+ break;
+ default:
+ if ((sk->sk_state == TCP_LISTEN) ||
+diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
+index 59ee1be5a6dd3..ec2c2afbf0d06 100644
+--- a/net/vmw_vsock/virtio_transport_common.c
++++ b/net/vmw_vsock/virtio_transport_common.c
+@@ -1299,7 +1299,8 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
+ space_available = virtio_transport_space_update(sk, pkt);
+
+ /* Update CID in case it has changed after a transport reset event */
+- vsk->local_addr.svm_cid = dst.svm_cid;
++ if (vsk->local_addr.svm_cid != VMADDR_CID_ANY)
++ vsk->local_addr.svm_cid = dst.svm_cid;
+
+ if (space_available)
+ sk->sk_write_space(sk);
+diff --git a/net/wireless/core.c b/net/wireless/core.c
+index aaba847d79eb2..eb297e1015e05 100644
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -1081,6 +1081,16 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
+ list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
+ cfg80211_put_bss(&rdev->wiphy, &scan->pub);
+ mutex_destroy(&rdev->wiphy.mtx);
++
++ /*
++ * The 'regd' can only be non-NULL if we never finished
++ * initializing the wiphy and thus never went through the
++ * unregister path - e.g. in failure scenarios. Thus, it
++ * cannot have been visible to anyone if non-NULL, so we
++ * can just free it here.
++ */
++ kfree(rcu_dereference_raw(rdev->wiphy.regd));
++
+ kfree(rdev);
+ }
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index bf7cd47525472..16b3d0cc0bdb0 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -922,33 +922,37 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
+ [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
+ };
+
+-int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
+- struct cfg80211_registered_device **rdev,
+- struct wireless_dev **wdev)
++static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
++ struct cfg80211_registered_device **rdev,
++ struct wireless_dev **wdev,
++ struct nlattr **attrbuf)
+ {
+ int err;
+
+ if (!cb->args[0]) {
+- struct nlattr **attrbuf;
++ struct nlattr **attrbuf_free = NULL;
+
+- attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
+- GFP_KERNEL);
+- if (!attrbuf)
+- return -ENOMEM;
++ if (!attrbuf) {
++ attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
++ GFP_KERNEL);
++ if (!attrbuf)
++ return -ENOMEM;
++ attrbuf_free = attrbuf;
++ }
+
+ err = nlmsg_parse_deprecated(cb->nlh,
+ GENL_HDRLEN + nl80211_fam.hdrsize,
+ attrbuf, nl80211_fam.maxattr,
+ nl80211_policy, NULL);
+ if (err) {
+- kfree(attrbuf);
++ kfree(attrbuf_free);
+ return err;
+ }
+
+ rtnl_lock();
+ *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
+ attrbuf);
+- kfree(attrbuf);
++ kfree(attrbuf_free);
+ if (IS_ERR(*wdev)) {
+ rtnl_unlock();
+ return PTR_ERR(*wdev);
+@@ -6001,7 +6005,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
+ int sta_idx = cb->args[2];
+ int err;
+
+- err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
++ err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
+ if (err)
+ return err;
+ /* nl80211_prepare_wdev_dump acquired it in the successful case */
+@@ -6896,7 +6900,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
+ int path_idx = cb->args[2];
+ int err;
+
+- err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
++ err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
+ if (err)
+ return err;
+ /* nl80211_prepare_wdev_dump acquired it in the successful case */
+@@ -7096,7 +7100,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
+ int path_idx = cb->args[2];
+ int err;
+
+- err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
++ err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
+ if (err)
+ return err;
+ /* nl80211_prepare_wdev_dump acquired it in the successful case */
+@@ -9518,7 +9522,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
+ int start = cb->args[2], idx = 0;
+ int err;
+
+- err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
++ err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
+ if (err)
+ return err;
+ /* nl80211_prepare_wdev_dump acquired it in the successful case */
+@@ -9651,7 +9655,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
+ if (!attrbuf)
+ return -ENOMEM;
+
+- res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
++ res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, attrbuf);
+ if (res) {
+ kfree(attrbuf);
+ return res;
+diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
+index a3f387770f1bf..d642e3be4ee78 100644
+--- a/net/wireless/nl80211.h
++++ b/net/wireless/nl80211.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ /*
+ * Portions of this file
+- * Copyright (C) 2018, 2020 Intel Corporation
++ * Copyright (C) 2018, 2020-2021 Intel Corporation
+ */
+ #ifndef __NET_WIRELESS_NL80211_H
+ #define __NET_WIRELESS_NL80211_H
+@@ -22,10 +22,6 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
+ ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
+ }
+
+-int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
+- struct cfg80211_registered_device **rdev,
+- struct wireless_dev **wdev);
+-
+ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ struct genl_info *info,
+ struct cfg80211_chan_def *chandef);
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index df87c7f3a0492..795e86b371bba 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -2338,6 +2338,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
+ struct cfg80211_chan_def chandef = {};
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+ enum nl80211_iftype iftype;
++ bool ret;
+
+ wdev_lock(wdev);
+ iftype = wdev->iftype;
+@@ -2387,7 +2388,11 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_ADHOC:
+- return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
++ wiphy_lock(wiphy);
++ ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
++ wiphy_unlock(wiphy);
++
++ return ret;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ return cfg80211_chandef_usable(wiphy, &chandef,
+diff --git a/net/wireless/util.c b/net/wireless/util.c
+index a1a99a5749844..4ddc269164f86 100644
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -1044,6 +1044,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
+
+ switch (otype) {
+ case NL80211_IFTYPE_AP:
++ case NL80211_IFTYPE_P2P_GO:
+ cfg80211_stop_ap(rdev, dev, true);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
+index 6e25fba64c72b..a81704d3317ba 100644
+--- a/samples/bpf/xdp_redirect_cpu_user.c
++++ b/samples/bpf/xdp_redirect_cpu_user.c
+@@ -309,7 +309,6 @@ int main(int argc, char **argv)
+ const char *mprog_filename = NULL, *mprog_name = NULL;
+ struct xdp_redirect_cpu *skel;
+ struct bpf_map_info info = {};
+- char ifname_buf[IF_NAMESIZE];
+ struct bpf_cpumap_val value;
+ __u32 infosz = sizeof(info);
+ int ret = EXIT_FAIL_OPTION;
+@@ -325,7 +324,6 @@ int main(int argc, char **argv)
+ int add_cpu = -1;
+ int ifindex = -1;
+ int *cpu, i, opt;
+- char *ifname;
+ __u32 qsize;
+ int n_cpus;
+
+@@ -391,11 +389,10 @@ int main(int argc, char **argv)
+ case 'd':
+ if (strlen(optarg) >= IF_NAMESIZE) {
+ fprintf(stderr, "-d/--dev name too long\n");
++ usage(argv, long_options, __doc__, mask, true, skel->obj);
+ goto end_cpu;
+ }
+- ifname = (char *)&ifname_buf;
+- safe_strncpy(ifname, optarg, sizeof(ifname));
+- ifindex = if_nametoindex(ifname);
++ ifindex = if_nametoindex(optarg);
+ if (!ifindex)
+ ifindex = strtoul(optarg, NULL, 0);
+ if (!ifindex) {
+diff --git a/samples/bpf/xdp_sample_user.c b/samples/bpf/xdp_sample_user.c
+index b32d821781990..8740838e77679 100644
+--- a/samples/bpf/xdp_sample_user.c
++++ b/samples/bpf/xdp_sample_user.c
+@@ -120,7 +120,10 @@ struct sample_output {
+ __u64 xmit;
+ } totals;
+ struct {
+- __u64 pps;
++ union {
++ __u64 pps;
++ __u64 num;
++ };
+ __u64 drop;
+ __u64 err;
+ } rx_cnt;
+@@ -1322,7 +1325,7 @@ int sample_install_xdp(struct bpf_program *xdp_prog, int ifindex, bool generic,
+
+ static void sample_summary_print(void)
+ {
+- double period = sample_out.rx_cnt.pps;
++ double num = sample_out.rx_cnt.num;
+
+ if (sample_out.totals.rx) {
+ double pkts = sample_out.totals.rx;
+@@ -1330,7 +1333,7 @@ static void sample_summary_print(void)
+ print_always(" Packets received : %'-10llu\n",
+ sample_out.totals.rx);
+ print_always(" Average packets/s : %'-10.0f\n",
+- sample_round(pkts / period));
++ sample_round(pkts / num));
+ }
+ if (sample_out.totals.redir) {
+ double pkts = sample_out.totals.redir;
+@@ -1338,7 +1341,7 @@ static void sample_summary_print(void)
+ print_always(" Packets redirected : %'-10llu\n",
+ sample_out.totals.redir);
+ print_always(" Average redir/s : %'-10.0f\n",
+- sample_round(pkts / period));
++ sample_round(pkts / num));
+ }
+ if (sample_out.totals.drop)
+ print_always(" Rx dropped : %'-10llu\n",
+@@ -1355,7 +1358,7 @@ static void sample_summary_print(void)
+ print_always(" Packets transmitted : %'-10llu\n",
+ sample_out.totals.xmit);
+ print_always(" Average transmit/s : %'-10.0f\n",
+- sample_round(pkts / period));
++ sample_round(pkts / num));
+ }
+ }
+
+@@ -1422,7 +1425,7 @@ static int sample_stats_collect(struct stats_record *rec)
+ return 0;
+ }
+
+-static void sample_summary_update(struct sample_output *out, int interval)
++static void sample_summary_update(struct sample_output *out)
+ {
+ sample_out.totals.rx += out->totals.rx;
+ sample_out.totals.redir += out->totals.redir;
+@@ -1430,12 +1433,11 @@ static void sample_summary_update(struct sample_output *out, int interval)
+ sample_out.totals.drop_xmit += out->totals.drop_xmit;
+ sample_out.totals.err += out->totals.err;
+ sample_out.totals.xmit += out->totals.xmit;
+- sample_out.rx_cnt.pps += interval;
++ sample_out.rx_cnt.num++;
+ }
+
+ static void sample_stats_print(int mask, struct stats_record *cur,
+- struct stats_record *prev, char *prog_name,
+- int interval)
++ struct stats_record *prev, char *prog_name)
+ {
+ struct sample_output out = {};
+
+@@ -1452,7 +1454,7 @@ static void sample_stats_print(int mask, struct stats_record *cur,
+ else if (mask & SAMPLE_DEVMAP_XMIT_CNT_MULTI)
+ stats_get_devmap_xmit_multi(cur, prev, 0, &out,
+ mask & SAMPLE_DEVMAP_XMIT_CNT);
+- sample_summary_update(&out, interval);
++ sample_summary_update(&out);
+
+ stats_print(prog_name, mask, cur, prev, &out);
+ }
+@@ -1495,7 +1497,7 @@ static void swap(struct stats_record **a, struct stats_record **b)
+ }
+
+ static int sample_timer_cb(int timerfd, struct stats_record **rec,
+- struct stats_record **prev, int interval)
++ struct stats_record **prev)
+ {
+ char line[64] = "Summary";
+ int ret;
+@@ -1524,7 +1526,7 @@ static int sample_timer_cb(int timerfd, struct stats_record **rec,
+ snprintf(line, sizeof(line), "%s->%s", f ?: "?", t ?: "?");
+ }
+
+- sample_stats_print(sample_mask, *rec, *prev, line, interval);
++ sample_stats_print(sample_mask, *rec, *prev, line);
+ return 0;
+ }
+
+@@ -1579,7 +1581,7 @@ int sample_run(int interval, void (*post_cb)(void *), void *ctx)
+ if (pfd[0].revents & POLLIN)
+ ret = sample_signal_cb();
+ else if (pfd[1].revents & POLLIN)
+- ret = sample_timer_cb(timerfd, &rec, &prev, interval);
++ ret = sample_timer_cb(timerfd, &rec, &prev);
+
+ if (ret)
+ break;
+diff --git a/samples/kprobes/kretprobe_example.c b/samples/kprobes/kretprobe_example.c
+index 5dc1bf3baa98b..228321ecb1616 100644
+--- a/samples/kprobes/kretprobe_example.c
++++ b/samples/kprobes/kretprobe_example.c
+@@ -86,7 +86,7 @@ static int __init kretprobe_init(void)
+ ret = register_kretprobe(&my_kretprobe);
+ if (ret < 0) {
+ pr_err("register_kretprobe failed, returned %d\n", ret);
+- return -1;
++ return ret;
+ }
+ pr_info("Planted return probe at %s: %p\n",
+ my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
+diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
+index b2d8b8aa2d99e..8f636a23bc3f2 100755
+--- a/scripts/leaking_addresses.pl
++++ b/scripts/leaking_addresses.pl
+@@ -455,8 +455,9 @@ sub parse_file
+
+ open my $fh, "<", $file or return;
+ while ( <$fh> ) {
++ chomp;
+ if (may_leak_address($_)) {
+- print $file . ': ' . $_;
++ printf("$file: $_\n");
+ }
+ }
+ close $fh;
+diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
+index 7d631aaa0ae11..52a000b057a57 100755
+--- a/scripts/recordmcount.pl
++++ b/scripts/recordmcount.pl
+@@ -219,7 +219,7 @@ if ($arch eq "x86_64") {
+
+ } elsif ($arch eq "s390" && $bits == 64) {
+ if ($cc =~ /-DCC_USING_HOTPATCH/) {
+- $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
++ $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
+ $mcount_adjust = 0;
+ }
+ $alignment = 8;
+diff --git a/security/Kconfig b/security/Kconfig
+index 0ced7fd33e4d0..fe6c0395fa025 100644
+--- a/security/Kconfig
++++ b/security/Kconfig
+@@ -191,6 +191,9 @@ config HARDENED_USERCOPY_PAGESPAN
+ config FORTIFY_SOURCE
+ bool "Harden common str/mem functions against buffer overflows"
+ depends on ARCH_HAS_FORTIFY_SOURCE
++ # https://bugs.llvm.org/show_bug.cgi?id=50322
++ # https://bugs.llvm.org/show_bug.cgi?id=41459
++ depends on !CC_IS_CLANG
+ help
+ Detect overflows of buffers in common string and memory functions
+ where the compiler can determine and validate the buffer sizes.
+diff --git a/security/apparmor/label.c b/security/apparmor/label.c
+index e68bcedca976b..6222fdfebe4e5 100644
+--- a/security/apparmor/label.c
++++ b/security/apparmor/label.c
+@@ -1454,7 +1454,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
+ if (label->hname || labels_ns(label) != ns)
+ return res;
+
+- if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) == -1)
++ if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0)
+ return res;
+
+ ls = labels_set(label);
+@@ -1704,7 +1704,7 @@ int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
+
+ /**
+ * aa_label_acntsxprint - allocate a __counted string buffer and print label
+- * @strp: buffer to write to. (MAY BE NULL if @size == 0)
++ * @strp: buffer to write to.
+ * @ns: namespace profile is being viewed from
+ * @label: label to view (NOT NULL)
+ * @flags: flags controlling what label info is printed
+diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
+index 1c8435dfabeea..08f907382c618 100644
+--- a/security/integrity/evm/evm_main.c
++++ b/security/integrity/evm/evm_main.c
+@@ -78,7 +78,7 @@ static struct xattr_list evm_config_default_xattrnames[] = {
+
+ LIST_HEAD(evm_config_xattrnames);
+
+-static int evm_fixmode;
++static int evm_fixmode __ro_after_init;
+ static int __init evm_set_fixmode(char *str)
+ {
+ if (strncmp(str, "fix", 3) == 0)
+diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
+index 87b9b71cb8201..12e8adcd80a2a 100644
+--- a/security/integrity/ima/ima_policy.c
++++ b/security/integrity/ima/ima_policy.c
+@@ -228,7 +228,7 @@ static struct ima_rule_entry *arch_policy_entry __ro_after_init;
+ static LIST_HEAD(ima_default_rules);
+ static LIST_HEAD(ima_policy_rules);
+ static LIST_HEAD(ima_temp_rules);
+-static struct list_head *ima_rules = &ima_default_rules;
++static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules);
+
+ static int ima_policy __initdata;
+
+@@ -675,12 +675,14 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
+ {
+ struct ima_rule_entry *entry;
+ int action = 0, actmask = flags | (flags << 1);
++ struct list_head *ima_rules_tmp;
+
+ if (template_desc && !*template_desc)
+ *template_desc = ima_template_desc_current();
+
+ rcu_read_lock();
+- list_for_each_entry_rcu(entry, ima_rules, list) {
++ ima_rules_tmp = rcu_dereference(ima_rules);
++ list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
+
+ if (!(entry->action & actmask))
+ continue;
+@@ -741,9 +743,11 @@ void ima_update_policy_flags(void)
+ {
+ struct ima_rule_entry *entry;
+ int new_policy_flag = 0;
++ struct list_head *ima_rules_tmp;
+
+ rcu_read_lock();
+- list_for_each_entry(entry, ima_rules, list) {
++ ima_rules_tmp = rcu_dereference(ima_rules);
++ list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
+ /*
+ * SETXATTR_CHECK rules do not implement a full policy check
+ * because rule checking would probably have an important
+@@ -968,10 +972,10 @@ void ima_update_policy(void)
+
+ list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
+
+- if (ima_rules != policy) {
++ if (ima_rules != (struct list_head __rcu *)policy) {
+ ima_policy_flag = 0;
+- ima_rules = policy;
+
++ rcu_assign_pointer(ima_rules, policy);
+ /*
+ * IMA architecture specific policy rules are specified
+ * as strings and converted to an array of ima_entry_rules
+@@ -1061,7 +1065,7 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
+ pr_warn("rule for LSM \'%s\' is undefined\n",
+ entry->lsm[lsm_rule].args_p);
+
+- if (ima_rules == &ima_default_rules) {
++ if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) {
+ kfree(entry->lsm[lsm_rule].args_p);
+ entry->lsm[lsm_rule].args_p = NULL;
+ result = -EINVAL;
+@@ -1768,9 +1772,11 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)
+ {
+ loff_t l = *pos;
+ struct ima_rule_entry *entry;
++ struct list_head *ima_rules_tmp;
+
+ rcu_read_lock();
+- list_for_each_entry_rcu(entry, ima_rules, list) {
++ ima_rules_tmp = rcu_dereference(ima_rules);
++ list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
+ if (!l--) {
+ rcu_read_unlock();
+ return entry;
+@@ -1789,7 +1795,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
+ rcu_read_unlock();
+ (*pos)++;
+
+- return (&entry->list == ima_rules) ? NULL : entry;
++ return (&entry->list == &ima_default_rules ||
++ &entry->list == &ima_policy_rules) ? NULL : entry;
+ }
+
+ void ima_policy_stop(struct seq_file *m, void *v)
+@@ -2014,6 +2021,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
+ struct ima_rule_entry *entry;
+ bool found = false;
+ enum ima_hooks func;
++ struct list_head *ima_rules_tmp;
+
+ if (id >= READING_MAX_ID)
+ return false;
+@@ -2021,7 +2029,8 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
+ func = read_idmap[id] ?: FILE_CHECK;
+
+ rcu_read_lock();
+- list_for_each_entry_rcu(entry, ima_rules, list) {
++ ima_rules_tmp = rcu_dereference(ima_rules);
++ list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
+ if (entry->action != APPRAISE)
+ continue;
+
+diff --git a/security/security.c b/security/security.c
+index 9ffa9e9c5c554..67264cb08fb31 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -747,25 +747,25 @@ static int lsm_superblock_alloc(struct super_block *sb)
+
+ /* Security operations */
+
+-int security_binder_set_context_mgr(struct task_struct *mgr)
++int security_binder_set_context_mgr(const struct cred *mgr)
+ {
+ return call_int_hook(binder_set_context_mgr, 0, mgr);
+ }
+
+-int security_binder_transaction(struct task_struct *from,
+- struct task_struct *to)
++int security_binder_transaction(const struct cred *from,
++ const struct cred *to)
+ {
+ return call_int_hook(binder_transaction, 0, from, to);
+ }
+
+-int security_binder_transfer_binder(struct task_struct *from,
+- struct task_struct *to)
++int security_binder_transfer_binder(const struct cred *from,
++ const struct cred *to)
+ {
+ return call_int_hook(binder_transfer_binder, 0, from, to);
+ }
+
+-int security_binder_transfer_file(struct task_struct *from,
+- struct task_struct *to, struct file *file)
++int security_binder_transfer_file(const struct cred *from,
++ const struct cred *to, struct file *file)
+ {
+ return call_int_hook(binder_transfer_file, 0, from, to, file);
+ }
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index e7ebd45ca3457..51432ea74044e 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -255,29 +255,6 @@ static inline u32 task_sid_obj(const struct task_struct *task)
+ return sid;
+ }
+
+-/*
+- * get the security ID of a task for use with binder
+- */
+-static inline u32 task_sid_binder(const struct task_struct *task)
+-{
+- /*
+- * In many case where this function is used we should be using the
+- * task's subjective SID, but we can't reliably access the subjective
+- * creds of a task other than our own so we must use the objective
+- * creds/SID, which are safe to access. The downside is that if a task
+- * is temporarily overriding it's creds it will not be reflected here;
+- * however, it isn't clear that binder would handle that case well
+- * anyway.
+- *
+- * If this ever changes and we can safely reference the subjective
+- * creds/SID of another task, this function will make it easier to
+- * identify the various places where we make use of the task SIDs in
+- * the binder code. It is also likely that we will need to adjust
+- * the main drivers/android binder code as well.
+- */
+- return task_sid_obj(task);
+-}
+-
+ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
+
+ /*
+@@ -634,10 +611,11 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
+ return 0;
+ }
+
+-static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
++static int parse_sid(struct super_block *sb, const char *s, u32 *sid,
++ gfp_t gfp)
+ {
+ int rc = security_context_str_to_sid(&selinux_state, s,
+- sid, GFP_KERNEL);
++ sid, gfp);
+ if (rc)
+ pr_warn("SELinux: security_context_str_to_sid"
+ "(%s) failed for (dev %s, type %s) errno=%d\n",
+@@ -708,7 +686,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ */
+ if (opts) {
+ if (opts->fscontext) {
+- rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
++ rc = parse_sid(sb, opts->fscontext, &fscontext_sid,
++ GFP_KERNEL);
+ if (rc)
+ goto out;
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+@@ -717,7 +696,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ sbsec->flags |= FSCONTEXT_MNT;
+ }
+ if (opts->context) {
+- rc = parse_sid(sb, opts->context, &context_sid);
++ rc = parse_sid(sb, opts->context, &context_sid,
++ GFP_KERNEL);
+ if (rc)
+ goto out;
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+@@ -726,7 +706,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ sbsec->flags |= CONTEXT_MNT;
+ }
+ if (opts->rootcontext) {
+- rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
++ rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid,
++ GFP_KERNEL);
+ if (rc)
+ goto out;
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+@@ -735,7 +716,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ sbsec->flags |= ROOTCONTEXT_MNT;
+ }
+ if (opts->defcontext) {
+- rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
++ rc = parse_sid(sb, opts->defcontext, &defcontext_sid,
++ GFP_KERNEL);
+ if (rc)
+ goto out;
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+@@ -2066,18 +2048,19 @@ static inline u32 open_file_to_av(struct file *file)
+
+ /* Hook functions begin here. */
+
+-static int selinux_binder_set_context_mgr(struct task_struct *mgr)
++static int selinux_binder_set_context_mgr(const struct cred *mgr)
+ {
+ return avc_has_perm(&selinux_state,
+- current_sid(), task_sid_binder(mgr), SECCLASS_BINDER,
++ current_sid(), cred_sid(mgr), SECCLASS_BINDER,
+ BINDER__SET_CONTEXT_MGR, NULL);
+ }
+
+-static int selinux_binder_transaction(struct task_struct *from,
+- struct task_struct *to)
++static int selinux_binder_transaction(const struct cred *from,
++ const struct cred *to)
+ {
+ u32 mysid = current_sid();
+- u32 fromsid = task_sid_binder(from);
++ u32 fromsid = cred_sid(from);
++ u32 tosid = cred_sid(to);
+ int rc;
+
+ if (mysid != fromsid) {
+@@ -2088,24 +2071,24 @@ static int selinux_binder_transaction(struct task_struct *from,
+ return rc;
+ }
+
+- return avc_has_perm(&selinux_state, fromsid, task_sid_binder(to),
++ return avc_has_perm(&selinux_state, fromsid, tosid,
+ SECCLASS_BINDER, BINDER__CALL, NULL);
+ }
+
+-static int selinux_binder_transfer_binder(struct task_struct *from,
+- struct task_struct *to)
++static int selinux_binder_transfer_binder(const struct cred *from,
++ const struct cred *to)
+ {
+ return avc_has_perm(&selinux_state,
+- task_sid_binder(from), task_sid_binder(to),
++ cred_sid(from), cred_sid(to),
+ SECCLASS_BINDER, BINDER__TRANSFER,
+ NULL);
+ }
+
+-static int selinux_binder_transfer_file(struct task_struct *from,
+- struct task_struct *to,
++static int selinux_binder_transfer_file(const struct cred *from,
++ const struct cred *to,
+ struct file *file)
+ {
+- u32 sid = task_sid_binder(to);
++ u32 sid = cred_sid(to);
+ struct file_security_struct *fsec = selinux_file(file);
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode_security_struct *isec;
+@@ -2723,14 +2706,14 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
+ return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
+
+ if (opts->fscontext) {
+- rc = parse_sid(sb, opts->fscontext, &sid);
++ rc = parse_sid(sb, opts->fscontext, &sid, GFP_NOWAIT);
+ if (rc)
+ return 1;
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ return 1;
+ }
+ if (opts->context) {
+- rc = parse_sid(sb, opts->context, &sid);
++ rc = parse_sid(sb, opts->context, &sid, GFP_NOWAIT);
+ if (rc)
+ return 1;
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+@@ -2740,14 +2723,14 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
+ struct inode_security_struct *root_isec;
+
+ root_isec = backing_inode_security(sb->s_root);
+- rc = parse_sid(sb, opts->rootcontext, &sid);
++ rc = parse_sid(sb, opts->rootcontext, &sid, GFP_NOWAIT);
+ if (rc)
+ return 1;
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ return 1;
+ }
+ if (opts->defcontext) {
+- rc = parse_sid(sb, opts->defcontext, &sid);
++ rc = parse_sid(sb, opts->defcontext, &sid, GFP_NOWAIT);
+ if (rc)
+ return 1;
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+@@ -2770,14 +2753,14 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
+ return 0;
+
+ if (opts->fscontext) {
+- rc = parse_sid(sb, opts->fscontext, &sid);
++ rc = parse_sid(sb, opts->fscontext, &sid, GFP_KERNEL);
+ if (rc)
+ return rc;
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ goto out_bad_option;
+ }
+ if (opts->context) {
+- rc = parse_sid(sb, opts->context, &sid);
++ rc = parse_sid(sb, opts->context, &sid, GFP_KERNEL);
+ if (rc)
+ return rc;
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+@@ -2786,14 +2769,14 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
+ if (opts->rootcontext) {
+ struct inode_security_struct *root_isec;
+ root_isec = backing_inode_security(sb->s_root);
+- rc = parse_sid(sb, opts->rootcontext, &sid);
++ rc = parse_sid(sb, opts->rootcontext, &sid, GFP_KERNEL);
+ if (rc)
+ return rc;
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ goto out_bad_option;
+ }
+ if (opts->defcontext) {
+- rc = parse_sid(sb, opts->defcontext, &sid);
++ rc = parse_sid(sb, opts->defcontext, &sid, GFP_KERNEL);
+ if (rc)
+ return rc;
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
+index b8f6b3e0a9219..a91fb0ed00de3 100644
+--- a/security/selinux/ss/hashtab.c
++++ b/security/selinux/ss/hashtab.c
+@@ -30,13 +30,20 @@ static u32 hashtab_compute_size(u32 nel)
+
+ int hashtab_init(struct hashtab *h, u32 nel_hint)
+ {
+- h->size = hashtab_compute_size(nel_hint);
++ u32 size = hashtab_compute_size(nel_hint);
++
++ /* should already be zeroed, but better be safe */
+ h->nel = 0;
+- if (!h->size)
+- return 0;
++ h->size = 0;
++ h->htable = NULL;
+
+- h->htable = kcalloc(h->size, sizeof(*h->htable), GFP_KERNEL);
+- return h->htable ? 0 : -ENOMEM;
++ if (size) {
++ h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL);
++ if (!h->htable)
++ return -ENOMEM;
++ h->size = size;
++ }
++ return 0;
+ }
+
+ int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
+diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
+index e5f1b2757a83a..c4931bf6f92a4 100644
+--- a/security/selinux/ss/services.c
++++ b/security/selinux/ss/services.c
+@@ -2376,6 +2376,43 @@ err_policy:
+ return rc;
+ }
+
++/**
++ * ocontext_to_sid - Helper to safely get sid for an ocontext
++ * @sidtab: SID table
++ * @c: ocontext structure
++ * @index: index of the context entry (0 or 1)
++ * @out_sid: pointer to the resulting SID value
++ *
++ * For all ocontexts except OCON_ISID the SID fields are populated
++ * on-demand when needed. Since updating the SID value is an SMP-sensitive
++ * operation, this helper must be used to do that safely.
++ *
++ * WARNING: This function may return -ESTALE, indicating that the caller
++ * must retry the operation after re-acquiring the policy pointer!
++ */
++static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
++ size_t index, u32 *out_sid)
++{
++ int rc;
++ u32 sid;
++
++ /* Ensure the associated sidtab entry is visible to this thread. */
++ sid = smp_load_acquire(&c->sid[index]);
++ if (!sid) {
++ rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
++ if (rc)
++ return rc;
++
++ /*
++ * Ensure the new sidtab entry is visible to other threads
++ * when they see the SID.
++ */
++ smp_store_release(&c->sid[index], sid);
++ }
++ *out_sid = sid;
++ return 0;
++}
++
+ /**
+ * security_port_sid - Obtain the SID for a port.
+ * @state: SELinux state
+@@ -2414,17 +2451,13 @@ retry:
+ }
+
+ if (c) {
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab, &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- *out_sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else {
+ *out_sid = SECINITSID_PORT;
+ }
+@@ -2473,18 +2506,13 @@ retry:
+ }
+
+ if (c) {
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab,
+- &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- *out_sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else
+ *out_sid = SECINITSID_UNLABELED;
+
+@@ -2533,17 +2561,13 @@ retry:
+ }
+
+ if (c) {
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab, &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- *out_sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else
+ *out_sid = SECINITSID_UNLABELED;
+
+@@ -2587,25 +2611,13 @@ retry:
+ }
+
+ if (c) {
+- if (!c->sid[0] || !c->sid[1]) {
+- rc = sidtab_context_to_sid(sidtab, &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
+- rc = sidtab_context_to_sid(sidtab, &c->context[1],
+- &c->sid[1]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, if_sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- *if_sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else
+ *if_sid = SECINITSID_NETIF;
+
+@@ -2697,18 +2709,13 @@ retry:
+ }
+
+ if (c) {
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab,
+- &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, out_sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- *out_sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else {
+ *out_sid = SECINITSID_NODE;
+ }
+@@ -2873,7 +2880,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
+ u16 sclass;
+ struct genfs *genfs;
+ struct ocontext *c;
+- int rc, cmp = 0;
++ int cmp = 0;
+
+ while (path[0] == '/' && path[1] == '/')
+ path++;
+@@ -2887,9 +2894,8 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
+ break;
+ }
+
+- rc = -ENOENT;
+ if (!genfs || cmp)
+- goto out;
++ return -ENOENT;
+
+ for (c = genfs->head; c; c = c->next) {
+ len = strlen(c->u.name);
+@@ -2898,20 +2904,10 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
+ break;
+ }
+
+- rc = -ENOENT;
+ if (!c)
+- goto out;
+-
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
+- if (rc)
+- goto out;
+- }
++ return -ENOENT;
+
+- *sid = c->sid[0];
+- rc = 0;
+-out:
+- return rc;
++ return ocontext_to_sid(sidtab, c, 0, sid);
+ }
+
+ /**
+@@ -2996,17 +2992,13 @@ retry:
+
+ if (c) {
+ sbsec->behavior = c->v.behavior;
+- if (!c->sid[0]) {
+- rc = sidtab_context_to_sid(sidtab, &c->context[0],
+- &c->sid[0]);
+- if (rc == -ESTALE) {
+- rcu_read_unlock();
+- goto retry;
+- }
+- if (rc)
+- goto out;
++ rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
++ if (rc == -ESTALE) {
++ rcu_read_unlock();
++ goto retry;
+ }
+- sbsec->sid = c->sid[0];
++ if (rc)
++ goto out;
+ } else {
+ rc = __security_genfs_sid(policy, fstype, "/",
+ SECCLASS_DIR, &sbsec->sid);
+diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
+index 3a75d2a8f5178..658eab05599e6 100644
+--- a/security/smack/smackfs.c
++++ b/security/smack/smackfs.c
+@@ -693,9 +693,7 @@ static void smk_cipso_doi(void)
+ printk(KERN_WARNING "%s:%d remove rc = %d\n",
+ __func__, __LINE__, rc);
+
+- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
+- if (doip == NULL)
+- panic("smack: Failed to initialize cipso DOI.\n");
++ doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL);
+ doip->map.std = NULL;
+ doip->doi = smk_cipso_doi_value;
+ doip->type = CIPSO_V4_MAP_PASS;
+@@ -714,7 +712,7 @@ static void smk_cipso_doi(void)
+ if (rc != 0) {
+ printk(KERN_WARNING "%s:%d map add rc = %d\n",
+ __func__, __LINE__, rc);
+- kfree(doip);
++ netlbl_cfg_cipsov4_del(doip->doi, &nai);
+ return;
+ }
+ }
+@@ -831,6 +829,7 @@ static int smk_open_cipso(struct inode *inode, struct file *file)
+ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos, int format)
+ {
++ struct netlbl_lsm_catmap *old_cat;
+ struct smack_known *skp;
+ struct netlbl_lsm_secattr ncats;
+ char mapcatset[SMK_CIPSOLEN];
+@@ -920,9 +919,11 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
+
+ rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN);
+ if (rc >= 0) {
+- netlbl_catmap_free(skp->smk_netlabel.attr.mls.cat);
++ old_cat = skp->smk_netlabel.attr.mls.cat;
+ skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat;
+ skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
++ synchronize_rcu();
++ netlbl_catmap_free(old_cat);
+ rc = count;
+ /*
+ * This mapping may have been cached, so clear the cache.
+diff --git a/sound/core/Makefile b/sound/core/Makefile
+index d774792850f31..79e1407cd0de7 100644
+--- a/sound/core/Makefile
++++ b/sound/core/Makefile
+@@ -9,7 +9,9 @@ ifneq ($(CONFIG_SND_PROC_FS),)
+ snd-y += info.o
+ snd-$(CONFIG_SND_OSSEMUL) += info_oss.o
+ endif
++ifneq ($(CONFIG_M68K),y)
+ snd-$(CONFIG_ISA_DMA_API) += isadma.o
++endif
+ snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
+ snd-$(CONFIG_SND_VMASTER) += vmaster.o
+ snd-$(CONFIG_SND_JACK) += ctljack.o jack.o
+diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
+index 470dabc60aa0e..edff063e088d2 100644
+--- a/sound/core/control_compat.c
++++ b/sound/core/control_compat.c
+@@ -264,6 +264,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
+ struct snd_ctl_elem_value *data,
+ int type, int count)
+ {
++ struct snd_ctl_elem_value32 __user *data32 = userdata;
+ int i, size;
+
+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+@@ -280,6 +281,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
+ if (copy_to_user(valuep, data->value.bytes.data, size))
+ return -EFAULT;
+ }
++ if (copy_to_user(&data32->id, &data->id, sizeof(data32->id)))
++ return -EFAULT;
+ return 0;
+ }
+
+diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
+index c7c943c661e63..2d842982576bb 100644
+--- a/sound/core/memalloc.c
++++ b/sound/core/memalloc.c
+@@ -176,8 +176,11 @@ EXPORT_SYMBOL_GPL(snd_devm_alloc_pages);
+ int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
+ struct vm_area_struct *area)
+ {
+- const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
++ const struct snd_malloc_ops *ops;
+
++ if (!dmab)
++ return -ENOENT;
++ ops = snd_dma_get_ops(dmab);
+ if (ops && ops->mmap)
+ return ops->mmap(dmab, area);
+ else
+@@ -491,6 +494,8 @@ static const struct snd_malloc_ops *dma_ops[] = {
+
+ static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab)
+ {
++ if (WARN_ON_ONCE(!dmab))
++ return NULL;
+ if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN ||
+ dmab->dev.type >= ARRAY_SIZE(dma_ops)))
+ return NULL;
+diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
+index 6a5abdd4271ba..9620115cfdc09 100644
+--- a/sound/core/oss/mixer_oss.c
++++ b/sound/core/oss/mixer_oss.c
+@@ -130,11 +130,13 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
+
+ if (mixer == NULL)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ for (chn = 0; chn < 31; chn++) {
+ pslot = &mixer->slots[chn];
+ if (pslot->put_volume || pslot->put_recsrc)
+ result |= 1 << chn;
+ }
++ mutex_unlock(&mixer->reg_mutex);
+ return result;
+ }
+
+@@ -146,11 +148,13 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
+
+ if (mixer == NULL)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ for (chn = 0; chn < 31; chn++) {
+ pslot = &mixer->slots[chn];
+ if (pslot->put_volume && pslot->stereo)
+ result |= 1 << chn;
+ }
++ mutex_unlock(&mixer->reg_mutex);
+ return result;
+ }
+
+@@ -161,6 +165,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
+
+ if (mixer == NULL)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
+ result = mixer->mask_recsrc;
+ } else {
+@@ -172,6 +177,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
+ result |= 1 << chn;
+ }
+ }
++ mutex_unlock(&mixer->reg_mutex);
+ return result;
+ }
+
+@@ -182,12 +188,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
+
+ if (mixer == NULL)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
+- int err;
+ unsigned int index;
+- err = mixer->get_recsrc(fmixer, &index);
+- if (err < 0)
+- return err;
++ result = mixer->get_recsrc(fmixer, &index);
++ if (result < 0)
++ goto unlock;
+ result = 1 << index;
+ } else {
+ struct snd_mixer_oss_slot *pslot;
+@@ -202,7 +208,10 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
+ }
+ }
+ }
+- return mixer->oss_recsrc = result;
++ mixer->oss_recsrc = result;
++ unlock:
++ mutex_unlock(&mixer->reg_mutex);
++ return result;
+ }
+
+ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
+@@ -215,6 +224,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
+
+ if (mixer == NULL)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
+ if (recsrc & ~mixer->oss_recsrc)
+ recsrc &= ~mixer->oss_recsrc;
+@@ -240,6 +250,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
+ }
+ }
+ }
++ mutex_unlock(&mixer->reg_mutex);
+ return result;
+ }
+
+@@ -251,6 +262,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
+
+ if (mixer == NULL || slot > 30)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ pslot = &mixer->slots[slot];
+ left = pslot->volume[0];
+ right = pslot->volume[1];
+@@ -258,15 +270,21 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
+ result = pslot->get_volume(fmixer, pslot, &left, &right);
+ if (!pslot->stereo)
+ right = left;
+- if (snd_BUG_ON(left < 0 || left > 100))
+- return -EIO;
+- if (snd_BUG_ON(right < 0 || right > 100))
+- return -EIO;
++ if (snd_BUG_ON(left < 0 || left > 100)) {
++ result = -EIO;
++ goto unlock;
++ }
++ if (snd_BUG_ON(right < 0 || right > 100)) {
++ result = -EIO;
++ goto unlock;
++ }
+ if (result >= 0) {
+ pslot->volume[0] = left;
+ pslot->volume[1] = right;
+ result = (left & 0xff) | ((right & 0xff) << 8);
+ }
++ unlock:
++ mutex_unlock(&mixer->reg_mutex);
+ return result;
+ }
+
+@@ -279,6 +297,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
+
+ if (mixer == NULL || slot > 30)
+ return -EIO;
++ mutex_lock(&mixer->reg_mutex);
+ pslot = &mixer->slots[slot];
+ if (left > 100)
+ left = 100;
+@@ -289,10 +308,13 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
+ if (pslot->put_volume)
+ result = pslot->put_volume(fmixer, pslot, left, right);
+ if (result < 0)
+- return result;
++ goto unlock;
+ pslot->volume[0] = left;
+ pslot->volume[1] = right;
+- return (left & 0xff) | ((right & 0xff) << 8);
++ result = (left & 0xff) | ((right & 0xff) << 8);
++ unlock:
++ mutex_unlock(&mixer->reg_mutex);
++ return result;
+ }
+
+ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
+diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
+index 82a818734a5f7..20a0a4771b9a8 100644
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -147,7 +147,7 @@ snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
+ *
+ * Return the maximum value for field PAR.
+ */
+-static unsigned int
++static int
+ snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
+ {
+@@ -682,18 +682,24 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *oss_params,
+ struct snd_pcm_hw_params *slave_params)
+ {
+- size_t s;
+- size_t oss_buffer_size, oss_period_size, oss_periods;
+- size_t min_period_size, max_period_size;
++ ssize_t s;
++ ssize_t oss_buffer_size;
++ ssize_t oss_period_size, oss_periods;
++ ssize_t min_period_size, max_period_size;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ size_t oss_frame_size;
+
+ oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
+ params_channels(oss_params) / 8;
+
++ oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
++ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
++ NULL);
++ if (oss_buffer_size <= 0)
++ return -EINVAL;
+ oss_buffer_size = snd_pcm_plug_client_size(substream,
+- snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
+- if (!oss_buffer_size)
++ oss_buffer_size * oss_frame_size);
++ if (oss_buffer_size <= 0)
+ return -EINVAL;
+ oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
+ if (atomic_read(&substream->mmap_count)) {
+@@ -730,7 +736,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
+
+ min_period_size = snd_pcm_plug_client_size(substream,
+ snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
+- if (min_period_size) {
++ if (min_period_size > 0) {
+ min_period_size *= oss_frame_size;
+ min_period_size = roundup_pow_of_two(min_period_size);
+ if (oss_period_size < min_period_size)
+@@ -739,7 +745,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
+
+ max_period_size = snd_pcm_plug_client_size(substream,
+ snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
+- if (max_period_size) {
++ if (max_period_size > 0) {
+ max_period_size *= oss_frame_size;
+ max_period_size = rounddown_pow_of_two(max_period_size);
+ if (oss_period_size > max_period_size)
+@@ -752,7 +758,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
+ oss_periods = substream->oss.setup.periods;
+
+ s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
+- if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
++ if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
+ s = runtime->oss.maxfrags;
+ if (oss_periods > s)
+ oss_periods = s;
+@@ -878,8 +884,15 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
+ err = -EINVAL;
+ goto failure;
+ }
+- choose_rate(substream, sparams, runtime->oss.rate);
+- snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
++
++ err = choose_rate(substream, sparams, runtime->oss.rate);
++ if (err < 0)
++ goto failure;
++ err = snd_pcm_hw_param_near(substream, sparams,
++ SNDRV_PCM_HW_PARAM_CHANNELS,
++ runtime->oss.channels, NULL);
++ if (err < 0)
++ goto failure;
+
+ format = snd_pcm_oss_format_from(runtime->oss.format);
+
+@@ -1956,7 +1969,7 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign
+ if (runtime->oss.subdivision || runtime->oss.fragshift)
+ return -EINVAL;
+ fragshift = val & 0xffff;
+- if (fragshift >= 31)
++ if (fragshift >= 25) /* should be large enough */
+ return -EINVAL;
+ runtime->oss.fragshift = fragshift;
+ runtime->oss.maxfrags = (val >> 16) & 0xffff;
+diff --git a/sound/core/timer.c b/sound/core/timer.c
+index 92b7008fcdb86..b3214baa89193 100644
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -624,13 +624,13 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
+ if (!timer)
+ return -EINVAL;
+ spin_lock_irqsave(&timer->lock, flags);
++ list_del_init(&timeri->ack_list);
++ list_del_init(&timeri->active_list);
+ if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
+ SNDRV_TIMER_IFLG_START))) {
+ result = -EBUSY;
+ goto unlock;
+ }
+- list_del_init(&timeri->ack_list);
+- list_del_init(&timeri->active_list);
+ if (timer->card && timer->card->shutdown)
+ goto unlock;
+ if (stop) {
+@@ -665,23 +665,22 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
+ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
+ {
+ unsigned long flags;
++ bool running;
+
+ spin_lock_irqsave(&slave_active_lock, flags);
+- if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) {
+- spin_unlock_irqrestore(&slave_active_lock, flags);
+- return -EBUSY;
+- }
++ running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
+ timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+ if (timeri->timer) {
+ spin_lock(&timeri->timer->lock);
+ list_del_init(&timeri->ack_list);
+ list_del_init(&timeri->active_list);
+- snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
+- SNDRV_TIMER_EVENT_PAUSE);
++ if (running)
++ snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
++ SNDRV_TIMER_EVENT_PAUSE);
+ spin_unlock(&timeri->timer->lock);
+ }
+ spin_unlock_irqrestore(&slave_active_lock, flags);
+- return 0;
++ return running ? 0 : -EBUSY;
+ }
+
+ /*
+diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
+index fff18b5d4e052..f4a702def3979 100644
+--- a/sound/firewire/oxfw/oxfw-stream.c
++++ b/sound/firewire/oxfw/oxfw-stream.c
+@@ -9,7 +9,7 @@
+ #include <linux/delay.h>
+
+ #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
+-#define READY_TIMEOUT_MS 200
++#define READY_TIMEOUT_MS 600
+
+ /*
+ * According to datasheet of Oxford Semiconductor:
+@@ -367,6 +367,11 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
+ // Just after changing sampling transfer frequency, many cycles are
+ // skipped for packet transmission.
+ tx_init_skip_cycles = 400;
++ } else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) {
++ // It takes a bit time for target device to adjust event frequency
++ // according to nominal event frequency in isochronous packets from
++ // ALSA oxfw driver.
++ tx_init_skip_cycles = 4000;
+ } else {
+ replay_seq = true;
+ }
+diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
+index daf731364695b..b496f87841aec 100644
+--- a/sound/firewire/oxfw/oxfw.c
++++ b/sound/firewire/oxfw/oxfw.c
+@@ -25,6 +25,7 @@
+ #define MODEL_SATELLITE 0x00200f
+ #define MODEL_SCS1M 0x001000
+ #define MODEL_DUET_FW 0x01dddd
++#define MODEL_ONYX_1640I 0x001640
+
+ #define SPECIFIER_1394TA 0x00a02d
+ #define VERSION_AVC 0x010001
+@@ -192,6 +193,13 @@ static int detect_quirks(struct snd_oxfw *oxfw, const struct ieee1394_device_id
+ // OXFW971-based models may transfer events by blocking method.
+ if (!(oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD))
+ oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION;
++
++ if (model == MODEL_ONYX_1640I) {
++ //Unless receiving packets without NOINFO packet, the device transfers
++ //mostly half of events in packets than expected.
++ oxfw->quirks |= SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET |
++ SND_OXFW_QUIRK_VOLUNTARY_RECOVERY;
++ }
+ }
+
+ return 0;
+diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
+index c13034f6c2ca5..d728e451a25c6 100644
+--- a/sound/firewire/oxfw/oxfw.h
++++ b/sound/firewire/oxfw/oxfw.h
+@@ -47,6 +47,11 @@ enum snd_oxfw_quirk {
+ // the device to process audio data even if the value is invalid in a point of
+ // IEC 61883-1/6.
+ SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET = 0x10,
++ // Loud Technologies Mackie Onyx 1640i seems to configure OXFW971 ASIC so that it decides
++ // event frequency according to events in received isochronous packets. The device looks to
++ // performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO
++ // are ignored, thus driver should transfer packets with timestamp.
++ SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20,
+ };
+
+ /* This is an arbitrary number for convinience. */
+diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
+index 0c005d67fa891..37154ed43bd53 100644
+--- a/sound/hda/ext/hdac_ext_stream.c
++++ b/sound/hda/ext/hdac_ext_stream.c
+@@ -106,20 +106,14 @@ void snd_hdac_stream_free_all(struct hdac_bus *bus)
+ }
+ EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
+
+-/**
+- * snd_hdac_ext_stream_decouple - decouple the hdac stream
+- * @bus: HD-audio core bus
+- * @stream: HD-audio ext core stream object to initialize
+- * @decouple: flag to decouple
+- */
+-void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
+- struct hdac_ext_stream *stream, bool decouple)
++void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
++ struct hdac_ext_stream *stream,
++ bool decouple)
+ {
+ struct hdac_stream *hstream = &stream->hstream;
+ u32 val;
+ int mask = AZX_PPCTL_PROCEN(hstream->index);
+
+- spin_lock_irq(&bus->reg_lock);
+ val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
+
+ if (decouple && !val)
+@@ -128,6 +122,20 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
+ snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
+
+ stream->decoupled = decouple;
++}
++EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple_locked);
++
++/**
++ * snd_hdac_ext_stream_decouple - decouple the hdac stream
++ * @bus: HD-audio core bus
++ * @stream: HD-audio ext core stream object to initialize
++ * @decouple: flag to decouple
++ */
++void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
++ struct hdac_ext_stream *stream, bool decouple)
++{
++ spin_lock_irq(&bus->reg_lock);
++ snd_hdac_ext_stream_decouple_locked(bus, stream, decouple);
+ spin_unlock_irq(&bus->reg_lock);
+ }
+ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
+@@ -252,6 +260,7 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
+ return NULL;
+ }
+
++ spin_lock_irq(&bus->reg_lock);
+ list_for_each_entry(stream, &bus->stream_list, list) {
+ struct hdac_ext_stream *hstream = container_of(stream,
+ struct hdac_ext_stream,
+@@ -266,17 +275,16 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
+ }
+
+ if (!hstream->link_locked) {
+- snd_hdac_ext_stream_decouple(bus, hstream, true);
++ snd_hdac_ext_stream_decouple_locked(bus, hstream, true);
+ res = hstream;
+ break;
+ }
+ }
+ if (res) {
+- spin_lock_irq(&bus->reg_lock);
+ res->link_locked = 1;
+ res->link_substream = substream;
+- spin_unlock_irq(&bus->reg_lock);
+ }
++ spin_unlock_irq(&bus->reg_lock);
+ return res;
+ }
+
+@@ -292,6 +300,7 @@ hdac_ext_host_stream_assign(struct hdac_bus *bus,
+ return NULL;
+ }
+
++ spin_lock_irq(&bus->reg_lock);
+ list_for_each_entry(stream, &bus->stream_list, list) {
+ struct hdac_ext_stream *hstream = container_of(stream,
+ struct hdac_ext_stream,
+@@ -301,18 +310,17 @@ hdac_ext_host_stream_assign(struct hdac_bus *bus,
+
+ if (!stream->opened) {
+ if (!hstream->decoupled)
+- snd_hdac_ext_stream_decouple(bus, hstream, true);
++ snd_hdac_ext_stream_decouple_locked(bus, hstream, true);
+ res = hstream;
+ break;
+ }
+ }
+ if (res) {
+- spin_lock_irq(&bus->reg_lock);
+ res->hstream.opened = 1;
+ res->hstream.running = 0;
+ res->hstream.substream = substream;
+- spin_unlock_irq(&bus->reg_lock);
+ }
++ spin_unlock_irq(&bus->reg_lock);
+
+ return res;
+ }
+@@ -378,15 +386,17 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
+ break;
+
+ case HDAC_EXT_STREAM_TYPE_HOST:
++ spin_lock_irq(&bus->reg_lock);
+ if (stream->decoupled && !stream->link_locked)
+- snd_hdac_ext_stream_decouple(bus, stream, false);
++ snd_hdac_ext_stream_decouple_locked(bus, stream, false);
++ spin_unlock_irq(&bus->reg_lock);
+ snd_hdac_stream_release(&stream->hstream);
+ break;
+
+ case HDAC_EXT_STREAM_TYPE_LINK:
+- if (stream->decoupled && !stream->hstream.opened)
+- snd_hdac_ext_stream_decouple(bus, stream, false);
+ spin_lock_irq(&bus->reg_lock);
++ if (stream->decoupled && !stream->hstream.opened)
++ snd_hdac_ext_stream_decouple_locked(bus, stream, false);
+ stream->link_locked = 0;
+ stream->link_substream = NULL;
+ spin_unlock_irq(&bus->reg_lock);
+diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
+index 1eb8563db2dff..9867555883c34 100644
+--- a/sound/hda/hdac_stream.c
++++ b/sound/hda/hdac_stream.c
+@@ -296,6 +296,7 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
+ int key = (substream->pcm->device << 16) | (substream->number << 2) |
+ (substream->stream + 1);
+
++ spin_lock_irq(&bus->reg_lock);
+ list_for_each_entry(azx_dev, &bus->stream_list, list) {
+ if (azx_dev->direction != substream->stream)
+ continue;
+@@ -309,13 +310,12 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
+ res = azx_dev;
+ }
+ if (res) {
+- spin_lock_irq(&bus->reg_lock);
+ res->opened = 1;
+ res->running = 0;
+ res->assigned_key = key;
+ res->substream = substream;
+- spin_unlock_irq(&bus->reg_lock);
+ }
++ spin_unlock_irq(&bus->reg_lock);
+ return res;
+ }
+ EXPORT_SYMBOL_GPL(snd_hdac_stream_assign);
+diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
+index c9d0ba353463b..4208fa8a4db5b 100644
+--- a/sound/hda/intel-dsp-config.c
++++ b/sound/hda/intel-dsp-config.c
+@@ -31,6 +31,7 @@ struct config_entry {
+ u16 device;
+ u8 acpi_hid[ACPI_ID_LEN];
+ const struct dmi_system_id *dmi_table;
++ u8 codec_hid[ACPI_ID_LEN];
+ };
+
+ /*
+@@ -56,7 +57,7 @@ static const struct config_entry config_table[] = {
+ /*
+ * Apollolake (Broxton-P)
+ * the legacy HDAudio driver is used except on Up Squared (SOF) and
+- * Chromebooks (SST)
++ * Chromebooks (SST), as well as devices based on the ES8336 codec
+ */
+ #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+ {
+@@ -73,6 +74,11 @@ static const struct config_entry config_table[] = {
+ {}
+ }
+ },
++ {
++ .flags = FLAG_SOF,
++ .device = 0x5a98,
++ .codec_hid = "ESSX8336",
++ },
+ #endif
+ #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
+ {
+@@ -137,7 +143,7 @@ static const struct config_entry config_table[] = {
+
+ /*
+ * Geminilake uses legacy HDAudio driver except for Google
+- * Chromebooks
++ * Chromebooks and devices based on the ES8336 codec
+ */
+ /* Geminilake */
+ #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
+@@ -154,6 +160,11 @@ static const struct config_entry config_table[] = {
+ {}
+ }
+ },
++ {
++ .flags = FLAG_SOF,
++ .device = 0x3198,
++ .codec_hid = "ESSX8336",
++ },
+ #endif
+
+ /*
+@@ -241,6 +252,11 @@ static const struct config_entry config_table[] = {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = 0x02c8,
+ },
++ {
++ .flags = FLAG_SOF,
++ .device = 0x02c8,
++ .codec_hid = "ESSX8336",
++ },
+ /* Cometlake-H */
+ {
+ .flags = FLAG_SOF,
+@@ -265,6 +281,11 @@ static const struct config_entry config_table[] = {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = 0x06c8,
+ },
++ {
++ .flags = FLAG_SOF,
++ .device = 0x06c8,
++ .codec_hid = "ESSX8336",
++ },
+ #endif
+
+ /* Icelake */
+@@ -288,6 +309,15 @@ static const struct config_entry config_table[] = {
+ },
+ #endif
+
++/* JasperLake */
++#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
++ {
++ .flags = FLAG_SOF,
++ .device = 0x4dc8,
++ .codec_hid = "ESSX8336",
++ },
++#endif
++
+ /* Tigerlake */
+ #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
+ {
+@@ -311,6 +341,11 @@ static const struct config_entry config_table[] = {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = 0x43c8,
+ },
++ {
++ .flags = FLAG_SOF,
++ .device = 0xa0c8,
++ .codec_hid = "ESSX8336",
++ },
+ #endif
+
+ /* Elkhart Lake */
+@@ -354,6 +389,8 @@ static const struct config_entry *snd_intel_dsp_find_config
+ continue;
+ if (table->dmi_table && !dmi_check_system(table->dmi_table))
+ continue;
++ if (table->codec_hid[0] && !acpi_dev_present(table->codec_hid, NULL, -1))
++ continue;
+ return table;
+ }
+ return NULL;
+diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
+index 6ffa48dd59830..570b88e0b2018 100644
+--- a/sound/isa/Kconfig
++++ b/sound/isa/Kconfig
+@@ -22,7 +22,7 @@ config SND_SB16_DSP
+ menuconfig SND_ISA
+ bool "ISA sound devices"
+ depends on ISA || COMPILE_TEST
+- depends on ISA_DMA_API
++ depends on ISA_DMA_API && !M68K
+ default y
+ help
+ Support for sound devices connected via the ISA bus.
+diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
+index a1c770d826dda..6d664dd8dde0b 100644
+--- a/sound/isa/gus/gus_dma.c
++++ b/sound/isa/gus/gus_dma.c
+@@ -126,6 +126,8 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
+ }
+ block = snd_gf1_dma_next_block(gus);
+ spin_unlock(&gus->dma_lock);
++ if (!block)
++ return;
+ snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
+ kfree(block);
+ #if 0
+diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
+index 93bc9bef7641f..41ce125971777 100644
+--- a/sound/pci/Kconfig
++++ b/sound/pci/Kconfig
+@@ -279,6 +279,7 @@ config SND_CS46XX_NEW_DSP
+ config SND_CS5530
+ tristate "CS5530 Audio"
+ depends on ISA_DMA_API && (X86_32 || COMPILE_TEST)
++ depends on !M68K
+ select SND_SB16_DSP
+ help
+ Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
+diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
+index da6e6350ceafa..d074727c3e21d 100644
+--- a/sound/pci/ctxfi/ctamixer.c
++++ b/sound/pci/ctxfi/ctamixer.c
+@@ -23,16 +23,15 @@
+
+ #define BLANK_SLOT 4094
+
+-static int amixer_master(struct rsc *rsc)
++static void amixer_master(struct rsc *rsc)
+ {
+ rsc->conj = 0;
+- return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
++ rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
+ }
+
+-static int amixer_next_conj(struct rsc *rsc)
++static void amixer_next_conj(struct rsc *rsc)
+ {
+ rsc->conj++;
+- return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
+ }
+
+ static int amixer_index(const struct rsc *rsc)
+@@ -331,16 +330,15 @@ int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
+
+ /* SUM resource management */
+
+-static int sum_master(struct rsc *rsc)
++static void sum_master(struct rsc *rsc)
+ {
+ rsc->conj = 0;
+- return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
++ rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
+ }
+
+-static int sum_next_conj(struct rsc *rsc)
++static void sum_next_conj(struct rsc *rsc)
+ {
+ rsc->conj++;
+- return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
+ }
+
+ static int sum_index(const struct rsc *rsc)
+diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
+index f589da0453424..7fc720046ce29 100644
+--- a/sound/pci/ctxfi/ctdaio.c
++++ b/sound/pci/ctxfi/ctdaio.c
+@@ -51,12 +51,12 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
+ [SPDIFIO] = {.left = 0x05, .right = 0x85},
+ };
+
+-static int daio_master(struct rsc *rsc)
++static void daio_master(struct rsc *rsc)
+ {
+ /* Actually, this is not the resource index of DAIO.
+ * For DAO, it is the input mapper index. And, for DAI,
+ * it is the output time-slot index. */
+- return rsc->conj = rsc->idx;
++ rsc->conj = rsc->idx;
+ }
+
+ static int daio_index(const struct rsc *rsc)
+@@ -64,19 +64,19 @@ static int daio_index(const struct rsc *rsc)
+ return rsc->conj;
+ }
+
+-static int daio_out_next_conj(struct rsc *rsc)
++static void daio_out_next_conj(struct rsc *rsc)
+ {
+- return rsc->conj += 2;
++ rsc->conj += 2;
+ }
+
+-static int daio_in_next_conj_20k1(struct rsc *rsc)
++static void daio_in_next_conj_20k1(struct rsc *rsc)
+ {
+- return rsc->conj += 0x200;
++ rsc->conj += 0x200;
+ }
+
+-static int daio_in_next_conj_20k2(struct rsc *rsc)
++static void daio_in_next_conj_20k2(struct rsc *rsc)
+ {
+- return rsc->conj += 0x100;
++ rsc->conj += 0x100;
+ }
+
+ static const struct rsc_ops daio_out_rsc_ops = {
+diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
+index 81ad269345182..be1d3e61309ce 100644
+--- a/sound/pci/ctxfi/ctresource.c
++++ b/sound/pci/ctxfi/ctresource.c
+@@ -109,18 +109,17 @@ static int audio_ring_slot(const struct rsc *rsc)
+ return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
+ }
+
+-static int rsc_next_conj(struct rsc *rsc)
++static void rsc_next_conj(struct rsc *rsc)
+ {
+ unsigned int i;
+ for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
+ i++;
+ rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
+- return rsc->conj;
+ }
+
+-static int rsc_master(struct rsc *rsc)
++static void rsc_master(struct rsc *rsc)
+ {
+- return rsc->conj = rsc->idx;
++ rsc->conj = rsc->idx;
+ }
+
+ static const struct rsc_ops rsc_generic_ops = {
+diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h
+index fdbfd808816d3..58553bda44f43 100644
+--- a/sound/pci/ctxfi/ctresource.h
++++ b/sound/pci/ctxfi/ctresource.h
+@@ -39,8 +39,8 @@ struct rsc {
+ };
+
+ struct rsc_ops {
+- int (*master)(struct rsc *rsc); /* Move to master resource */
+- int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
++ void (*master)(struct rsc *rsc); /* Move to master resource */
++ void (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
+ int (*index)(const struct rsc *rsc); /* Return the index of resource */
+ /* Return the output slot number */
+ int (*output_slot)(const struct rsc *rsc);
+diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
+index bd4697b442334..4a94b4708a77e 100644
+--- a/sound/pci/ctxfi/ctsrc.c
++++ b/sound/pci/ctxfi/ctsrc.c
+@@ -590,16 +590,15 @@ int src_mgr_destroy(struct src_mgr *src_mgr)
+
+ /* SRCIMP resource manager operations */
+
+-static int srcimp_master(struct rsc *rsc)
++static void srcimp_master(struct rsc *rsc)
+ {
+ rsc->conj = 0;
+- return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
++ rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
+ }
+
+-static int srcimp_next_conj(struct rsc *rsc)
++static void srcimp_next_conj(struct rsc *rsc)
+ {
+ rsc->conj++;
+- return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
+ }
+
+ static int srcimp_index(const struct rsc *rsc)
+diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
+index 4d22e7adeee8e..21fec82489bd7 100644
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -335,7 +335,10 @@ enum {
+ ((pci)->device == 0x0c0c) || \
+ ((pci)->device == 0x0d0c) || \
+ ((pci)->device == 0x160c) || \
+- ((pci)->device == 0x490d))
++ ((pci)->device == 0x490d) || \
++ ((pci)->device == 0x4f90) || \
++ ((pci)->device == 0x4f91) || \
++ ((pci)->device == 0x4f92))
+
+ #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+
+@@ -638,13 +641,17 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
+ * the update-IRQ timing. The IRQ is issued before actually the
+ * data is processed. So, we need to process it afterwords in a
+ * workqueue.
++ *
++ * Returns 1 if OK to proceed, 0 for delay handling, -1 for skipping update
+ */
+ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
+ {
+ struct snd_pcm_substream *substream = azx_dev->core.substream;
++ struct snd_pcm_runtime *runtime = substream->runtime;
+ int stream = substream->stream;
+ u32 wallclk;
+ unsigned int pos;
++ snd_pcm_uframes_t hwptr, target;
+
+ wallclk = azx_readl(chip, WALLCLK) - azx_dev->core.start_wallclk;
+ if (wallclk < (azx_dev->core.period_wallclk * 2) / 3)
+@@ -681,6 +688,24 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
+ /* NG - it's below the first next period boundary */
+ return chip->bdl_pos_adj ? 0 : -1;
+ azx_dev->core.start_wallclk += wallclk;
++
++ if (azx_dev->core.no_period_wakeup)
++ return 1; /* OK, no need to check period boundary */
++
++ if (runtime->hw_ptr_base != runtime->hw_ptr_interrupt)
++ return 1; /* OK, already in hwptr updating process */
++
++ /* check whether the period gets really elapsed */
++ pos = bytes_to_frames(runtime, pos);
++ hwptr = runtime->hw_ptr_base + pos;
++ if (hwptr < runtime->status->hw_ptr)
++ hwptr += runtime->buffer_size;
++ target = runtime->hw_ptr_interrupt + runtime->period_size;
++ if (hwptr < target) {
++ /* too early wakeup, process it later */
++ return chip->bdl_pos_adj ? 0 : -1;
++ }
++
+ return 1; /* OK, it's fine */
+ }
+
+@@ -859,31 +884,6 @@ static int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
+ return substream->runtime->delay;
+ }
+
+-static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
+- struct azx_dev *azx_dev)
+-{
+- return _snd_hdac_chip_readl(azx_bus(chip),
+- AZX_REG_VS_SDXDPIB_XBASE +
+- (AZX_REG_VS_SDXDPIB_XINTERVAL *
+- azx_dev->core.index));
+-}
+-
+-/* get the current DMA position with correction on SKL+ chips */
+-static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev)
+-{
+- /* DPIB register gives a more accurate position for playback */
+- if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+- return azx_skl_get_dpib_pos(chip, azx_dev);
+-
+- /* For capture, we need to read posbuf, but it requires a delay
+- * for the possible boundary overlap; the read of DPIB fetches the
+- * actual posbuf
+- */
+- udelay(20);
+- azx_skl_get_dpib_pos(chip, azx_dev);
+- return azx_get_pos_posbuf(chip, azx_dev);
+-}
+-
+ static void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset)
+ {
+ azx_stop_chip(chip);
+@@ -1573,7 +1573,7 @@ static void assign_position_fix(struct azx *chip, int fix)
+ [POS_FIX_POSBUF] = azx_get_pos_posbuf,
+ [POS_FIX_VIACOMBO] = azx_via_get_position,
+ [POS_FIX_COMBO] = azx_get_pos_lpib,
+- [POS_FIX_SKL] = azx_get_pos_skl,
++ [POS_FIX_SKL] = azx_get_pos_posbuf,
+ [POS_FIX_FIFO] = azx_get_pos_fifo,
+ };
+
+@@ -2330,7 +2330,8 @@ static int azx_probe_continue(struct azx *chip)
+
+ out_free:
+ if (err < 0) {
+- azx_free(chip);
++ pci_set_drvdata(pci, NULL);
++ snd_card_free(chip->card);
+ return err;
+ }
+
+@@ -2474,6 +2475,13 @@ static const struct pci_device_id azx_ids[] = {
+ /* DG1 */
+ { PCI_DEVICE(0x8086, 0x490d),
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
++ /* DG2 */
++ { PCI_DEVICE(0x8086, 0x4f90),
++ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
++ { PCI_DEVICE(0x8086, 0x4f91),
++ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
++ { PCI_DEVICE(0x8086, 0x4f92),
++ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ /* Alderlake-S */
+ { PCI_DEVICE(0x8086, 0x7ad0),
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
+index ea8ab8b433378..d22c96eb2f8fb 100644
+--- a/sound/pci/hda/hda_local.h
++++ b/sound/pci/hda/hda_local.h
+@@ -438,6 +438,15 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
+ #define for_each_hda_codec_node(nid, codec) \
+ for ((nid) = (codec)->core.start_nid; (nid) < (codec)->core.end_nid; (nid)++)
+
++/* Set the codec power_state flag to indicate to allow unsol event handling;
++ * see hda_codec_unsol_event() in hda_bind.c. Calling this might confuse the
++ * state tracking, so use with care.
++ */
++static inline void snd_hda_codec_allow_unsol_events(struct hda_codec *codec)
++{
++ codec->core.dev.power.power_state = PMSG_ON;
++}
++
+ /*
+ * get widget capabilities
+ */
+diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
+index 31ff11ab868e1..039b9f2f8e947 100644
+--- a/sound/pci/hda/patch_cs8409.c
++++ b/sound/pci/hda/patch_cs8409.c
+@@ -750,6 +750,11 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
+ if (cs42l42->full_scale_vol)
+ cs8409_i2c_write(cs42l42, 0x2001, 0x01);
+
++ /* we have to explicitly allow unsol event handling even during the
++ * resume phase so that the jack event is processed properly
++ */
++ snd_hda_codec_allow_unsol_events(cs42l42->codec);
++
+ cs42l42_enable_jack_detect(cs42l42);
+ }
+
+diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
+index 65d2c55399195..415701bd10ac8 100644
+--- a/sound/pci/hda/patch_hdmi.c
++++ b/sound/pci/hda/patch_hdmi.c
+@@ -4380,10 +4380,11 @@ HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
+ HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
+ HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
+ HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi),
+-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
+ HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
++HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi),
+ HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
+ HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
++HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
+ HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
+ HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
+ HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 965b096f416f6..3599f4c85ebf7 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -2539,6 +2539,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
++ SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
+@@ -4355,6 +4356,16 @@ static void alc287_fixup_hp_gpio_led(struct hda_codec *codec,
+ alc_fixup_hp_gpio_led(codec, action, 0x10, 0);
+ }
+
++static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ struct alc_spec *spec = codec->spec;
++
++ if (action == HDA_FIXUP_ACT_PRE_PROBE)
++ spec->micmute_led_polarity = 1;
++ alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
++}
++
+ /* turn on/off mic-mute LED per capture hook via VREF change */
+ static int vref_micmute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+@@ -6492,22 +6503,47 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
+ /* for alc285_fixup_ideapad_s740_coef() */
+ #include "ideapad_s740_helper.c"
+
+-static void alc256_fixup_tongfang_reset_persistent_settings(struct hda_codec *codec,
+- const struct hda_fixup *fix,
+- int action)
++static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
++ WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
++ WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
++ WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
++ {}
++};
++
++static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
++ const struct hda_fixup *fix,
++ int action)
+ {
+ /*
+- * A certain other OS sets these coeffs to different values. On at least one TongFang
+- * barebone these settings might survive even a cold reboot. So to restore a clean slate the
+- * values are explicitly reset to default here. Without this, the external microphone is
+- * always in a plugged-in state, while the internal microphone is always in an unplugged
+- * state, breaking the ability to use the internal microphone.
+- */
+- alc_write_coef_idx(codec, 0x24, 0x0000);
+- alc_write_coef_idx(codec, 0x26, 0x0000);
+- alc_write_coef_idx(codec, 0x29, 0x3000);
+- alc_write_coef_idx(codec, 0x37, 0xfe05);
+- alc_write_coef_idx(codec, 0x45, 0x5089);
++ * A certain other OS sets these coeffs to different values. On at least
++ * one TongFang barebone these settings might survive even a cold
++ * reboot. So to restore a clean slate the values are explicitly reset
++ * to default here. Without this, the external microphone is always in a
++ * plugged-in state, while the internal microphone is always in an
++ * unplugged state, breaking the ability to use the internal microphone.
++ */
++ alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
++}
++
++static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
++ WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
++ WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
++ WRITE_COEF(0x49, 0x0149),
++ {}
++};
++
++static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
++ const struct hda_fixup *fix,
++ int action)
++{
++ /*
++ * The audio jack input and output is not detected on the ASRock NUC Box
++ * 1100 series when cold booting without this fix. Warm rebooting from a
++ * certain other OS makes the audio functional, as COEF settings are
++ * preserved in this case. This fix sets these altered COEF values as
++ * the default.
++ */
++ alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
+ }
+
+ enum {
+@@ -6709,6 +6745,7 @@ enum {
+ ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+ ALC287_FIXUP_HP_GPIO_LED,
+ ALC256_FIXUP_HP_HEADSET_MIC,
++ ALC245_FIXUP_HP_GPIO_LED,
+ ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
+ ALC282_FIXUP_ACER_DISABLE_LINEOUT,
+ ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST,
+@@ -6726,7 +6763,9 @@ enum {
+ ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
+ ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
+ ALC287_FIXUP_13S_GEN2_SPEAKERS,
+- ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS,
++ ALC256_FIXUP_SET_COEF_DEFAULTS,
++ ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
++ ALC233_FIXUP_NO_AUDIO_JACK,
+ };
+
+ static const struct hda_fixup alc269_fixups[] = {
+@@ -7333,6 +7372,8 @@ static const struct hda_fixup alc269_fixups[] = {
+ [ALC245_FIXUP_HP_X360_AMP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_x360_amp,
++ .chained = true,
++ .chain_id = ALC245_FIXUP_HP_GPIO_LED
+ },
+ [ALC288_FIXUP_DELL_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+@@ -8428,9 +8469,26 @@ static const struct hda_fixup alc269_fixups[] = {
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MODE,
+ },
+- [ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS] = {
++ [ALC256_FIXUP_SET_COEF_DEFAULTS] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc256_fixup_set_coef_defaults,
++ },
++ [ALC245_FIXUP_HP_GPIO_LED] = {
+ .type = HDA_FIXUP_FUNC,
+- .v.func = alc256_fixup_tongfang_reset_persistent_settings,
++ .v.func = alc245_fixup_hp_gpio_led,
++ },
++ [ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x19, 0x03a11120 }, /* use as headset mic, without its own jack detect */
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
++ },
++ [ALC233_FIXUP_NO_AUDIO_JACK] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc233_fixup_no_audio_jack,
+ },
+ };
+
+@@ -8468,6 +8526,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC),
++ SND_PCI_QUIRK(0x1025, 0x141f, "Acer Spin SP513-54N", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
+@@ -8607,8 +8666,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
++ SND_PCI_QUIRK(0x103c, 0x8728, "HP EliteBook 840 G7", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
++ SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
+@@ -8617,6 +8678,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
+ ALC285_FIXUP_HP_GPIO_AMP_INIT),
++ SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+@@ -8668,6 +8730,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
++ SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1982, "ASUS B1400CEPE", ALC256_FIXUP_ASUS_HPE),
+ SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
+ SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
+@@ -8731,11 +8794,15 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x5015, "Clevo NH5[58]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x5017, "Clevo NH7[79]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50a3, "Clevo NJ51GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50b3, "Clevo NK50S[BEZ]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50b6, "Clevo NK50S5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50b8, "Clevo NK50SZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50d5, "Clevo NP50D5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x50e1, "Clevo NH5[58]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x50e2, "Clevo NH7[79]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50f0, "Clevo NH50A[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50f2, "Clevo NH50E[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x50f3, "Clevo NH58DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+@@ -8858,6 +8925,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
++ SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
+ SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
+ SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
+ SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
+@@ -8865,7 +8933,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
+ SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
+ SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
+- SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS),
++ SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
+ SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+@@ -10167,6 +10235,27 @@ static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
+ }
+ }
+
++static void alc897_hp_automute_hook(struct hda_codec *codec,
++ struct hda_jack_callback *jack)
++{
++ struct alc_spec *spec = codec->spec;
++ int vref;
++
++ snd_hda_gen_hp_automute(codec, jack);
++ vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
++ snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
++ vref);
++}
++
++static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ struct alc_spec *spec = codec->spec;
++ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
++ spec->gen.hp_automute_hook = alc897_hp_automute_hook;
++ }
++}
++
+ static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+@@ -10247,6 +10336,8 @@ enum {
+ ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
+ ALC668_FIXUP_HEADSET_MIC,
+ ALC668_FIXUP_MIC_DET_COEF,
++ ALC897_FIXUP_LENOVO_HEADSET_MIC,
++ ALC897_FIXUP_HEADSET_MIC_PIN,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -10653,6 +10744,19 @@ static const struct hda_fixup alc662_fixups[] = {
+ {}
+ },
+ },
++ [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc897_fixup_lenovo_headset_mic,
++ },
++ [ALC897_FIXUP_HEADSET_MIC_PIN] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1a, 0x03a11050 },
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -10697,6 +10801,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+ SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
++ SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
+index 75aa2ea733a59..96c12dfb24cf9 100644
+--- a/sound/pci/rme9652/hdsp.c
++++ b/sound/pci/rme9652/hdsp.c
+@@ -468,8 +468,11 @@ struct hdsp {
+ unsigned char ss_out_channels;
+ u32 io_loopback; /* output loopback channel states*/
+
+- struct snd_dma_buffer *capture_dma_buf;
+- struct snd_dma_buffer *playback_dma_buf;
++ /* DMA buffers; those are copied instances from the original snd_dma_buf
++ * objects (which are managed via devres) for the address alignments
++ */
++ struct snd_dma_buffer capture_dma_buf;
++ struct snd_dma_buffer playback_dma_buf;
+ unsigned char *capture_buffer; /* suitably aligned address */
+ unsigned char *playback_buffer; /* suitably aligned address */
+
+@@ -3764,30 +3767,32 @@ static void snd_hdsp_proc_init(struct hdsp *hdsp)
+
+ static int snd_hdsp_initialize_memory(struct hdsp *hdsp)
+ {
+- unsigned long pb_bus, cb_bus;
++ struct snd_dma_buffer *capture_dma, *playback_dma;
+
+- hdsp->capture_dma_buf =
+- snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
+- hdsp->playback_dma_buf =
+- snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
+- if (!hdsp->capture_dma_buf || !hdsp->playback_dma_buf) {
++ capture_dma = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
++ playback_dma = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES);
++ if (!capture_dma || !playback_dma) {
+ dev_err(hdsp->card->dev,
+ "%s: no buffers available\n", hdsp->card_name);
+ return -ENOMEM;
+ }
+
+- /* Align to bus-space 64K boundary */
++ /* copy to the own data for alignment */
++ hdsp->capture_dma_buf = *capture_dma;
++ hdsp->playback_dma_buf = *playback_dma;
+
+- cb_bus = ALIGN(hdsp->capture_dma_buf->addr, 0x10000ul);
+- pb_bus = ALIGN(hdsp->playback_dma_buf->addr, 0x10000ul);
++ /* Align to bus-space 64K boundary */
++ hdsp->capture_dma_buf.addr = ALIGN(capture_dma->addr, 0x10000ul);
++ hdsp->playback_dma_buf.addr = ALIGN(playback_dma->addr, 0x10000ul);
+
+ /* Tell the card where it is */
++ hdsp_write(hdsp, HDSP_inputBufferAddress, hdsp->capture_dma_buf.addr);
++ hdsp_write(hdsp, HDSP_outputBufferAddress, hdsp->playback_dma_buf.addr);
+
+- hdsp_write(hdsp, HDSP_inputBufferAddress, cb_bus);
+- hdsp_write(hdsp, HDSP_outputBufferAddress, pb_bus);
+-
+- hdsp->capture_buffer = hdsp->capture_dma_buf->area + (cb_bus - hdsp->capture_dma_buf->addr);
+- hdsp->playback_buffer = hdsp->playback_dma_buf->area + (pb_bus - hdsp->playback_dma_buf->addr);
++ hdsp->capture_dma_buf.area += hdsp->capture_dma_buf.addr - capture_dma->addr;
++ hdsp->playback_dma_buf.area += hdsp->playback_dma_buf.addr - playback_dma->addr;
++ hdsp->capture_buffer = hdsp->capture_dma_buf.area;
++ hdsp->playback_buffer = hdsp->playback_dma_buf.area;
+
+ return 0;
+ }
+@@ -4507,7 +4512,7 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
+ snd_pcm_set_sync(substream);
+
+ runtime->hw = snd_hdsp_playback_subinfo;
+- snd_pcm_set_runtime_buffer(substream, hdsp->playback_dma_buf);
++ snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf);
+
+ hdsp->playback_pid = current->pid;
+ hdsp->playback_substream = substream;
+@@ -4583,7 +4588,7 @@ static int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
+ snd_pcm_set_sync(substream);
+
+ runtime->hw = snd_hdsp_capture_subinfo;
+- snd_pcm_set_runtime_buffer(substream, hdsp->capture_dma_buf);
++ snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf);
+
+ hdsp->capture_pid = current->pid;
+ hdsp->capture_substream = substream;
+diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
+index e76f737ac9e8e..7755e19aa7761 100644
+--- a/sound/pci/rme9652/rme9652.c
++++ b/sound/pci/rme9652/rme9652.c
+@@ -208,8 +208,11 @@ struct snd_rme9652 {
+ unsigned char ds_channels;
+ unsigned char ss_channels; /* different for hammerfall/hammerfall-light */
+
+- struct snd_dma_buffer *playback_dma_buf;
+- struct snd_dma_buffer *capture_dma_buf;
++ /* DMA buffers; those are copied instances from the original snd_dma_buf
++ * objects (which are managed via devres) for the address alignments
++ */
++ struct snd_dma_buffer playback_dma_buf;
++ struct snd_dma_buffer capture_dma_buf;
+
+ unsigned char *capture_buffer; /* suitably aligned address */
+ unsigned char *playback_buffer; /* suitably aligned address */
+@@ -1719,30 +1722,32 @@ static void snd_rme9652_card_free(struct snd_card *card)
+
+ static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
+ {
+- unsigned long pb_bus, cb_bus;
++ struct snd_dma_buffer *capture_dma, *playback_dma;
+
+- rme9652->capture_dma_buf =
+- snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
+- rme9652->playback_dma_buf =
+- snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
+- if (!rme9652->capture_dma_buf || !rme9652->playback_dma_buf) {
++ capture_dma = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
++ playback_dma = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES);
++ if (!capture_dma || !playback_dma) {
+ dev_err(rme9652->card->dev,
+ "%s: no buffers available\n", rme9652->card_name);
+ return -ENOMEM;
+ }
+
+- /* Align to bus-space 64K boundary */
++ /* copy to the own data for alignment */
++ rme9652->capture_dma_buf = *capture_dma;
++ rme9652->playback_dma_buf = *playback_dma;
+
+- cb_bus = ALIGN(rme9652->capture_dma_buf->addr, 0x10000ul);
+- pb_bus = ALIGN(rme9652->playback_dma_buf->addr, 0x10000ul);
++ /* Align to bus-space 64K boundary */
++ rme9652->capture_dma_buf.addr = ALIGN(capture_dma->addr, 0x10000ul);
++ rme9652->playback_dma_buf.addr = ALIGN(playback_dma->addr, 0x10000ul);
+
+ /* Tell the card where it is */
++ rme9652_write(rme9652, RME9652_rec_buffer, rme9652->capture_dma_buf.addr);
++ rme9652_write(rme9652, RME9652_play_buffer, rme9652->playback_dma_buf.addr);
+
+- rme9652_write(rme9652, RME9652_rec_buffer, cb_bus);
+- rme9652_write(rme9652, RME9652_play_buffer, pb_bus);
+-
+- rme9652->capture_buffer = rme9652->capture_dma_buf->area + (cb_bus - rme9652->capture_dma_buf->addr);
+- rme9652->playback_buffer = rme9652->playback_dma_buf->area + (pb_bus - rme9652->playback_dma_buf->addr);
++ rme9652->capture_dma_buf.area += rme9652->capture_dma_buf.addr - capture_dma->addr;
++ rme9652->playback_dma_buf.area += rme9652->playback_dma_buf.addr - playback_dma->addr;
++ rme9652->capture_buffer = rme9652->capture_dma_buf.area;
++ rme9652->playback_buffer = rme9652->playback_dma_buf.area;
+
+ return 0;
+ }
+@@ -2259,7 +2264,7 @@ static int snd_rme9652_playback_open(struct snd_pcm_substream *substream)
+ snd_pcm_set_sync(substream);
+
+ runtime->hw = snd_rme9652_playback_subinfo;
+- snd_pcm_set_runtime_buffer(substream, rme9652->playback_dma_buf);
++ snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf);
+
+ if (rme9652->capture_substream == NULL) {
+ rme9652_stop(rme9652);
+@@ -2318,7 +2323,7 @@ static int snd_rme9652_capture_open(struct snd_pcm_substream *substream)
+ snd_pcm_set_sync(substream);
+
+ runtime->hw = snd_rme9652_capture_subinfo;
+- snd_pcm_set_runtime_buffer(substream, rme9652->capture_dma_buf);
++ snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf);
+
+ if (rme9652->playback_substream == NULL) {
+ rme9652_stop(rme9652);
+diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
+index 9a463ab54bddc..762d9de73dbc2 100644
+--- a/sound/soc/codecs/cs42l42.c
++++ b/sound/soc/codecs/cs42l42.c
+@@ -93,7 +93,7 @@ static const struct reg_default cs42l42_reg_defaults[] = {
+ { CS42L42_ASP_RX_INT_MASK, 0x1F },
+ { CS42L42_ASP_TX_INT_MASK, 0x0F },
+ { CS42L42_CODEC_INT_MASK, 0x03 },
+- { CS42L42_SRCPL_INT_MASK, 0xFF },
++ { CS42L42_SRCPL_INT_MASK, 0x7F },
+ { CS42L42_VPMON_INT_MASK, 0x01 },
+ { CS42L42_PLL_LOCK_INT_MASK, 0x01 },
+ { CS42L42_TSRS_PLUG_INT_MASK, 0x0F },
+@@ -130,7 +130,7 @@ static const struct reg_default cs42l42_reg_defaults[] = {
+ { CS42L42_MIXER_CHA_VOL, 0x3F },
+ { CS42L42_MIXER_ADC_VOL, 0x3F },
+ { CS42L42_MIXER_CHB_VOL, 0x3F },
+- { CS42L42_EQ_COEF_IN0, 0x22 },
++ { CS42L42_EQ_COEF_IN0, 0x00 },
+ { CS42L42_EQ_COEF_IN1, 0x00 },
+ { CS42L42_EQ_COEF_IN2, 0x00 },
+ { CS42L42_EQ_COEF_IN3, 0x00 },
+@@ -853,11 +853,10 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
+
+ switch(substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
+- if (channels == 2) {
+- val |= CS42L42_ASP_TX_CH2_AP_MASK;
+- val |= width << CS42L42_ASP_TX_CH2_RES_SHIFT;
+- }
+- val |= width << CS42L42_ASP_TX_CH1_RES_SHIFT;
++ /* channel 2 on high LRCLK */
++ val = CS42L42_ASP_TX_CH2_AP_MASK |
++ (width << CS42L42_ASP_TX_CH2_RES_SHIFT) |
++ (width << CS42L42_ASP_TX_CH1_RES_SHIFT);
+
+ snd_soc_component_update_bits(component, CS42L42_ASP_TX_CH_AP_RES,
+ CS42L42_ASP_TX_CH1_AP_MASK | CS42L42_ASP_TX_CH2_AP_MASK |
+@@ -1685,12 +1684,15 @@ static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42)
+ (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT));
+
+ /* Enable the tip sense circuit */
++ regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
++ CS42L42_TS_INV_MASK, CS42L42_TS_INV_MASK);
++
+ regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL,
+ CS42L42_TIP_SENSE_CTRL_MASK |
+ CS42L42_TIP_SENSE_INV_MASK |
+ CS42L42_TIP_SENSE_DEBOUNCE_MASK,
+ (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) |
+- (0 << CS42L42_TIP_SENSE_INV_SHIFT) |
++ (!cs42l42->ts_inv << CS42L42_TIP_SENSE_INV_SHIFT) |
+ (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT));
+
+ /* Save the initial status of the tip sense */
+@@ -1734,10 +1736,6 @@ static int cs42l42_handle_device_data(struct device *dev,
+ cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+ }
+
+- regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+- CS42L42_TS_INV_MASK,
+- (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT));
+-
+ ret = device_property_read_u32(dev, "cirrus,ts-dbnc-rise", &val);
+ if (!ret) {
+ switch (val) {
+@@ -1948,8 +1946,9 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
+ NULL, cs42l42_irq_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs42l42", cs42l42);
+-
+- if (ret != 0)
++ if (ret == -EPROBE_DEFER)
++ goto err_disable;
++ else if (ret != 0)
+ dev_err(&i2c_client->dev,
+ "Failed to request IRQ: %d\n", ret);
+
+diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
+index 067757d1d70a3..5fb02635c1406 100644
+--- a/sound/soc/codecs/es8316.c
++++ b/sound/soc/codecs/es8316.c
+@@ -811,12 +811,9 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client,
+ mutex_init(&es8316->lock);
+
+ ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq,
+- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ "es8316", es8316);
+- if (ret == 0) {
+- /* Gets re-enabled by es8316_set_jack() */
+- disable_irq(es8316->irq);
+- } else {
++ if (ret) {
+ dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret);
+ es8316->irq = -ENXIO;
+ }
+diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
+index 196b06898eeb2..07894ec5e7a61 100644
+--- a/sound/soc/codecs/lpass-rx-macro.c
++++ b/sound/soc/codecs/lpass-rx-macro.c
+@@ -2188,7 +2188,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
+ snd_soc_component_update_bits(component,
+ CDC_RX_CLSH_DECAY_CTRL,
+ CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
+- snd_soc_component_update_bits(component,
++ snd_soc_component_write_field(component,
+ CDC_RX_RX1_RX_PATH_CFG0,
+ CDC_RX_RXn_CLSH_EN_MASK, 0x1);
+ break;
+diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
+index f946ef65a4c19..f7018f2dd21fd 100644
+--- a/sound/soc/codecs/nau8824.c
++++ b/sound/soc/codecs/nau8824.c
+@@ -8,6 +8,7 @@
+
+ #include <linux/module.h>
+ #include <linux/delay.h>
++#include <linux/dmi.h>
+ #include <linux/init.h>
+ #include <linux/i2c.h>
+ #include <linux/regmap.h>
+@@ -27,6 +28,12 @@
+
+ #include "nau8824.h"
+
++#define NAU8824_JD_ACTIVE_HIGH BIT(0)
++
++static int nau8824_quirk;
++static int quirk_override = -1;
++module_param_named(quirk, quirk_override, uint, 0444);
++MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
+ static int nau8824_config_sysclk(struct nau8824 *nau8824,
+ int clk_id, unsigned int freq);
+@@ -1845,6 +1852,34 @@ static int nau8824_read_device_properties(struct device *dev,
+ return 0;
+ }
+
++/* Please keep this list alphabetically sorted */
++static const struct dmi_system_id nau8824_quirk_table[] = {
++ {
++ /* 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"),
++ },
++ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
++ },
++ {}
++};
++
++static void nau8824_check_quirks(void)
++{
++ const struct dmi_system_id *dmi_id;
++
++ if (quirk_override != -1) {
++ nau8824_quirk = quirk_override;
++ return;
++ }
++
++ dmi_id = dmi_first_match(nau8824_quirk_table);
++ if (dmi_id)
++ nau8824_quirk = (unsigned long)dmi_id->driver_data;
++}
++
+ static int nau8824_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+ {
+@@ -1869,6 +1904,11 @@ static int nau8824_i2c_probe(struct i2c_client *i2c,
+ nau8824->irq = i2c->irq;
+ sema_init(&nau8824->jd_sem, 1);
+
++ nau8824_check_quirks();
++
++ if (nau8824_quirk & NAU8824_JD_ACTIVE_HIGH)
++ nau8824->jkdet_polarity = 0;
++
+ nau8824_print_device_properties(nau8824);
+
+ ret = regmap_read(nau8824->regmap, NAU8824_REG_I2C_DEVICE_ID, &value);
+diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c
+index 943d7d933e81b..03f24edfe4f64 100644
+--- a/sound/soc/codecs/rk817_codec.c
++++ b/sound/soc/codecs/rk817_codec.c
+@@ -539,3 +539,4 @@ module_platform_driver(rk817_codec_driver);
+ MODULE_DESCRIPTION("ASoC RK817 codec driver");
+ MODULE_AUTHOR("binyuan <kevan.lan@rock-chips.com>");
+ MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:rk817-codec");
+diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
+index fc0c83b73f099..93820561b9f5d 100644
+--- a/sound/soc/codecs/rt5651.c
++++ b/sound/soc/codecs/rt5651.c
+@@ -2261,11 +2261,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
+
+ ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+- | IRQF_ONESHOT, "rt5651", rt5651);
+- if (ret == 0) {
+- /* Gets re-enabled by rt5651_set_jack() */
+- disable_irq(rt5651->irq);
+- } else {
++ | IRQF_ONESHOT | IRQF_NO_AUTOEN, "rt5651", rt5651);
++ if (ret) {
+ dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+ rt5651->irq, ret);
+ rt5651->irq = -ENXIO;
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 4a64cab99c55b..5ac2b1444694d 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -46,6 +46,8 @@ static const struct reg_sequence patch_list[] = {
+ {RT5682_SAR_IL_CMD_1, 0x22b7},
+ {RT5682_SAR_IL_CMD_3, 0x0365},
+ {RT5682_SAR_IL_CMD_6, 0x0110},
++ {RT5682_CHARGE_PUMP_1, 0x0210},
++ {RT5682_HP_LOGIC_CTRL_2, 0x0007},
+ };
+
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
+@@ -1515,21 +1517,29 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+- snd_soc_component_write(component,
+- RT5682_HP_LOGIC_CTRL_2, 0x0012);
+- snd_soc_component_write(component,
+- RT5682_HP_CTRL_2, 0x6000);
++ snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
++ RT5682_HP_C2_DAC_AMP_MUTE, 0);
++ snd_soc_component_update_bits(component, RT5682_HP_LOGIC_CTRL_2,
++ RT5682_HP_LC2_SIG_SOUR2_MASK, RT5682_HP_LC2_SIG_SOUR2_REG);
+ snd_soc_component_update_bits(component,
+ RT5682_DEPOP_1, 0x60, 0x60);
+ snd_soc_component_update_bits(component,
+ RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
++ snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
++ RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
++ RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
++ usleep_range(5000, 10000);
++ snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
++ RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
++ snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
++ RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN, 0);
++ snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
++ RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_M);
+ snd_soc_component_update_bits(component,
+ RT5682_DEPOP_1, 0x60, 0x0);
+- snd_soc_component_write(component,
+- RT5682_HP_CTRL_2, 0x0000);
+ snd_soc_component_update_bits(component,
+ RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000);
+ break;
+@@ -1637,6 +1647,23 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_adcdat_pin_enum,
+ static const struct snd_kcontrol_new rt5682_adcdat_pin_ctrl =
+ SOC_DAPM_ENUM("ADCDAT", rt5682_adcdat_pin_enum);
+
++static const unsigned int rt5682_hpo_sig_out_values[] = {
++ 2,
++ 7,
++};
++
++static const char * const rt5682_hpo_sig_out_mode[] = {
++ "Legacy",
++ "OneBit",
++};
++
++static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_hpo_sig_out_enum,
++ RT5682_HP_LOGIC_CTRL_2, 0, RT5682_HP_LC2_SIG_SOUR1_MASK,
++ rt5682_hpo_sig_out_mode, rt5682_hpo_sig_out_values);
++
++static const struct snd_kcontrol_new rt5682_hpo_sig_demux =
++ SOC_DAPM_ENUM("HPO Signal Demux", rt5682_hpo_sig_out_enum);
++
+ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("LDO2", RT5682_PWR_ANLG_3, RT5682_PWR_LDO2_BIT,
+ 0, NULL, 0),
+@@ -1820,6 +1847,10 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
+ SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+ &hpor_switch),
+
++ SND_SOC_DAPM_OUT_DRV("HPO Legacy", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_OUT_DRV("HPO OneBit", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_DEMUX("HPO Signal Demux", SND_SOC_NOPM, 0, 0, &rt5682_hpo_sig_demux),
++
+ /* CLK DET */
+ SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682_CLK_DET,
+ RT5682_SYS_CLK_DET_SFT, 0, NULL, 0),
+@@ -1987,10 +2018,19 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
+ {"HP Amp", NULL, "Charge Pump"},
+ {"HP Amp", NULL, "CLKDET SYS"},
+ {"HP Amp", NULL, "Vref1"},
+- {"HPOL Playback", "Switch", "HP Amp"},
+- {"HPOR Playback", "Switch", "HP Amp"},
++
++ {"HPO Signal Demux", NULL, "HP Amp"},
++
++ {"HPO Legacy", "Legacy", "HPO Signal Demux"},
++ {"HPO OneBit", "OneBit", "HPO Signal Demux"},
++
++ {"HPOL Playback", "Switch", "HPO Legacy"},
++ {"HPOR Playback", "Switch", "HPO Legacy"},
++
+ {"HPOL", NULL, "HPOL Playback"},
+ {"HPOR", NULL, "HPOR Playback"},
++ {"HPOL", NULL, "HPO OneBit"},
++ {"HPOR", NULL, "HPO OneBit"},
+ };
+
+ static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+@@ -2800,6 +2840,8 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component)
+
+ for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) {
+ struct clk_init_data init = { };
++ struct clk_parent_data parent_data;
++ const struct clk_hw *parent;
+
+ dai_clk_hw = &rt5682->dai_clks_hw[i];
+
+@@ -2807,17 +2849,17 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component)
+ case RT5682_DAI_WCLK_IDX:
+ /* Make MCLK the parent of WCLK */
+ if (rt5682->mclk) {
+- init.parent_data = &(struct clk_parent_data){
++ parent_data = (struct clk_parent_data){
+ .fw_name = "mclk",
+ };
++ init.parent_data = &parent_data;
+ init.num_parents = 1;
+ }
+ break;
+ case RT5682_DAI_BCLK_IDX:
+ /* Make WCLK the parent of BCLK */
+- init.parent_hws = &(const struct clk_hw *){
+- &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX]
+- };
++ parent = &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX];
++ init.parent_hws = &parent;
+ init.num_parents = 1;
+ break;
+ default:
+diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
+index b59221048ebf9..8e3244a62c160 100644
+--- a/sound/soc/codecs/rt5682.h
++++ b/sound/soc/codecs/rt5682.h
+@@ -375,6 +375,14 @@
+ #define RT5682_R_VOL_MASK (0x3f)
+ #define RT5682_R_VOL_SFT 0
+
++/* Headphone Amp Control 2 (0x0003) */
++#define RT5682_HP_C2_DAC_AMP_MUTE_SFT 15
++#define RT5682_HP_C2_DAC_AMP_MUTE (0x1 << 15)
++#define RT5682_HP_C2_DAC_L_EN_SFT 14
++#define RT5682_HP_C2_DAC_L_EN (0x1 << 14)
++#define RT5682_HP_C2_DAC_R_EN_SFT 13
++#define RT5682_HP_C2_DAC_R_EN (0x1 << 13)
++
+ /*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+ #define RT5682_G_HP (0xf << 8)
+ #define RT5682_G_HP_SFT 8
+@@ -1265,6 +1273,10 @@
+ #define RT5682_HPA_CP_BIAS_6UA (0x3 << 2)
+
+ /* Charge Pump Internal Register1 (0x0125) */
++#define RT5682_CP_SW_SIZE_MASK (0x7 << 8)
++#define RT5682_CP_SW_SIZE_L (0x4 << 8)
++#define RT5682_CP_SW_SIZE_M (0x2 << 8)
++#define RT5682_CP_SW_SIZE_S (0x1 << 8)
+ #define RT5682_CP_CLK_HP_MASK (0x3 << 4)
+ #define RT5682_CP_CLK_HP_100KHZ (0x0 << 4)
+ #define RT5682_CP_CLK_HP_200KHZ (0x1 << 4)
+@@ -1315,6 +1327,14 @@
+ #define RT5682_DEB_STO_DAC_MASK (0x7 << 4)
+ #define RT5682_DEB_80_MS (0x0 << 4)
+
++/* HP Behavior Logic Control 2 (0x01db) */
++#define RT5682_HP_LC2_SIG_SOUR2_MASK (0x1 << 4)
++#define RT5682_HP_LC2_SIG_SOUR2_REG (0x1 << 4)
++#define RT5682_HP_LC2_SIG_SOUR2_DC_CAL (0x0 << 4)
++#define RT5682_HP_LC2_SIG_SOUR1_MASK (0x7)
++#define RT5682_HP_LC2_SIG_SOUR1_1BIT (0x7)
++#define RT5682_HP_LC2_SIG_SOUR1_LEGA (0x2)
++
+ /* SAR ADC Inline Command Control 1 (0x0210) */
+ #define RT5682_SAR_BUTT_DET_MASK (0x1 << 15)
+ #define RT5682_SAR_BUTT_DET_EN (0x1 << 15)
+diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
+index d885ced34f606..bc5d68c53e5ab 100644
+--- a/sound/soc/codecs/wcd9335.c
++++ b/sound/soc/codecs/wcd9335.c
+@@ -4859,7 +4859,7 @@ static int wcd9335_codec_probe(struct snd_soc_component *component)
+
+ snd_soc_component_init_regmap(component, wcd->regmap);
+ /* Class-H Init*/
+- wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version);
++ wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, WCD9335);
+ if (IS_ERR(wcd->clsh_ctrl))
+ return PTR_ERR(wcd->clsh_ctrl);
+
+diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
+index c496b359f2f40..e63c6b723d76c 100644
+--- a/sound/soc/codecs/wcd934x.c
++++ b/sound/soc/codecs/wcd934x.c
+@@ -1896,9 +1896,8 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream,
+ }
+
+ wcd->dai[dai->id].sconfig.rate = params_rate(params);
+- wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
+
+- return 0;
++ return wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
+ }
+
+ static int wcd934x_hw_free(struct snd_pcm_substream *substream,
+@@ -3257,6 +3256,9 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
+ int value = ucontrol->value.integer.value[0];
+ int sel;
+
++ if (wcd->comp_enabled[comp] == value)
++ return 0;
++
+ wcd->comp_enabled[comp] = value;
+ sel = value ? WCD934X_HPH_GAIN_SRC_SEL_COMPANDER :
+ WCD934X_HPH_GAIN_SRC_SEL_REGISTER;
+@@ -3280,10 +3282,10 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
+ case COMPANDER_8:
+ break;
+ default:
+- break;
++ return 0;
+ }
+
+- return 0;
++ return 1;
+ }
+
+ static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
+@@ -3327,6 +3329,31 @@ static int slim_rx_mux_get(struct snd_kcontrol *kc,
+ return 0;
+ }
+
++static int slim_rx_mux_to_dai_id(int mux)
++{
++ int aif_id;
++
++ switch (mux) {
++ case 1:
++ aif_id = AIF1_PB;
++ break;
++ case 2:
++ aif_id = AIF2_PB;
++ break;
++ case 3:
++ aif_id = AIF3_PB;
++ break;
++ case 4:
++ aif_id = AIF4_PB;
++ break;
++ default:
++ aif_id = -1;
++ break;
++ }
++
++ return aif_id;
++}
++
+ static int slim_rx_mux_put(struct snd_kcontrol *kc,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -3334,43 +3361,59 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
+ struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
+ struct soc_enum *e = (struct soc_enum *)kc->private_value;
+ struct snd_soc_dapm_update *update = NULL;
++ struct wcd934x_slim_ch *ch, *c;
+ u32 port_id = w->shift;
++ bool found = false;
++ int mux_idx;
++ int prev_mux_idx = wcd->rx_port_value[port_id];
++ int aif_id;
+
+- if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
+- return 0;
++ mux_idx = ucontrol->value.enumerated.item[0];
+
+- wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
++ if (mux_idx == prev_mux_idx)
++ return 0;
+
+- switch (wcd->rx_port_value[port_id]) {
++ switch(mux_idx) {
+ case 0:
+- list_del_init(&wcd->rx_chs[port_id].list);
+- break;
+- case 1:
+- list_add_tail(&wcd->rx_chs[port_id].list,
+- &wcd->dai[AIF1_PB].slim_ch_list);
+- break;
+- case 2:
+- list_add_tail(&wcd->rx_chs[port_id].list,
+- &wcd->dai[AIF2_PB].slim_ch_list);
+- break;
+- case 3:
+- list_add_tail(&wcd->rx_chs[port_id].list,
+- &wcd->dai[AIF3_PB].slim_ch_list);
++ aif_id = slim_rx_mux_to_dai_id(prev_mux_idx);
++ if (aif_id < 0)
++ return 0;
++
++ list_for_each_entry_safe(ch, c, &wcd->dai[aif_id].slim_ch_list, list) {
++ if (ch->port == port_id + WCD934X_RX_START) {
++ found = true;
++ list_del_init(&ch->list);
++ break;
++ }
++ }
++ if (!found)
++ return 0;
++
+ break;
+- case 4:
+- list_add_tail(&wcd->rx_chs[port_id].list,
+- &wcd->dai[AIF4_PB].slim_ch_list);
++ case 1 ... 4:
++ aif_id = slim_rx_mux_to_dai_id(mux_idx);
++ if (aif_id < 0)
++ return 0;
++
++ if (list_empty(&wcd->rx_chs[port_id].list)) {
++ list_add_tail(&wcd->rx_chs[port_id].list,
++ &wcd->dai[aif_id].slim_ch_list);
++ } else {
++ dev_err(wcd->dev ,"SLIM_RX%d PORT is busy\n", port_id);
++ return 0;
++ }
+ break;
++
+ default:
+- dev_err(wcd->dev, "Unknown AIF %d\n",
+- wcd->rx_port_value[port_id]);
++ dev_err(wcd->dev, "Unknown AIF %d\n", mux_idx);
+ goto err;
+ }
+
++ wcd->rx_port_value[port_id] = mux_idx;
+ snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
+ e, update);
+
+- return 0;
++ return 1;
+ err:
+ return -EINVAL;
+ }
+@@ -3816,6 +3859,7 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
+ struct soc_mixer_control *mixer =
+ (struct soc_mixer_control *)kc->private_value;
+ int enable = ucontrol->value.integer.value[0];
++ struct wcd934x_slim_ch *ch, *c;
+ int dai_id = widget->shift;
+ int port_id = mixer->shift;
+
+@@ -3823,17 +3867,32 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
+ if (enable == wcd->tx_port_value[port_id])
+ return 0;
+
+- wcd->tx_port_value[port_id] = enable;
+-
+- if (enable)
+- list_add_tail(&wcd->tx_chs[port_id].list,
+- &wcd->dai[dai_id].slim_ch_list);
+- else
+- list_del_init(&wcd->tx_chs[port_id].list);
++ if (enable) {
++ if (list_empty(&wcd->tx_chs[port_id].list)) {
++ list_add_tail(&wcd->tx_chs[port_id].list,
++ &wcd->dai[dai_id].slim_ch_list);
++ } else {
++ dev_err(wcd->dev ,"SLIM_TX%d PORT is busy\n", port_id);
++ return 0;
++ }
++ } else {
++ bool found = false;
++
++ list_for_each_entry_safe(ch, c, &wcd->dai[dai_id].slim_ch_list, list) {
++ if (ch->port == port_id) {
++ found = true;
++ list_del_init(&wcd->tx_chs[port_id].list);
++ break;
++ }
++ }
++ if (!found)
++ return 0;
++ }
+
++ wcd->tx_port_value[port_id] = enable;
+ snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
+
+- return 0;
++ return 1;
+ }
+
+ static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = {
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index 52de7d14b1398..67151c7770c65 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -1174,6 +1174,9 @@ static bool wcd938x_readonly_register(struct device *dev, unsigned int reg)
+ case WCD938X_DIGITAL_INTR_STATUS_0:
+ case WCD938X_DIGITAL_INTR_STATUS_1:
+ case WCD938X_DIGITAL_INTR_STATUS_2:
++ case WCD938X_DIGITAL_INTR_CLEAR_0:
++ case WCD938X_DIGITAL_INTR_CLEAR_1:
++ case WCD938X_DIGITAL_INTR_CLEAR_2:
+ case WCD938X_DIGITAL_SWR_HM_TEST_0:
+ case WCD938X_DIGITAL_SWR_HM_TEST_1:
+ case WCD938X_DIGITAL_EFUSE_T_DATA_0:
+diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
+index 2da4a5fa7a18d..564b78f3cdd0a 100644
+--- a/sound/soc/codecs/wsa881x.c
++++ b/sound/soc/codecs/wsa881x.c
+@@ -772,7 +772,8 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
+
+ usleep_range(1000, 1010);
+ }
+- return 0;
++
++ return 1;
+ }
+
+ static int wsa881x_get_port(struct snd_kcontrol *kcontrol,
+@@ -816,15 +817,22 @@ static int wsa881x_set_port(struct snd_kcontrol *kcontrol,
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+- if (ucontrol->value.integer.value[0])
++ if (ucontrol->value.integer.value[0]) {
++ if (data->port_enable[portidx])
++ return 0;
++
+ data->port_enable[portidx] = true;
+- else
++ } else {
++ if (!data->port_enable[portidx])
++ return 0;
++
+ data->port_enable[portidx] = false;
++ }
+
+ if (portidx == WSA881X_PORT_BOOST) /* Boost Switch */
+ wsa881x_boost_ctrl(comp, data->port_enable[portidx]);
+
+- return 0;
++ return 1;
+ }
+
+ static const char * const smart_boost_lvl_text[] = {
+diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
+index 6b06248a9327a..f10496206ceed 100644
+--- a/sound/soc/intel/boards/sof_sdw.c
++++ b/sound/soc/intel/boards/sof_sdw.c
+@@ -213,6 +213,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
+ SOF_RT715_DAI_ID_FIX |
+ SOF_SDW_FOUR_SPK),
+ },
++ {
++ .callback = sof_sdw_quirk_cb,
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
++ },
++ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
++ RT711_JD2 |
++ SOF_RT715_DAI_ID_FIX),
++ },
+ /* AlderLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+index 785d5f5f8a9c9..11801b905ecc2 100644
+--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
++++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+@@ -156,6 +156,15 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+ }
+ };
+
++static const struct snd_soc_acpi_adr_device rt1316_1_single_adr[] = {
++ {
++ .adr = 0x000131025D131601ull,
++ .num_endpoints = 1,
++ .endpoints = &single_endpoint,
++ .name_prefix = "rt1316-1"
++ }
++};
++
+ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
+ {
+ .adr = 0x000131025D131601ull, /* unique ID is set for some reason */
+@@ -320,6 +329,25 @@ static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = {
+ {}
+ };
+
++static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca_mono[] = {
++ {
++ .mask = BIT(0),
++ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
++ .adr_d = rt711_sdca_0_adr,
++ },
++ {
++ .mask = BIT(1),
++ .num_adr = ARRAY_SIZE(rt1316_1_single_adr),
++ .adr_d = rt1316_1_single_adr,
++ },
++ {
++ .mask = BIT(3),
++ .num_adr = ARRAY_SIZE(rt714_3_adr),
++ .adr_d = rt714_3_adr,
++ },
++ {}
++};
++
+ static const struct snd_soc_acpi_codecs tgl_max98373_amp = {
+ .num_codecs = 1,
+ .codecs = {"MX98373"}
+@@ -412,6 +440,19 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-tgl-rt711-rt1316-rt714.tplg",
+ },
++ {
++ /*
++ * link_mask should be 0xB, but all links are enabled by BIOS.
++ * This entry will be selected if there is no rt1316 amplifier exposed
++ * on link2 since it will fail to match the above entry.
++ */
++
++ .link_mask = 0xF, /* 4 active links required */
++ .links = tgl_3_in_1_sdca_mono,
++ .drv_name = "sof_sdw",
++ .sof_tplg_filename = "sof-tgl-rt711-l0-rt1316-l1-mono-rt714-l3.tplg",
++ },
++
+ {
+ .link_mask = 0x3, /* rt711 on link 0 and 1 rt1308 on link 1 */
+ .links = tgl_hp,
+diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c
+index de09f67c04502..a3fa8efc8f81c 100644
+--- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c
++++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c
+@@ -1040,8 +1040,10 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev)
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
++ if (!priv) {
++ of_node_put(platform_node);
+ return -ENOMEM;
++ }
+
+ snd_soc_card_set_drvdata(card, priv);
+
+@@ -1049,6 +1051,8 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev)
+ if (ret)
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
++
++ of_node_put(platform_node);
+ return ret;
+ }
+
+diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
+index 46f365528d501..b74b67720ef43 100644
+--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
++++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
+@@ -269,9 +269,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
+
+ if (ret < 0) {
+ dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
+- q6asm_audio_client_free(prtd->audio_client);
+- prtd->audio_client = NULL;
+- return -ENOMEM;
++ goto open_err;
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+@@ -279,7 +277,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
+ prtd->session_id, substream->stream);
+ if (ret) {
+ dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
+- return ret;
++ goto routing_err;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+@@ -301,10 +299,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
+ }
+ if (ret < 0)
+ dev_info(dev, "%s: CMD Format block failed\n", __func__);
++ else
++ prtd->state = Q6ASM_STREAM_RUNNING;
+
+- prtd->state = Q6ASM_STREAM_RUNNING;
++ return ret;
+
+- return 0;
++routing_err:
++ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
++open_err:
++ q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
++ q6asm_audio_client_free(prtd->audio_client);
++ prtd->audio_client = NULL;
++
++ return ret;
+ }
+
+ static int q6asm_dai_trigger(struct snd_soc_component *component,
+diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
+index 3390ebef9549d..18c90bb4922be 100644
+--- a/sound/soc/qcom/qdsp6/q6routing.c
++++ b/sound/soc/qcom/qdsp6/q6routing.c
+@@ -492,9 +492,15 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
+ struct session_data *session = &data->sessions[session_id];
+
+ if (ucontrol->value.integer.value[0]) {
++ if (session->port_id == be_id)
++ return 0;
++
+ session->port_id = be_id;
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
+ } else {
++ if (session->port_id == -1 || session->port_id != be_id)
++ return 0;
++
+ session->port_id = -1;
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
+ }
+diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
+index 978bd0406729a..6a8fe0da7670b 100644
+--- a/sound/soc/sh/rcar/core.c
++++ b/sound/soc/sh/rcar/core.c
+@@ -1225,6 +1225,7 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
+ if (i < 0) {
+ dev_err(dev, "strange node numbering (%s)",
+ of_node_full_name(node));
++ of_node_put(np);
+ return 0;
+ }
+ i++;
+diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
+index 16c6e0265749b..03e0d4eca7815 100644
+--- a/sound/soc/sh/rcar/dma.c
++++ b/sound/soc/sh/rcar/dma.c
+@@ -102,7 +102,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
+ struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+ if (dmaen->chan)
+- dmaengine_terminate_sync(dmaen->chan);
++ dmaengine_terminate_async(dmaen->chan);
+
+ return 0;
+ }
+diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
+index 59d07648a7e7f..0479bb0005abd 100644
+--- a/sound/soc/soc-dapm.c
++++ b/sound/soc/soc-dapm.c
+@@ -2557,8 +2557,13 @@ static struct snd_soc_dapm_widget *dapm_find_widget(
+ return NULL;
+ }
+
+-static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+- const char *pin, int status)
++/*
++ * set the DAPM pin status:
++ * returns 1 when the value has been updated, 0 when unchanged, or a negative
++ * error code; called from kcontrol put callback
++ */
++static int __snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
++ const char *pin, int status)
+ {
+ struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+ int ret = 0;
+@@ -2584,6 +2589,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+ return ret;
+ }
+
++/*
++ * similar as __snd_soc_dapm_set_pin(), but returns 0 when successful;
++ * called from several API functions below
++ */
++static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
++ const char *pin, int status)
++{
++ int ret = __snd_soc_dapm_set_pin(dapm, pin, status);
++
++ return ret < 0 ? ret : 0;
++}
++
+ /**
+ * snd_soc_dapm_sync_unlocked - scan and power dapm paths
+ * @dapm: DAPM context
+@@ -3587,10 +3604,10 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
+ const char *pin = (const char *)kcontrol->private_value;
+ int ret;
+
+- if (ucontrol->value.integer.value[0])
+- ret = snd_soc_dapm_enable_pin(&card->dapm, pin);
+- else
+- ret = snd_soc_dapm_disable_pin(&card->dapm, pin);
++ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
++ ret = __snd_soc_dapm_set_pin(&card->dapm, pin,
++ !!ucontrol->value.integer.value[0]);
++ mutex_unlock(&card->dapm_mutex);
+
+ snd_soc_dapm_sync(&card->dapm);
+ return ret;
+diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
+index f6e5ac3e03140..7459956d62b99 100644
+--- a/sound/soc/soc-topology.c
++++ b/sound/soc/soc-topology.c
+@@ -2674,6 +2674,7 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
+ /* remove dynamic controls from the component driver */
+ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
+ {
++ struct snd_card *card = comp->card->snd_card;
+ struct snd_soc_dobj *dobj, *next_dobj;
+ int pass = SOC_TPLG_PASS_END;
+
+@@ -2681,6 +2682,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
+ while (pass >= SOC_TPLG_PASS_START) {
+
+ /* remove mixer controls */
++ down_write(&card->controls_rwsem);
+ list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
+ list) {
+
+@@ -2719,6 +2721,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
+ break;
+ }
+ }
++ up_write(&card->controls_rwsem);
+ pass--;
+ }
+
+diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
+index 30025d3c16b6e..0862ff8b66273 100644
+--- a/sound/soc/sof/intel/hda-bus.c
++++ b/sound/soc/sof/intel/hda-bus.c
+@@ -10,6 +10,8 @@
+ #include <linux/io.h>
+ #include <sound/hdaudio.h>
+ #include <sound/hda_i915.h>
++#include <sound/hda_codec.h>
++#include <sound/hda_register.h>
+ #include "../sof-priv.h"
+ #include "hda.h"
+
+@@ -21,6 +23,18 @@
+ #endif
+
+ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
++static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power)
++{
++ unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN);
++
++ if (link_power)
++ mask &= ~BIT(addr);
++ else
++ mask |= BIT(addr);
++
++ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
++}
++
+ static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable)
+ {
+ struct hdac_bus *bus = codec->bus;
+@@ -41,6 +55,9 @@ static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable)
+ */
+ if (codec->addr == HDA_IDISP_ADDR && !enable)
+ snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
++
++ /* WAKEEN needs to be set for disabled links */
++ update_codec_wake_enable(bus, codec->addr, enable);
+ }
+
+ static const struct hdac_bus_ops bus_core_ops = {
+diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
+index c1f9f0f584647..6704dbcd101cd 100644
+--- a/sound/soc/sof/intel/hda-dai.c
++++ b/sound/soc/sof/intel/hda-dai.c
+@@ -68,6 +68,7 @@ static struct hdac_ext_stream *
+ return NULL;
+ }
+
++ spin_lock_irq(&bus->reg_lock);
+ list_for_each_entry(stream, &bus->stream_list, list) {
+ struct hdac_ext_stream *hstream =
+ stream_to_hdac_ext_stream(stream);
+@@ -107,12 +108,12 @@ static struct hdac_ext_stream *
+ * is updated in snd_hdac_ext_stream_decouple().
+ */
+ if (!res->decoupled)
+- snd_hdac_ext_stream_decouple(bus, res, true);
+- spin_lock_irq(&bus->reg_lock);
++ snd_hdac_ext_stream_decouple_locked(bus, res, true);
++
+ res->link_locked = 1;
+ res->link_substream = substream;
+- spin_unlock_irq(&bus->reg_lock);
+ }
++ spin_unlock_irq(&bus->reg_lock);
+
+ return res;
+ }
+diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
+index 623cf291e2074..262a70791a8f8 100644
+--- a/sound/soc/sof/intel/hda-dsp.c
++++ b/sound/soc/sof/intel/hda-dsp.c
+@@ -623,8 +623,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
+ hda_dsp_ipc_int_disable(sdev);
+
+ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+- if (runtime_suspend)
+- hda_codec_jack_wake_enable(sdev, true);
++ hda_codec_jack_wake_enable(sdev, runtime_suspend);
+
+ /* power down all hda link */
+ snd_hdac_ext_bus_link_power_down_all(bus);
+diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
+index f60e2c57d3d0c..ef92cca7ae01e 100644
+--- a/sound/soc/sof/intel/hda.c
++++ b/sound/soc/sof/intel/hda.c
+@@ -696,6 +696,20 @@ skip_soundwire:
+ return 0;
+ }
+
++static void hda_check_for_state_change(struct snd_sof_dev *sdev)
++{
++#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
++ struct hdac_bus *bus = sof_to_bus(sdev);
++ unsigned int codec_mask;
++
++ codec_mask = snd_hdac_chip_readw(bus, STATESTS);
++ if (codec_mask) {
++ hda_codec_jack_check(sdev);
++ snd_hdac_chip_writew(bus, STATESTS, codec_mask);
++ }
++#endif
++}
++
+ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
+ {
+ struct snd_sof_dev *sdev = context;
+@@ -737,6 +751,8 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
+ if (hda_sdw_check_wakeen_irq(sdev))
+ hda_sdw_process_wakeen(sdev);
+
++ hda_check_for_state_change(sdev);
++
+ /* enable GIE interrupt */
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+ SOF_HDA_INTCTL,
+diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
+index cc9585bfa4e9f..1bb2dcf37ffe9 100644
+--- a/sound/soc/sof/topology.c
++++ b/sound/soc/sof/topology.c
+@@ -2598,6 +2598,15 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
+
+ /* power down the pipeline schedule core */
+ pipeline = swidget->private;
++
++ /*
++ * Runtime PM should still function normally if topology loading fails and
++ * it's components are unloaded. Do not power down the primary core so that the
++ * CTX_SAVE IPC can succeed during runtime suspend.
++ */
++ if (pipeline->core == SOF_DSP_PRIMARY_CORE)
++ break;
++
+ ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
+ if (ret < 0)
+ dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
+diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
+index 6254bacad6eb7..717f45a83445c 100644
+--- a/sound/soc/stm/stm32_i2s.c
++++ b/sound/soc/stm/stm32_i2s.c
+@@ -700,7 +700,7 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
+ if (ret < 0)
+ return ret;
+
+- nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1);
++ nb_bits = frame_len * (FIELD_GET(I2S_CGFR_CHLEN, cgfr) + 1);
+ ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
+ (nb_bits * rate));
+ if (ret)
+diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
+index 8ee9a77bd83d3..a74c980ee7753 100644
+--- a/sound/soc/tegra/tegra186_dspk.c
++++ b/sound/soc/tegra/tegra186_dspk.c
+@@ -26,51 +26,162 @@ static const struct reg_default tegra186_dspk_reg_defaults[] = {
+ { TEGRA186_DSPK_CODEC_CTRL, 0x03000000 },
+ };
+
+-static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
++static int tegra186_dspk_get_fifo_th(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+- if (strstr(kcontrol->id.name, "FIFO Threshold"))
+- ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
+- else if (strstr(kcontrol->id.name, "OSR Value"))
+- ucontrol->value.integer.value[0] = dspk->osr_val;
+- else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+- ucontrol->value.integer.value[0] = dspk->lrsel;
+- else if (strstr(kcontrol->id.name, "Channel Select"))
+- ucontrol->value.integer.value[0] = dspk->ch_sel;
+- else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+- ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
+- else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+- ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
++ ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
+
+ return 0;
+ }
+
+-static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
++static int tegra186_dspk_put_fifo_th(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+- int val = ucontrol->value.integer.value[0];
+-
+- if (strstr(kcontrol->id.name, "FIFO Threshold"))
+- dspk->rx_fifo_th = val;
+- else if (strstr(kcontrol->id.name, "OSR Value"))
+- dspk->osr_val = val;
+- else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+- dspk->lrsel = val;
+- else if (strstr(kcontrol->id.name, "Channel Select"))
+- dspk->ch_sel = val;
+- else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+- dspk->mono_to_stereo = val;
+- else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+- dspk->stereo_to_mono = val;
++ int value = ucontrol->value.integer.value[0];
++
++ if (value == dspk->rx_fifo_th)
++ return 0;
++
++ dspk->rx_fifo_th = value;
++
++ return 1;
++}
++
++static int tegra186_dspk_get_osr_val(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++
++ ucontrol->value.enumerated.item[0] = dspk->osr_val;
+
+ return 0;
+ }
+
++static int tegra186_dspk_put_osr_val(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dspk->osr_val)
++ return 0;
++
++ dspk->osr_val = value;
++
++ return 1;
++}
++
++static int tegra186_dspk_get_pol_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++
++ ucontrol->value.enumerated.item[0] = dspk->lrsel;
++
++ return 0;
++}
++
++static int tegra186_dspk_put_pol_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dspk->lrsel)
++ return 0;
++
++ dspk->lrsel = value;
++
++ return 1;
++}
++
++static int tegra186_dspk_get_ch_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++
++ ucontrol->value.enumerated.item[0] = dspk->ch_sel;
++
++ return 0;
++}
++
++static int tegra186_dspk_put_ch_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dspk->ch_sel)
++ return 0;
++
++ dspk->ch_sel = value;
++
++ return 1;
++}
++
++static int tegra186_dspk_get_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++
++ ucontrol->value.enumerated.item[0] = dspk->mono_to_stereo;
++
++ return 0;
++}
++
++static int tegra186_dspk_put_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dspk->mono_to_stereo)
++ return 0;
++
++ dspk->mono_to_stereo = value;
++
++ return 1;
++}
++
++static int tegra186_dspk_get_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++
++ ucontrol->value.enumerated.item[0] = dspk->stereo_to_mono;
++
++ return 0;
++}
++
++static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
++ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dspk->stereo_to_mono)
++ return 0;
++
++ dspk->stereo_to_mono = value;
++
++ return 1;
++}
++
+ static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
+ {
+ struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+@@ -279,17 +390,19 @@ static const struct soc_enum tegra186_dspk_lrsel_enum =
+ static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
+ SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
+ TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_fifo_th, tegra186_dspk_put_fifo_th),
+ SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_osr_val, tegra186_dspk_put_osr_val),
+ SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_pol_sel, tegra186_dspk_put_pol_sel),
+ SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_ch_sel, tegra186_dspk_put_ch_sel),
+ SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_mono_to_stereo,
++ tegra186_dspk_put_mono_to_stereo),
+ SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
+- tegra186_dspk_get_control, tegra186_dspk_put_control),
++ tegra186_dspk_get_stereo_to_mono,
++ tegra186_dspk_put_stereo_to_mono),
+ };
+
+ static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
+diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
+index bcccdf3ddc528..1a2e868a62209 100644
+--- a/sound/soc/tegra/tegra210_admaif.c
++++ b/sound/soc/tegra/tegra210_admaif.c
+@@ -424,46 +424,122 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+ .trigger = tegra_admaif_trigger,
+ };
+
+-static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++
++ ucontrol->value.enumerated.item[0] =
++ admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
++
++ return 0;
++}
++
++static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
++ return 0;
++
++ admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
++
++ return 1;
++}
++
++static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++
++ ucontrol->value.enumerated.item[0] =
++ admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
++
++ return 0;
++}
++
++static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
++ return 0;
++
++ admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
++
++ return 1;
++}
++
++static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+- long *uctl_val = &ucontrol->value.integer.value[0];
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+
+- if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+- *uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
+- else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+- *uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
+- else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+- *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+- else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+- *uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
++ ucontrol->value.enumerated.item[0] =
++ admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+
+ return 0;
+ }
+
+-static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
++ return 0;
++
++ admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
++
++ return 1;
++}
++
++static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+- int value = ucontrol->value.integer.value[0];
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+
+- if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+- admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
+- else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+- admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
+- else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+- admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+- else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+- admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
++ ucontrol->value.enumerated.item[0] =
++ admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
+
+ return 0;
+ }
+
++static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
++ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
++ return 0;
++
++ admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
++
++ return 1;
++}
++
+ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
+ {
+ struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+@@ -559,17 +635,21 @@ static const char * const tegra_admaif_mono_conv_text[] = {
+ }
+
+ #define TEGRA_ADMAIF_CIF_CTRL(reg) \
+- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
+- tegra_admaif_get_control, tegra_admaif_put_control, \
++ NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1, \
++ tegra210_admaif_pget_mono_to_stereo, \
++ tegra210_admaif_pput_mono_to_stereo, \
+ tegra_admaif_mono_conv_text), \
+- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
+- tegra_admaif_get_control, tegra_admaif_put_control, \
++ NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1, \
++ tegra210_admaif_pget_stereo_to_mono, \
++ tegra210_admaif_pput_stereo_to_mono, \
+ tegra_admaif_stereo_conv_text), \
+- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
+- tegra_admaif_get_control, tegra_admaif_put_control, \
++ NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
++ tegra210_admaif_cget_mono_to_stereo, \
++ tegra210_admaif_cput_mono_to_stereo, \
+ tegra_admaif_mono_conv_text), \
+- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
+- tegra_admaif_get_control, tegra_admaif_put_control, \
++ NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
++ tegra210_admaif_cget_stereo_to_mono, \
++ tegra210_admaif_cput_stereo_to_mono, \
+ tegra_admaif_stereo_conv_text)
+
+ static struct snd_kcontrol_new tegra210_admaif_controls[] = {
+diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
+index 66287a7c9865d..1b2f7cb8c6adc 100644
+--- a/sound/soc/tegra/tegra210_ahub.c
++++ b/sound/soc/tegra/tegra210_ahub.c
+@@ -62,6 +62,7 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+ unsigned int *item = uctl->value.enumerated.item;
+ unsigned int value = e->values[item[0]];
+ unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
++ int change = 0;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+@@ -86,12 +87,14 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+
+ /* Update widget power if state has changed */
+ if (snd_soc_component_test_bits(cmpnt, update[i].reg,
+- update[i].mask, update[i].val))
+- snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
+- &update[i]);
++ update[i].mask,
++ update[i].val))
++ change |= snd_soc_dapm_mux_update_power(dapm, kctl,
++ item[0], e,
++ &update[i]);
+ }
+
+- return 0;
++ return change;
+ }
+
+ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
+diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
+index b096478cd2ef0..db95794530f46 100644
+--- a/sound/soc/tegra/tegra210_dmic.c
++++ b/sound/soc/tegra/tegra210_dmic.c
+@@ -156,51 +156,162 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
+ return 0;
+ }
+
+-static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
++static int tegra210_dmic_get_boost_gain(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++
++ ucontrol->value.integer.value[0] = dmic->boost_gain;
++
++ return 0;
++}
++
++static int tegra210_dmic_put_boost_gain(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++ int value = ucontrol->value.integer.value[0];
++
++ if (value == dmic->boost_gain)
++ return 0;
++
++ dmic->boost_gain = value;
++
++ return 1;
++}
++
++static int tegra210_dmic_get_ch_select(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++
++ ucontrol->value.enumerated.item[0] = dmic->ch_select;
++
++ return 0;
++}
++
++static int tegra210_dmic_put_ch_select(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dmic->ch_select)
++ return 0;
++
++ dmic->ch_select = value;
++
++ return 1;
++}
++
++static int tegra210_dmic_get_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++
++ ucontrol->value.enumerated.item[0] = dmic->mono_to_stereo;
++
++ return 0;
++}
++
++static int tegra210_dmic_put_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dmic->mono_to_stereo)
++ return 0;
++
++ dmic->mono_to_stereo = value;
++
++ return 1;
++}
++
++static int tegra210_dmic_get_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++
++ ucontrol->value.enumerated.item[0] = dmic->stereo_to_mono;
++
++ return 0;
++}
++
++static int tegra210_dmic_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dmic->stereo_to_mono)
++ return 0;
++
++ dmic->stereo_to_mono = value;
++
++ return 1;
++}
++
++static int tegra210_dmic_get_osr_val(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+- if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+- ucontrol->value.integer.value[0] = dmic->boost_gain;
+- else if (strstr(kcontrol->id.name, "Channel Select"))
+- ucontrol->value.integer.value[0] = dmic->ch_select;
+- else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+- ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
+- else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+- ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
+- else if (strstr(kcontrol->id.name, "OSR Value"))
+- ucontrol->value.integer.value[0] = dmic->osr_val;
+- else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+- ucontrol->value.integer.value[0] = dmic->lrsel;
++ ucontrol->value.enumerated.item[0] = dmic->osr_val;
+
+ return 0;
+ }
+
+-static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
++static int tegra210_dmic_put_osr_val(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+- int value = ucontrol->value.integer.value[0];
++ unsigned int value = ucontrol->value.enumerated.item[0];
+
+- if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+- dmic->boost_gain = value;
+- else if (strstr(kcontrol->id.name, "Channel Select"))
+- dmic->ch_select = ucontrol->value.integer.value[0];
+- else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+- dmic->mono_to_stereo = value;
+- else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+- dmic->stereo_to_mono = value;
+- else if (strstr(kcontrol->id.name, "OSR Value"))
+- dmic->osr_val = value;
+- else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+- dmic->lrsel = value;
++ if (value == dmic->osr_val)
++ return 0;
++
++ dmic->osr_val = value;
++
++ return 1;
++}
++
++static int tegra210_dmic_get_pol_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++
++ ucontrol->value.enumerated.item[0] = dmic->lrsel;
+
+ return 0;
+ }
+
++static int tegra210_dmic_put_pol_sel(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == dmic->lrsel)
++ return 0;
++
++ dmic->lrsel = value;
++
++ return 1;
++}
++
+ static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
+ .hw_params = tegra210_dmic_hw_params,
+ };
+@@ -287,19 +398,22 @@ static const struct soc_enum tegra210_dmic_lrsel_enum =
+
+ static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
+ SOC_SINGLE_EXT("Boost Gain Volume", 0, 0, MAX_BOOST_GAIN, 0,
+- tegra210_dmic_get_control, tegra210_dmic_put_control),
++ tegra210_dmic_get_boost_gain,
++ tegra210_dmic_put_boost_gain),
+ SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
+- tegra210_dmic_get_control, tegra210_dmic_put_control),
++ tegra210_dmic_get_ch_select, tegra210_dmic_put_ch_select),
+ SOC_ENUM_EXT("Mono To Stereo",
+- tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
+- tegra210_dmic_put_control),
++ tegra210_dmic_mono_conv_enum,
++ tegra210_dmic_get_mono_to_stereo,
++ tegra210_dmic_put_mono_to_stereo),
+ SOC_ENUM_EXT("Stereo To Mono",
+- tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
+- tegra210_dmic_put_control),
++ tegra210_dmic_stereo_conv_enum,
++ tegra210_dmic_get_stereo_to_mono,
++ tegra210_dmic_put_stereo_to_mono),
+ SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
+- tegra210_dmic_get_control, tegra210_dmic_put_control),
++ tegra210_dmic_get_osr_val, tegra210_dmic_put_osr_val),
+ SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
+- tegra210_dmic_get_control, tegra210_dmic_put_control),
++ tegra210_dmic_get_pol_sel, tegra210_dmic_put_pol_sel),
+ };
+
+ static const struct snd_soc_component_driver tegra210_dmic_compnt = {
+diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
+index 45f31ccb49d89..9552bbb939dd1 100644
+--- a/sound/soc/tegra/tegra210_i2s.c
++++ b/sound/soc/tegra/tegra210_i2s.c
+@@ -302,85 +302,235 @@ static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+ return 0;
+ }
+
+-static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+- unsigned int ratio)
++static int tegra210_i2s_get_loopback(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
+ {
+- struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+- i2s->bclk_ratio = ratio;
++ ucontrol->value.integer.value[0] = i2s->loopback;
+
+ return 0;
+ }
+
+-static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++static int tegra210_i2s_put_loopback(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ int value = ucontrol->value.integer.value[0];
++
++ if (value == i2s->loopback)
++ return 0;
++
++ i2s->loopback = value;
++
++ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, I2S_CTRL_LPBK_MASK,
++ i2s->loopback << I2S_CTRL_LPBK_SHIFT);
++
++ return 1;
++}
++
++static int tegra210_i2s_get_fsync_width(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+- long *uctl_val = &ucontrol->value.integer.value[0];
+-
+- if (strstr(kcontrol->id.name, "Loopback"))
+- *uctl_val = i2s->loopback;
+- else if (strstr(kcontrol->id.name, "FSYNC Width"))
+- *uctl_val = i2s->fsync_width;
+- else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+- *uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
+- else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+- *uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
+- else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+- *uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
+- else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+- *uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
+- else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
+- *uctl_val = i2s->rx_fifo_th;
+- else if (strstr(kcontrol->id.name, "BCLK Ratio"))
+- *uctl_val = i2s->bclk_ratio;
++
++ ucontrol->value.integer.value[0] = i2s->fsync_width;
+
+ return 0;
+ }
+
+-static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *ucontrol)
++static int tegra210_i2s_put_fsync_width(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ int value = ucontrol->value.integer.value[0];
+
+- if (strstr(kcontrol->id.name, "Loopback")) {
+- i2s->loopback = value;
++ if (value == i2s->fsync_width)
++ return 0;
+
+- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+- I2S_CTRL_LPBK_MASK,
+- i2s->loopback << I2S_CTRL_LPBK_SHIFT);
++ i2s->fsync_width = value;
+
+- } else if (strstr(kcontrol->id.name, "FSYNC Width")) {
+- /*
+- * Frame sync width is used only for FSYNC modes and not
+- * applicable for LRCK modes. Reset value for this field is "0",
+- * which means the width is one bit clock wide.
+- * The width requirement may depend on the codec and in such
+- * cases mixer control is used to update custom values. A value
+- * of "N" here means, width is "N + 1" bit clock wide.
+- */
+- i2s->fsync_width = value;
+-
+- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+- I2S_CTRL_FSYNC_WIDTH_MASK,
+- i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+-
+- } else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
+- i2s->stereo_to_mono[I2S_TX_PATH] = value;
+- } else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
+- i2s->mono_to_stereo[I2S_TX_PATH] = value;
+- } else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
+- i2s->stereo_to_mono[I2S_RX_PATH] = value;
+- } else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
+- i2s->mono_to_stereo[I2S_RX_PATH] = value;
+- } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
+- i2s->rx_fifo_th = value;
+- } else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
+- i2s->bclk_ratio = value;
+- }
++ /*
++ * Frame sync width is used only for FSYNC modes and not
++ * applicable for LRCK modes. Reset value for this field is "0",
++ * which means the width is one bit clock wide.
++ * The width requirement may depend on the codec and in such
++ * cases mixer control is used to update custom values. A value
++ * of "N" here means, width is "N + 1" bit clock wide.
++ */
++ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
++ I2S_CTRL_FSYNC_WIDTH_MASK,
++ i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
++
++ return 1;
++}
++
++static int tegra210_i2s_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_TX_PATH];
++
++ return 0;
++}
++
++static int tegra210_i2s_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == i2s->stereo_to_mono[I2S_TX_PATH])
++ return 0;
++
++ i2s->stereo_to_mono[I2S_TX_PATH] = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_TX_PATH];
++
++ return 0;
++}
++
++static int tegra210_i2s_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == i2s->mono_to_stereo[I2S_TX_PATH])
++ return 0;
++
++ i2s->mono_to_stereo[I2S_TX_PATH] = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_RX_PATH];
++
++ return 0;
++}
++
++static int tegra210_i2s_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == i2s->stereo_to_mono[I2S_RX_PATH])
++ return 0;
++
++ i2s->stereo_to_mono[I2S_RX_PATH] = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_RX_PATH];
++
++ return 0;
++}
++
++static int tegra210_i2s_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ unsigned int value = ucontrol->value.enumerated.item[0];
++
++ if (value == i2s->mono_to_stereo[I2S_RX_PATH])
++ return 0;
++
++ i2s->mono_to_stereo[I2S_RX_PATH] = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_pget_fifo_th(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.integer.value[0] = i2s->rx_fifo_th;
++
++ return 0;
++}
++
++static int tegra210_i2s_pput_fifo_th(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ int value = ucontrol->value.integer.value[0];
++
++ if (value == i2s->rx_fifo_th)
++ return 0;
++
++ i2s->rx_fifo_th = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++
++ ucontrol->value.integer.value[0] = i2s->bclk_ratio;
++
++ return 0;
++}
++
++static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
++ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
++ int value = ucontrol->value.integer.value[0];
++
++ if (value == i2s->bclk_ratio)
++ return 0;
++
++ i2s->bclk_ratio = value;
++
++ return 1;
++}
++
++static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
++ unsigned int ratio)
++{
++ struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++ i2s->bclk_ratio = ratio;
+
+ return 0;
+ }
+@@ -598,22 +748,28 @@ static const struct soc_enum tegra210_i2s_stereo_conv_enum =
+ tegra210_i2s_stereo_conv_text);
+
+ static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
+- SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
+- tegra210_i2s_put_control),
+- SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
+- tegra210_i2s_put_control),
++ SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_loopback,
++ tegra210_i2s_put_loopback),
++ SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0,
++ tegra210_i2s_get_fsync_width,
++ tegra210_i2s_put_fsync_width),
+ SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+- tegra210_i2s_get_control, tegra210_i2s_put_control),
++ tegra210_i2s_cget_stereo_to_mono,
++ tegra210_i2s_cput_stereo_to_mono),
+ SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
+- tegra210_i2s_get_control, tegra210_i2s_put_control),
++ tegra210_i2s_cget_mono_to_stereo,
++ tegra210_i2s_cput_mono_to_stereo),
+ SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+- tegra210_i2s_get_control, tegra210_i2s_put_control),
++ tegra210_i2s_pget_mono_to_stereo,
++ tegra210_i2s_pput_mono_to_stereo),
+ SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
+- tegra210_i2s_get_control, tegra210_i2s_put_control),
++ tegra210_i2s_pget_stereo_to_mono,
++ tegra210_i2s_pput_stereo_to_mono),
+ SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
+- 0, tegra210_i2s_get_control, tegra210_i2s_put_control),
+- SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
+- tegra210_i2s_put_control),
++ 0, tegra210_i2s_pget_fifo_th, tegra210_i2s_pput_fifo_th),
++ SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0,
++ tegra210_i2s_get_bclk_ratio,
++ tegra210_i2s_put_bclk_ratio),
+ };
+
+ static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
+diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c
+index 735909310a262..78fb423df550b 100644
+--- a/sound/soc/tegra/tegra_asoc_machine.c
++++ b/sound/soc/tegra/tegra_asoc_machine.c
+@@ -341,9 +341,34 @@ tegra_machine_parse_phandle(struct device *dev, const char *name)
+ return np;
+ }
+
++static void tegra_machine_unregister_codec(void *pdev)
++{
++ platform_device_unregister(pdev);
++}
++
++static int tegra_machine_register_codec(struct device *dev, const char *name)
++{
++ struct platform_device *pdev;
++ int err;
++
++ if (!name)
++ return 0;
++
++ pdev = platform_device_register_simple(name, -1, NULL, 0);
++ if (IS_ERR(pdev))
++ return PTR_ERR(pdev);
++
++ err = devm_add_action_or_reset(dev, tegra_machine_unregister_codec,
++ pdev);
++ if (err)
++ return err;
++
++ return 0;
++}
++
+ int tegra_asoc_machine_probe(struct platform_device *pdev)
+ {
+- struct device_node *np_codec, *np_i2s;
++ struct device_node *np_codec, *np_i2s, *np_ac97;
+ const struct tegra_asoc_data *asoc;
+ struct device *dev = &pdev->dev;
+ struct tegra_machine *machine;
+@@ -404,17 +429,30 @@ int tegra_asoc_machine_probe(struct platform_device *pdev)
+ return err;
+ }
+
+- np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec");
+- if (IS_ERR(np_codec))
+- return PTR_ERR(np_codec);
++ if (asoc->set_ac97) {
++ err = tegra_machine_register_codec(dev, asoc->codec_dev_name);
++ if (err)
++ return err;
++
++ np_ac97 = tegra_machine_parse_phandle(dev, "nvidia,ac97-controller");
++ if (IS_ERR(np_ac97))
++ return PTR_ERR(np_ac97);
+
+- np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller");
+- if (IS_ERR(np_i2s))
+- return PTR_ERR(np_i2s);
++ card->dai_link->cpus->of_node = np_ac97;
++ card->dai_link->platforms->of_node = np_ac97;
++ } else {
++ np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec");
++ if (IS_ERR(np_codec))
++ return PTR_ERR(np_codec);
+
+- card->dai_link->cpus->of_node = np_i2s;
+- card->dai_link->codecs->of_node = np_codec;
+- card->dai_link->platforms->of_node = np_i2s;
++ np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller");
++ if (IS_ERR(np_i2s))
++ return PTR_ERR(np_i2s);
++
++ card->dai_link->cpus->of_node = np_i2s;
++ card->dai_link->codecs->of_node = np_codec;
++ card->dai_link->platforms->of_node = np_i2s;
++ }
+
+ if (asoc->add_common_controls) {
+ card->controls = tegra_machine_controls;
+@@ -589,6 +627,7 @@ static struct snd_soc_card snd_soc_tegra_wm9712 = {
+ static const struct tegra_asoc_data tegra_wm9712_data = {
+ .card = &snd_soc_tegra_wm9712,
+ .add_common_dapm_widgets = true,
++ .codec_dev_name = "wm9712-codec",
+ .set_ac97 = true,
+ };
+
+@@ -686,6 +725,7 @@ static struct snd_soc_dai_link tegra_tlv320aic23_dai = {
+ };
+
+ static struct snd_soc_card snd_soc_tegra_trimslice = {
++ .name = "tegra-trimslice",
+ .components = "codec:tlv320aic23",
+ .dai_link = &tegra_tlv320aic23_dai,
+ .num_links = 1,
+diff --git a/sound/soc/tegra/tegra_asoc_machine.h b/sound/soc/tegra/tegra_asoc_machine.h
+index 8ee0ec814f67c..d6a8d13205516 100644
+--- a/sound/soc/tegra/tegra_asoc_machine.h
++++ b/sound/soc/tegra/tegra_asoc_machine.h
+@@ -13,6 +13,7 @@ struct snd_soc_pcm_runtime;
+
+ struct tegra_asoc_data {
+ unsigned int (*mclk_rate)(unsigned int srate);
++ const char *codec_dev_name;
+ struct snd_soc_card *card;
+ unsigned int mclk_id;
+ bool hp_jack_gpio_active_low;
+diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
+index 49d1976a132c0..5ed8e36d2e043 100644
+--- a/sound/synth/emux/emux.c
++++ b/sound/synth/emux/emux.c
+@@ -88,7 +88,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
+ emu->name = kstrdup(name, GFP_KERNEL);
+ emu->voices = kcalloc(emu->max_voices, sizeof(struct snd_emux_voice),
+ GFP_KERNEL);
+- if (emu->voices == NULL)
++ if (emu->name == NULL || emu->voices == NULL)
+ return -ENOMEM;
+
+ /* create soundfont list */
+diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
+index 43a2a62d66f7e..49629d4bb327a 100644
+--- a/sound/usb/6fire/comm.c
++++ b/sound/usb/6fire/comm.c
+@@ -95,7 +95,7 @@ static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
+ int actual_len;
+
+ ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
+- buffer, buffer[1] + 2, &actual_len, HZ);
++ buffer, buffer[1] + 2, &actual_len, 1000);
+ if (ret < 0)
+ return ret;
+ else if (actual_len != buffer[1] + 2)
+diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
+index 8981e61f2da4a..c51abc54d2f84 100644
+--- a/sound/usb/6fire/firmware.c
++++ b/sound/usb/6fire/firmware.c
+@@ -160,7 +160,7 @@ static int usb6fire_fw_ezusb_write(struct usb_device *device,
+ {
+ return usb_control_msg_send(device, 0, type,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+- value, 0, data, len, HZ, GFP_KERNEL);
++ value, 0, data, len, 1000, GFP_KERNEL);
+ }
+
+ static int usb6fire_fw_ezusb_read(struct usb_device *device,
+@@ -168,7 +168,7 @@ static int usb6fire_fw_ezusb_read(struct usb_device *device,
+ {
+ return usb_control_msg_recv(device, 0, type,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+- value, 0, data, len, HZ, GFP_KERNEL);
++ value, 0, data, len, 1000, GFP_KERNEL);
+ }
+
+ static int usb6fire_fw_fpga_write(struct usb_device *device,
+@@ -178,7 +178,7 @@ static int usb6fire_fw_fpga_write(struct usb_device *device,
+ int ret;
+
+ ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
+- &actual_len, HZ);
++ &actual_len, 1000);
+ if (ret < 0)
+ return ret;
+ else if (actual_len != len)
+diff --git a/sound/usb/card.h b/sound/usb/card.h
+index 5b19901f305a3..87f042d06ce08 100644
+--- a/sound/usb/card.h
++++ b/sound/usb/card.h
+@@ -74,8 +74,9 @@ struct snd_usb_endpoint {
+
+ atomic_t state; /* running state */
+
+- void (*prepare_data_urb) (struct snd_usb_substream *subs,
+- struct urb *urb);
++ int (*prepare_data_urb) (struct snd_usb_substream *subs,
++ struct urb *urb,
++ bool in_stream_lock);
+ void (*retire_data_urb) (struct snd_usb_substream *subs,
+ struct urb *urb);
+
+@@ -94,9 +95,9 @@ struct snd_usb_endpoint {
+ struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */
+
+ unsigned int nurbs; /* # urbs */
+- unsigned int nominal_queue_size; /* total buffer sizes in URBs */
+ unsigned long active_mask; /* bitmask of active urbs */
+ unsigned long unlink_mask; /* bitmask of unlinked urbs */
++ atomic_t submitted_urbs; /* currently submitted urbs */
+ char *syncbuf; /* sync buffer for all sync URBs */
+ dma_addr_t sync_dma; /* DMA address of syncbuf */
+
+@@ -125,6 +126,7 @@ struct snd_usb_endpoint {
+ int skip_packets; /* quirks for devices to ignore the first n packets
+ in a stream */
+ bool implicit_fb_sync; /* syncs with implicit feedback */
++ bool lowlatency_playback; /* low-latency playback mode */
+ bool need_setup; /* (re-)need for configure? */
+
+ /* for hw constraints */
+@@ -136,6 +138,7 @@ struct snd_usb_endpoint {
+ unsigned int cur_period_frames;
+ unsigned int cur_period_bytes;
+ unsigned int cur_buffer_periods;
++ unsigned char cur_clock;
+
+ spinlock_t lock;
+ struct list_head list;
+@@ -188,7 +191,7 @@ struct snd_usb_substream {
+ } dsd_dop;
+
+ bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
+- bool early_playback_start; /* early start needed for playback? */
++ bool lowlatency_playback; /* low-latency playback mode */
+ struct media_ctl *media_ctl;
+ };
+
+diff --git a/sound/usb/clock.c b/sound/usb/clock.c
+index 81d5ce07d548b..98345a695dccb 100644
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -496,6 +496,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+ union uac23_clock_source_desc *cs_desc;
+
+ cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
++
++ if (!cs_desc)
++ return 0;
++
+ if (fmt->protocol == UAC_VERSION_3)
+ bmControls = le32_to_cpu(cs_desc->v3.bmControls);
+ else
+diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
+index 533919a28856f..743b8287cfcdd 100644
+--- a/sound/usb/endpoint.c
++++ b/sound/usb/endpoint.c
+@@ -148,18 +148,23 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)
+ * This won't be used for implicit feedback which takes the packet size
+ * returned from the sync source
+ */
+-static int slave_next_packet_size(struct snd_usb_endpoint *ep)
++static int slave_next_packet_size(struct snd_usb_endpoint *ep,
++ unsigned int avail)
+ {
+ unsigned long flags;
++ unsigned int phase;
+ int ret;
+
+ if (ep->fill_max)
+ return ep->maxframesize;
+
+ spin_lock_irqsave(&ep->lock, flags);
+- ep->phase = (ep->phase & 0xffff)
+- + (ep->freqm << ep->datainterval);
+- ret = min(ep->phase >> 16, ep->maxframesize);
++ phase = (ep->phase & 0xffff) + (ep->freqm << ep->datainterval);
++ ret = min(phase >> 16, ep->maxframesize);
++ if (avail && ret >= avail)
++ ret = -EAGAIN;
++ else
++ ep->phase = phase;
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ return ret;
+@@ -169,20 +174,25 @@ static int slave_next_packet_size(struct snd_usb_endpoint *ep)
+ * Return the number of samples to be sent in the next packet
+ * for adaptive and synchronous endpoints
+ */
+-static int next_packet_size(struct snd_usb_endpoint *ep)
++static int next_packet_size(struct snd_usb_endpoint *ep, unsigned int avail)
+ {
++ unsigned int sample_accum;
+ int ret;
+
+ if (ep->fill_max)
+ return ep->maxframesize;
+
+- ep->sample_accum += ep->sample_rem;
+- if (ep->sample_accum >= ep->pps) {
+- ep->sample_accum -= ep->pps;
++ sample_accum = ep->sample_accum + ep->sample_rem;
++ if (sample_accum >= ep->pps) {
++ sample_accum -= ep->pps;
+ ret = ep->packsize[1];
+ } else {
+ ret = ep->packsize[0];
+ }
++ if (avail && ret >= avail)
++ ret = -EAGAIN;
++ else
++ ep->sample_accum = sample_accum;
+
+ return ret;
+ }
+@@ -190,16 +200,27 @@ static int next_packet_size(struct snd_usb_endpoint *ep)
+ /*
+ * snd_usb_endpoint_next_packet_size: Return the number of samples to be sent
+ * in the next packet
++ *
++ * If the size is equal or exceeds @avail, don't proceed but return -EAGAIN
++ * Exception: @avail = 0 for skipping the check.
+ */
+ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
+- struct snd_urb_ctx *ctx, int idx)
++ struct snd_urb_ctx *ctx, int idx,
++ unsigned int avail)
+ {
+- if (ctx->packet_size[idx])
+- return ctx->packet_size[idx];
+- else if (ep->sync_source)
+- return slave_next_packet_size(ep);
++ unsigned int packet;
++
++ packet = ctx->packet_size[idx];
++ if (packet) {
++ if (avail && packet >= avail)
++ return -EAGAIN;
++ return packet;
++ }
++
++ if (ep->sync_source)
++ return slave_next_packet_size(ep, avail);
+ else
+- return next_packet_size(ep);
++ return next_packet_size(ep, avail);
+ }
+
+ static void call_retire_callback(struct snd_usb_endpoint *ep,
+@@ -263,7 +284,7 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
+ unsigned int length;
+ int counts;
+
+- counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
++ counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
+ length = counts * ep->stride; /* number of silent bytes */
+ offset = offs * ep->stride + extra * i;
+ urb->iso_frame_desc[i].offset = offset;
+@@ -286,8 +307,9 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
+ /*
+ * Prepare a PLAYBACK urb for submission to the bus.
+ */
+-static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+- struct snd_urb_ctx *ctx)
++static int prepare_outbound_urb(struct snd_usb_endpoint *ep,
++ struct snd_urb_ctx *ctx,
++ bool in_stream_lock)
+ {
+ struct urb *urb = ctx->urb;
+ unsigned char *cp = urb->transfer_buffer;
+@@ -299,9 +321,9 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ data_subs = READ_ONCE(ep->data_subs);
+ if (data_subs && ep->prepare_data_urb)
+- ep->prepare_data_urb(data_subs, urb);
+- else /* no data provider, so send silence */
+- prepare_silent_urb(ep, ctx);
++ return ep->prepare_data_urb(data_subs, urb, in_stream_lock);
++ /* no data provider, so send silence */
++ prepare_silent_urb(ep, ctx);
+ break;
+
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+@@ -330,13 +352,14 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+
+ break;
+ }
++ return 0;
+ }
+
+ /*
+ * Prepare a CAPTURE or SYNC urb for submission to the bus.
+ */
+-static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+- struct snd_urb_ctx *urb_ctx)
++static int prepare_inbound_urb(struct snd_usb_endpoint *ep,
++ struct snd_urb_ctx *urb_ctx)
+ {
+ int i, offs;
+ struct urb *urb = urb_ctx->urb;
+@@ -361,6 +384,7 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+ urb->iso_frame_desc[0].offset = 0;
+ break;
+ }
++ return 0;
+ }
+
+ /* notify an error as XRUN to the assigned PCM data substream */
+@@ -396,6 +420,16 @@ next_packet_fifo_dequeue(struct snd_usb_endpoint *ep)
+ return p;
+ }
+
++static void push_back_to_ready_list(struct snd_usb_endpoint *ep,
++ struct snd_urb_ctx *ctx)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ep->lock, flags);
++ list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
++ spin_unlock_irqrestore(&ep->lock, flags);
++}
++
+ /*
+ * Send output urbs that have been prepared previously. URBs are dequeued
+ * from ep->ready_playback_urbs and in case there aren't any available
+@@ -406,12 +440,14 @@ next_packet_fifo_dequeue(struct snd_usb_endpoint *ep)
+ * is that host controllers don't guarantee the order in which they return
+ * inbound and outbound packets to their submitters.
+ *
+- * This function is only used for implicit feedback endpoints. For endpoints
+- * driven by dedicated sync endpoints, URBs are immediately re-submitted
+- * from their completion handler.
++ * This function is used both for implicit feedback endpoints and in low-
++ * latency playback mode.
+ */
+-static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
++void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
++ bool in_stream_lock)
+ {
++ bool implicit_fb = snd_usb_endpoint_implicit_feedback_sink(ep);
++
+ while (ep_state_running(ep)) {
+
+ unsigned long flags;
+@@ -420,14 +456,14 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+ int err, i;
+
+ spin_lock_irqsave(&ep->lock, flags);
+- if (ep->next_packet_queued > 0 &&
++ if ((!implicit_fb || ep->next_packet_queued > 0) &&
+ !list_empty(&ep->ready_playback_urbs)) {
+ /* take URB out of FIFO */
+ ctx = list_first_entry(&ep->ready_playback_urbs,
+ struct snd_urb_ctx, ready_list);
+ list_del_init(&ctx->ready_list);
+-
+- packet = next_packet_fifo_dequeue(ep);
++ if (implicit_fb)
++ packet = next_packet_fifo_dequeue(ep);
+ }
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+@@ -435,11 +471,24 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+ return;
+
+ /* copy over the length information */
+- for (i = 0; i < packet->packets; i++)
+- ctx->packet_size[i] = packet->packet_size[i];
++ if (implicit_fb) {
++ for (i = 0; i < packet->packets; i++)
++ ctx->packet_size[i] = packet->packet_size[i];
++ }
+
+ /* call the data handler to fill in playback data */
+- prepare_outbound_urb(ep, ctx);
++ err = prepare_outbound_urb(ep, ctx, in_stream_lock);
++ /* can be stopped during prepare callback */
++ if (unlikely(!ep_state_running(ep)))
++ break;
++ if (err < 0) {
++ /* push back to ready list again for -EAGAIN */
++ if (err == -EAGAIN)
++ push_back_to_ready_list(ep, ctx);
++ else
++ notify_xrun(ep);
++ return;
++ }
+
+ err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
+ if (err < 0) {
+@@ -451,6 +500,7 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+ }
+
+ set_bit(ctx->index, &ep->active_mask);
++ atomic_inc(&ep->submitted_urbs);
+ }
+ }
+
+@@ -461,7 +511,6 @@ static void snd_complete_urb(struct urb *urb)
+ {
+ struct snd_urb_ctx *ctx = urb->context;
+ struct snd_usb_endpoint *ep = ctx->ep;
+- unsigned long flags;
+ int err;
+
+ if (unlikely(urb->status == -ENOENT || /* unlinked */
+@@ -482,16 +531,20 @@ static void snd_complete_urb(struct urb *urb)
+ if (unlikely(!ep_state_running(ep)))
+ goto exit_clear;
+
+- if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
+- spin_lock_irqsave(&ep->lock, flags);
+- list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
++ /* in low-latency and implicit-feedback modes, push back the
++ * URB to ready list at first, then process as much as possible
++ */
++ if (ep->lowlatency_playback ||
++ snd_usb_endpoint_implicit_feedback_sink(ep)) {
++ push_back_to_ready_list(ep, ctx);
+ clear_bit(ctx->index, &ep->active_mask);
+- spin_unlock_irqrestore(&ep->lock, flags);
+- queue_pending_output_urbs(ep);
++ snd_usb_queue_pending_output_urbs(ep, false);
++ atomic_dec(&ep->submitted_urbs); /* decrement at last */
+ return;
+ }
+
+- prepare_outbound_urb(ep, ctx);
++ /* in non-lowlatency mode, no error handling for prepare */
++ prepare_outbound_urb(ep, ctx, false);
+ /* can be stopped during prepare callback */
+ if (unlikely(!ep_state_running(ep)))
+ goto exit_clear;
+@@ -513,6 +566,7 @@ static void snd_complete_urb(struct urb *urb)
+
+ exit_clear:
+ clear_bit(ctx->index, &ep->active_mask);
++ atomic_dec(&ep->submitted_urbs);
+ }
+
+ /*
+@@ -596,6 +650,7 @@ int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type)
+ ep->type = type;
+ ep->ep_num = ep_num;
+ INIT_LIST_HEAD(&ep->ready_playback_urbs);
++ atomic_set(&ep->submitted_urbs, 0);
+
+ is_playback = ((ep_num & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+ ep_num &= USB_ENDPOINT_NUMBER_MASK;
+@@ -722,6 +777,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
+ ep->cur_period_frames = params_period_size(params);
+ ep->cur_period_bytes = ep->cur_period_frames * ep->cur_frame_bytes;
+ ep->cur_buffer_periods = params_periods(params);
++ ep->cur_clock = fp->clock;
+
+ if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
+ endpoint_set_syncinterval(chip, ep);
+@@ -781,14 +837,19 @@ void snd_usb_endpoint_set_sync(struct snd_usb_audio *chip,
+ * Pass NULL to deactivate each callback.
+ */
+ void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep,
+- void (*prepare)(struct snd_usb_substream *subs,
+- struct urb *urb),
++ int (*prepare)(struct snd_usb_substream *subs,
++ struct urb *urb,
++ bool in_stream_lock),
+ void (*retire)(struct snd_usb_substream *subs,
+ struct urb *urb),
+ struct snd_usb_substream *data_subs)
+ {
+ ep->prepare_data_urb = prepare;
+ ep->retire_data_urb = retire;
++ if (data_subs)
++ ep->lowlatency_playback = data_subs->lowlatency_playback;
++ else
++ ep->lowlatency_playback = false;
+ WRITE_ONCE(ep->data_subs, data_subs);
+ }
+
+@@ -833,6 +894,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
+ ep->altsetting = 0;
+ ep->cur_audiofmt = NULL;
+ ep->cur_rate = 0;
++ ep->cur_clock = 0;
+ ep->iface_ref = NULL;
+ usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num);
+ }
+@@ -859,7 +921,7 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
+ return 0;
+
+ do {
+- alive = bitmap_weight(&ep->active_mask, ep->nurbs);
++ alive = atomic_read(&ep->submitted_urbs);
+ if (!alive)
+ break;
+
+@@ -893,9 +955,10 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
+ *
+ * This function moves the EP to STOPPING state if it's being RUNNING.
+ */
+-static int stop_urbs(struct snd_usb_endpoint *ep, bool force)
++static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending)
+ {
+ unsigned int i;
++ unsigned long flags;
+
+ if (!force && atomic_read(&ep->running))
+ return -EBUSY;
+@@ -903,9 +966,14 @@ static int stop_urbs(struct snd_usb_endpoint *ep, bool force)
+ if (!ep_state_update(ep, EP_STATE_RUNNING, EP_STATE_STOPPING))
+ return 0;
+
++ spin_lock_irqsave(&ep->lock, flags);
+ INIT_LIST_HEAD(&ep->ready_playback_urbs);
+ ep->next_packet_head = 0;
+ ep->next_packet_queued = 0;
++ spin_unlock_irqrestore(&ep->lock, flags);
++
++ if (keep_pending)
++ return 0;
+
+ for (i = 0; i < ep->nurbs; i++) {
+ if (test_bit(i, &ep->active_mask)) {
+@@ -930,7 +998,7 @@ static int release_urbs(struct snd_usb_endpoint *ep, bool force)
+ snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
+
+ /* stop and unlink urbs */
+- err = stop_urbs(ep, force);
++ err = stop_urbs(ep, force, false);
+ if (err)
+ return err;
+
+@@ -1132,10 +1200,6 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
+ INIT_LIST_HEAD(&u->ready_list);
+ }
+
+- /* total buffer bytes of all URBs plus the next queue;
+- * referred in pcm.c
+- */
+- ep->nominal_queue_size = maxsize * urb_packs * (ep->nurbs + 1);
+ return 0;
+
+ out_of_memory:
+@@ -1340,6 +1404,25 @@ unlock:
+ return err;
+ }
+
++/* get the current rate set to the given clock by any endpoint */
++int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock)
++{
++ struct snd_usb_endpoint *ep;
++ int rate = 0;
++
++ if (!clock)
++ return 0;
++ mutex_lock(&chip->mutex);
++ list_for_each_entry(ep, &chip->ep_list, list) {
++ if (ep->cur_clock == clock && ep->cur_rate) {
++ rate = ep->cur_rate;
++ break;
++ }
++ }
++ mutex_unlock(&chip->mutex);
++ return rate;
++}
++
+ /**
+ * snd_usb_endpoint_start: start an snd_usb_endpoint
+ *
+@@ -1355,6 +1438,7 @@ unlock:
+ */
+ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+ {
++ bool is_playback = usb_pipeout(ep->pipe);
+ int err;
+ unsigned int i;
+
+@@ -1391,13 +1475,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+
+ if (snd_usb_endpoint_implicit_feedback_sink(ep) &&
+ !(ep->chip->quirk_flags & QUIRK_FLAG_PLAYBACK_FIRST)) {
+- for (i = 0; i < ep->nurbs; i++) {
+- struct snd_urb_ctx *ctx = ep->urb + i;
+- list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+- }
+-
+ usb_audio_dbg(ep->chip, "No URB submission due to implicit fb sync\n");
+- return 0;
++ i = 0;
++ goto fill_rest;
+ }
+
+ for (i = 0; i < ep->nurbs; i++) {
+@@ -1406,10 +1486,18 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+ if (snd_BUG_ON(!urb))
+ goto __error;
+
+- if (usb_pipeout(ep->pipe)) {
+- prepare_outbound_urb(ep, urb->context);
+- } else {
+- prepare_inbound_urb(ep, urb->context);
++ if (is_playback)
++ err = prepare_outbound_urb(ep, urb->context, true);
++ else
++ err = prepare_inbound_urb(ep, urb->context);
++ if (err < 0) {
++ /* stop filling at applptr */
++ if (err == -EAGAIN)
++ break;
++ usb_audio_dbg(ep->chip,
++ "EP 0x%x: failed to prepare urb: %d\n",
++ ep->ep_num, err);
++ goto __error;
+ }
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -1420,14 +1508,29 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+ goto __error;
+ }
+ set_bit(i, &ep->active_mask);
++ atomic_inc(&ep->submitted_urbs);
++ }
++
++ if (!i) {
++ usb_audio_dbg(ep->chip, "XRUN at starting EP 0x%x\n",
++ ep->ep_num);
++ goto __error;
+ }
+
+ usb_audio_dbg(ep->chip, "%d URBs submitted for EP 0x%x\n",
+- ep->nurbs, ep->ep_num);
++ i, ep->ep_num);
++
++ fill_rest:
++ /* put the remaining URBs to ready list */
++ if (is_playback) {
++ for (; i < ep->nurbs; i++)
++ push_back_to_ready_list(ep, ep->urb + i);
++ }
++
+ return 0;
+
+ __error:
+- snd_usb_endpoint_stop(ep);
++ snd_usb_endpoint_stop(ep, false);
+ return -EPIPE;
+ }
+
+@@ -1435,6 +1538,7 @@ __error:
+ * snd_usb_endpoint_stop: stop an snd_usb_endpoint
+ *
+ * @ep: the endpoint to stop (may be NULL)
++ * @keep_pending: keep in-flight URBs
+ *
+ * A call to this function will decrement the running count of the endpoint.
+ * In case the last user has requested the endpoint stop, the URBs will
+@@ -1445,7 +1549,7 @@ __error:
+ * The caller needs to synchronize the pending stop operation via
+ * snd_usb_endpoint_sync_pending_stop().
+ */
+-void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
++void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending)
+ {
+ if (!ep)
+ return;
+@@ -1460,7 +1564,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
+ if (!atomic_dec_return(&ep->running)) {
+ if (ep->sync_source)
+ WRITE_ONCE(ep->sync_source->sync_sink, NULL);
+- stop_urbs(ep, false);
++ stop_urbs(ep, false, keep_pending);
+ }
+ }
+
+@@ -1575,7 +1679,7 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+ }
+
+ spin_unlock_irqrestore(&ep->lock, flags);
+- queue_pending_output_urbs(ep);
++ snd_usb_queue_pending_output_urbs(ep, false);
+
+ return;
+ }
+diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
+index a668f675b52b0..6a9af04cf175a 100644
+--- a/sound/usb/endpoint.h
++++ b/sound/usb/endpoint.h
+@@ -19,6 +19,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
+ struct snd_usb_endpoint *ep);
+ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
+ struct snd_usb_endpoint *ep);
++int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock);
+
+ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip,
+ struct snd_usb_endpoint *ep,
+@@ -29,14 +30,15 @@ void snd_usb_endpoint_set_sync(struct snd_usb_audio *chip,
+ struct snd_usb_endpoint *data_ep,
+ struct snd_usb_endpoint *sync_ep);
+ void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep,
+- void (*prepare)(struct snd_usb_substream *subs,
+- struct urb *urb),
++ int (*prepare)(struct snd_usb_substream *subs,
++ struct urb *urb,
++ bool in_stream_lock),
+ void (*retire)(struct snd_usb_substream *subs,
+ struct urb *urb),
+ struct snd_usb_substream *data_subs);
+
+ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
+-void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep);
++void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending);
+ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
+ void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep);
+ int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
+@@ -45,6 +47,9 @@ void snd_usb_endpoint_free_all(struct snd_usb_audio *chip);
+
+ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
+ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
+- struct snd_urb_ctx *ctx, int idx);
++ struct snd_urb_ctx *ctx, int idx,
++ unsigned int avail);
++void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
++ bool in_stream_lock);
+
+ #endif /* __USBAUDIO_ENDPOINT_H */
+diff --git a/sound/usb/format.c b/sound/usb/format.c
+index 50efccbffb8a7..f5e676a51b30d 100644
+--- a/sound/usb/format.c
++++ b/sound/usb/format.c
+@@ -414,6 +414,7 @@ static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip,
+ case USB_ID(0x0e41, 0x4242): /* Line6 Helix Rack */
+ case USB_ID(0x0e41, 0x4244): /* Line6 Helix LT */
+ case USB_ID(0x0e41, 0x4246): /* Line6 HX-Stomp */
++ case USB_ID(0x0e41, 0x4253): /* Line6 HX-Stomp XL */
+ case USB_ID(0x0e41, 0x4247): /* Line6 Pod Go */
+ case USB_ID(0x0e41, 0x4248): /* Line6 Helix >= fw 2.82 */
+ case USB_ID(0x0e41, 0x4249): /* Line6 Helix Rack >= fw 2.82 */
+diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
+index 23767a14d1266..70319c822c10b 100644
+--- a/sound/usb/implicit.c
++++ b/sound/usb/implicit.c
+@@ -54,8 +54,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
+
+ /* Fixed EP */
+ /* FIXME: check the availability of generic matching */
+- IMPLICIT_FB_FIXED_DEV(0x1397, 0x0001, 0x81, 1), /* Behringer UFX1604 */
+- IMPLICIT_FB_FIXED_DEV(0x1397, 0x0002, 0x81, 1), /* Behringer UFX1204 */
+ IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */
+ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */
+ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */
+diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
+index 9602929b7de90..59faa5a9a7141 100644
+--- a/sound/usb/line6/driver.c
++++ b/sound/usb/line6/driver.c
+@@ -113,12 +113,12 @@ int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+ retval = usb_interrupt_msg(line6->usbdev,
+ usb_sndintpipe(line6->usbdev, properties->ep_ctrl_w),
+ (char *)frag_buf, frag_size,
+- &partial, LINE6_TIMEOUT * HZ);
++ &partial, LINE6_TIMEOUT);
+ } else {
+ retval = usb_bulk_msg(line6->usbdev,
+ usb_sndbulkpipe(line6->usbdev, properties->ep_ctrl_w),
+ (char *)frag_buf, frag_size,
+- &partial, LINE6_TIMEOUT * HZ);
++ &partial, LINE6_TIMEOUT);
+ }
+
+ if (retval) {
+@@ -347,7 +347,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
+ ret = usb_control_msg_send(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ (datalen << 8) | 0x21, address, NULL, 0,
+- LINE6_TIMEOUT * HZ, GFP_KERNEL);
++ LINE6_TIMEOUT, GFP_KERNEL);
+ if (ret) {
+ dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
+ goto exit;
+@@ -360,7 +360,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
+ ret = usb_control_msg_recv(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x0012, 0x0000, &len, 1,
+- LINE6_TIMEOUT * HZ, GFP_KERNEL);
++ LINE6_TIMEOUT, GFP_KERNEL);
+ if (ret) {
+ dev_err(line6->ifcdev,
+ "receive length failed (error %d)\n", ret);
+@@ -387,7 +387,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
+ /* receive the result: */
+ ret = usb_control_msg_recv(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+- 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT * HZ,
++ 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT,
+ GFP_KERNEL);
+ if (ret)
+ dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
+@@ -417,7 +417,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
+
+ ret = usb_control_msg_send(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+- 0x0022, address, data, datalen, LINE6_TIMEOUT * HZ,
++ 0x0022, address, data, datalen, LINE6_TIMEOUT,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(line6->ifcdev,
+@@ -430,7 +430,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
+
+ ret = usb_control_msg_recv(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+- 0x0012, 0x0000, status, 1, LINE6_TIMEOUT * HZ,
++ 0x0012, 0x0000, status, 1, LINE6_TIMEOUT,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(line6->ifcdev,
+diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
+index 71d3da1db8c81..ecf3a2b39c7eb 100644
+--- a/sound/usb/line6/driver.h
++++ b/sound/usb/line6/driver.h
+@@ -27,7 +27,7 @@
+ #define LINE6_FALLBACK_INTERVAL 10
+ #define LINE6_FALLBACK_MAXPACKETSIZE 16
+
+-#define LINE6_TIMEOUT 1
++#define LINE6_TIMEOUT 1000
+ #define LINE6_BUFSIZE_LISTEN 64
+ #define LINE6_MIDI_MESSAGE_MAXLEN 256
+
+diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
+index 28794a35949d4..b24bc82f89e37 100644
+--- a/sound/usb/line6/podhd.c
++++ b/sound/usb/line6/podhd.c
+@@ -190,7 +190,7 @@ static int podhd_dev_start(struct usb_line6_podhd *pod)
+ ret = usb_control_msg_send(usbdev, 0,
+ 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x11, 0,
+- NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
++ NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
+ if (ret) {
+ dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
+ goto exit;
+@@ -200,7 +200,7 @@ static int podhd_dev_start(struct usb_line6_podhd *pod)
+ ret = usb_control_msg_recv(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x11, 0x0,
+- init_bytes, 3, LINE6_TIMEOUT * HZ, GFP_KERNEL);
++ init_bytes, 3, LINE6_TIMEOUT, GFP_KERNEL);
+ if (ret) {
+ dev_err(pod->line6.ifcdev,
+ "receive length failed (error %d)\n", ret);
+@@ -220,7 +220,7 @@ static int podhd_dev_start(struct usb_line6_podhd *pod)
+ USB_REQ_SET_FEATURE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 1, 0,
+- NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
++ NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
+ exit:
+ return ret;
+ }
+diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
+index 4e5693c97aa42..e33df58740a91 100644
+--- a/sound/usb/line6/toneport.c
++++ b/sound/usb/line6/toneport.c
+@@ -128,7 +128,7 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
+
+ ret = usb_control_msg_send(usbdev, 0, 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+- cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ,
++ cmd1, cmd2, NULL, 0, LINE6_TIMEOUT,
+ GFP_KERNEL);
+
+ if (ret) {
+diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
+index 5834d1dc317ef..4f6b20ed29dd7 100644
+--- a/sound/usb/misc/ua101.c
++++ b/sound/usb/misc/ua101.c
+@@ -1000,7 +1000,7 @@ static int detect_usb_format(struct ua101 *ua)
+ fmt_playback->bSubframeSize * ua->playback.channels;
+
+ epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc;
+- if (!usb_endpoint_is_isoc_in(epd)) {
++ if (!usb_endpoint_is_isoc_in(epd) || usb_endpoint_maxp(epd) == 0) {
+ dev_err(&ua->dev->dev, "invalid capture endpoint\n");
+ return -ENXIO;
+ }
+@@ -1008,7 +1008,7 @@ static int detect_usb_format(struct ua101 *ua)
+ ua->capture.max_packet_bytes = usb_endpoint_maxp(epd);
+
+ epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc;
+- if (!usb_endpoint_is_isoc_out(epd)) {
++ if (!usb_endpoint_is_isoc_out(epd) || usb_endpoint_maxp(epd) == 0) {
+ dev_err(&ua->dev->dev, "invalid playback endpoint\n");
+ return -ENXIO;
+ }
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index 46082dc57be09..823b6b8de942d 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -2795,6 +2795,7 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
+ #define SND_DJM_750_IDX 0x1
+ #define SND_DJM_850_IDX 0x2
+ #define SND_DJM_900NXS2_IDX 0x3
++#define SND_DJM_750MK2_IDX 0x4
+
+
+ #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
+@@ -2984,12 +2985,42 @@ static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = {
+ SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP)
+ };
+
++// DJM-750MK2
++static const u16 snd_djm_opts_750mk2_cap1[] = {
++ 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a };
++static const u16 snd_djm_opts_750mk2_cap2[] = {
++ 0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a };
++static const u16 snd_djm_opts_750mk2_cap3[] = {
++ 0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a };
++static const u16 snd_djm_opts_750mk2_cap4[] = {
++ 0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a };
++static const u16 snd_djm_opts_750mk2_cap5[] = {
++ 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 };
++
++static const u16 snd_djm_opts_750mk2_pb1[] = { 0x0100, 0x0101, 0x0104 };
++static const u16 snd_djm_opts_750mk2_pb2[] = { 0x0200, 0x0201, 0x0204 };
++static const u16 snd_djm_opts_750mk2_pb3[] = { 0x0300, 0x0301, 0x0304 };
++
++
++static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = {
++ SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
++ SND_DJM_CTL("Ch1 Input", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP),
++ SND_DJM_CTL("Ch2 Input", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP),
++ SND_DJM_CTL("Ch3 Input", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP),
++ SND_DJM_CTL("Ch4 Input", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP),
++ SND_DJM_CTL("Ch5 Input", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP),
++ SND_DJM_CTL("Ch1 Output", 750mk2_pb1, 0, SND_DJM_WINDEX_PB),
++ SND_DJM_CTL("Ch2 Output", 750mk2_pb2, 1, SND_DJM_WINDEX_PB),
++ SND_DJM_CTL("Ch3 Output", 750mk2_pb3, 2, SND_DJM_WINDEX_PB)
++};
++
+
+ static const struct snd_djm_device snd_djm_devices[] = {
+- SND_DJM_DEVICE(250mk2),
+- SND_DJM_DEVICE(750),
+- SND_DJM_DEVICE(850),
+- SND_DJM_DEVICE(900nxs2)
++ [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2),
++ [SND_DJM_750_IDX] = SND_DJM_DEVICE(750),
++ [SND_DJM_850_IDX] = SND_DJM_DEVICE(850),
++ [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2),
++ [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2),
+ };
+
+
+@@ -3235,6 +3266,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
+ case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */
+ err = snd_djm_controls_create(mixer, SND_DJM_750_IDX);
+ break;
++ case USB_ID(0x2b73, 0x001b): /* Pioneer DJ DJM-750MK2 */
++ err = snd_djm_controls_create(mixer, SND_DJM_750MK2_IDX);
++ break;
+ case USB_ID(0x08e4, 0x0163): /* Pioneer DJ DJM-850 */
+ err = snd_djm_controls_create(mixer, SND_DJM_850_IDX);
+ break;
+diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
+index 5dc9266180e37..2e51fb031ae01 100644
+--- a/sound/usb/pcm.c
++++ b/sound/usb/pcm.c
+@@ -219,16 +219,16 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip,
+ return 0;
+ }
+
+-static bool stop_endpoints(struct snd_usb_substream *subs)
++static bool stop_endpoints(struct snd_usb_substream *subs, bool keep_pending)
+ {
+ bool stopped = 0;
+
+ if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
+- snd_usb_endpoint_stop(subs->sync_endpoint);
++ snd_usb_endpoint_stop(subs->sync_endpoint, keep_pending);
+ stopped = true;
+ }
+ if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
+- snd_usb_endpoint_stop(subs->data_endpoint);
++ snd_usb_endpoint_stop(subs->data_endpoint, keep_pending);
+ stopped = true;
+ }
+ return stopped;
+@@ -261,7 +261,7 @@ static int start_endpoints(struct snd_usb_substream *subs)
+ return 0;
+
+ error:
+- stop_endpoints(subs);
++ stop_endpoints(subs, false);
+ return err;
+ }
+
+@@ -437,7 +437,7 @@ static int configure_endpoints(struct snd_usb_audio *chip,
+
+ if (subs->data_endpoint->need_setup) {
+ /* stop any running stream beforehand */
+- if (stop_endpoints(subs))
++ if (stop_endpoints(subs, false))
+ sync_pending_stops(subs);
+ err = snd_usb_endpoint_configure(chip, subs->data_endpoint);
+ if (err < 0)
+@@ -572,7 +572,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
+ subs->cur_audiofmt = NULL;
+ mutex_unlock(&chip->mutex);
+ if (!snd_usb_lock_shutdown(chip)) {
+- if (stop_endpoints(subs))
++ if (stop_endpoints(subs, false))
+ sync_pending_stops(subs);
+ close_endpoints(chip, subs);
+ snd_usb_unlock_shutdown(chip);
+@@ -581,6 +581,31 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
+ return 0;
+ }
+
++/* free-wheeling mode? (e.g. dmix) */
++static int in_free_wheeling_mode(struct snd_pcm_runtime *runtime)
++{
++ return runtime->stop_threshold > runtime->buffer_size;
++}
++
++/* check whether early start is needed for playback stream */
++static int lowlatency_playback_available(struct snd_pcm_runtime *runtime,
++ struct snd_usb_substream *subs)
++{
++ struct snd_usb_audio *chip = subs->stream->chip;
++
++ if (subs->direction == SNDRV_PCM_STREAM_CAPTURE)
++ return false;
++ /* disabled via module option? */
++ if (!chip->lowlatency)
++ return false;
++ if (in_free_wheeling_mode(runtime))
++ return false;
++ /* implicit feedback mode has own operation mode */
++ if (snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint))
++ return false;
++ return true;
++}
++
+ /*
+ * prepare callback
+ *
+@@ -614,13 +639,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
+ subs->period_elapsed_pending = 0;
+ runtime->delay = 0;
+
+- /* check whether early start is needed for playback stream */
+- subs->early_playback_start =
+- subs->direction == SNDRV_PCM_STREAM_PLAYBACK &&
+- (!chip->lowlatency ||
+- (subs->data_endpoint->nominal_queue_size >= subs->buffer_bytes));
+-
+- if (subs->early_playback_start)
++ subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
++ !subs->lowlatency_playback)
+ ret = start_endpoints(subs);
+
+ unlock:
+@@ -734,6 +755,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+ {
+ struct snd_usb_substream *subs = rule->private;
++ struct snd_usb_audio *chip = subs->stream->chip;
+ const struct audioformat *fp;
+ struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ unsigned int rmin, rmax, r;
+@@ -745,6 +767,14 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
+ list_for_each_entry(fp, &subs->fmt_list, list) {
+ if (!hw_check_valid_format(subs, params, fp))
+ continue;
++ r = snd_usb_endpoint_get_clock_rate(chip, fp->clock);
++ if (r > 0) {
++ if (!snd_interval_test(it, r))
++ continue;
++ rmin = min(rmin, r);
++ rmax = max(rmax, r);
++ continue;
++ }
+ if (fp->rate_table && fp->nr_rates) {
+ for (i = 0; i < fp->nr_rates; i++) {
+ r = fp->rate_table[i];
+@@ -1068,6 +1098,10 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
+ int ret;
+
+ runtime->hw = snd_usb_hardware;
++ /* need an explicit sync to catch applptr update in low-latency mode */
++ if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
++ as->chip->lowlatency)
++ runtime->hw.info |= SNDRV_PCM_INFO_SYNC_APPLPTR;
+ runtime->private_data = subs;
+ subs->pcm_substream = substream;
+ /* runtime PM is also done there */
+@@ -1320,44 +1354,66 @@ static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs,
+ return bytes;
+ }
+
+-static void prepare_playback_urb(struct snd_usb_substream *subs,
+- struct urb *urb)
++static int prepare_playback_urb(struct snd_usb_substream *subs,
++ struct urb *urb,
++ bool in_stream_lock)
+ {
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ struct snd_usb_endpoint *ep = subs->data_endpoint;
+ struct snd_urb_ctx *ctx = urb->context;
+- unsigned int counts, frames, bytes;
++ unsigned int frames, bytes;
++ int counts;
++ unsigned int transfer_done, frame_limit, avail = 0;
+ int i, stride, period_elapsed = 0;
+ unsigned long flags;
++ int err = 0;
+
+ stride = ep->stride;
+
+ frames = 0;
+ ctx->queued = 0;
+ urb->number_of_packets = 0;
++
+ spin_lock_irqsave(&subs->lock, flags);
+- subs->frame_limit += ep->max_urb_frames;
++ frame_limit = subs->frame_limit + ep->max_urb_frames;
++ transfer_done = subs->transfer_done;
++
++ if (subs->lowlatency_playback &&
++ runtime->status->state != SNDRV_PCM_STATE_DRAINING) {
++ unsigned int hwptr = subs->hwptr_done / stride;
++
++ /* calculate the byte offset-in-buffer of the appl_ptr */
++ avail = (runtime->control->appl_ptr - runtime->hw_ptr_base)
++ % runtime->buffer_size;
++ if (avail <= hwptr)
++ avail += runtime->buffer_size;
++ avail -= hwptr;
++ }
++
+ for (i = 0; i < ctx->packets; i++) {
+- counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
++ counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail);
++ if (counts < 0)
++ break;
+ /* set up descriptor */
+ urb->iso_frame_desc[i].offset = frames * stride;
+ urb->iso_frame_desc[i].length = counts * stride;
+ frames += counts;
++ avail -= counts;
+ urb->number_of_packets++;
+- subs->transfer_done += counts;
+- if (subs->transfer_done >= runtime->period_size) {
+- subs->transfer_done -= runtime->period_size;
+- subs->frame_limit = 0;
++ transfer_done += counts;
++ if (transfer_done >= runtime->period_size) {
++ transfer_done -= runtime->period_size;
++ frame_limit = 0;
+ period_elapsed = 1;
+ if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
+- if (subs->transfer_done > 0) {
++ if (transfer_done > 0) {
+ /* FIXME: fill-max mode is not
+ * supported yet */
+- frames -= subs->transfer_done;
+- counts -= subs->transfer_done;
++ frames -= transfer_done;
++ counts -= transfer_done;
+ urb->iso_frame_desc[i].length =
+ counts * stride;
+- subs->transfer_done = 0;
++ transfer_done = 0;
+ }
+ i++;
+ if (i < ctx->packets) {
+@@ -1371,13 +1427,19 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
+ }
+ }
+ /* finish at the period boundary or after enough frames */
+- if ((period_elapsed ||
+- subs->transfer_done >= subs->frame_limit) &&
++ if ((period_elapsed || transfer_done >= frame_limit) &&
+ !snd_usb_endpoint_implicit_feedback_sink(ep))
+ break;
+ }
+- bytes = frames * stride;
+
++ if (!frames) {
++ err = -EAGAIN;
++ goto unlock;
++ }
++
++ bytes = frames * stride;
++ subs->transfer_done = transfer_done;
++ subs->frame_limit = frame_limit;
+ if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE &&
+ subs->cur_audiofmt->dsd_dop)) {
+ fill_playback_urb_dsd_dop(subs, urb, bytes);
+@@ -1403,14 +1465,23 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
+ subs->trigger_tstamp_pending_update = false;
+ }
+
+- if (period_elapsed && !subs->running && !subs->early_playback_start) {
++ if (period_elapsed && !subs->running && subs->lowlatency_playback) {
+ subs->period_elapsed_pending = 1;
+ period_elapsed = 0;
+ }
++
++ unlock:
+ spin_unlock_irqrestore(&subs->lock, flags);
++ if (err < 0)
++ return err;
+ urb->transfer_buffer_length = bytes;
+- if (period_elapsed)
+- snd_pcm_period_elapsed(subs->pcm_substream);
++ if (period_elapsed) {
++ if (in_stream_lock)
++ snd_pcm_period_elapsed_under_stream_lock(subs->pcm_substream);
++ else
++ snd_pcm_period_elapsed(subs->pcm_substream);
++ }
++ return 0;
+ }
+
+ /*
+@@ -1442,6 +1513,27 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
+ snd_pcm_period_elapsed(subs->pcm_substream);
+ }
+
++/* PCM ack callback for the playback stream;
++ * this plays a role only when the stream is running in low-latency mode.
++ */
++static int snd_usb_pcm_playback_ack(struct snd_pcm_substream *substream)
++{
++ struct snd_usb_substream *subs = substream->runtime->private_data;
++ struct snd_usb_endpoint *ep;
++
++ if (!subs->lowlatency_playback || !subs->running)
++ return 0;
++ ep = subs->data_endpoint;
++ if (!ep)
++ return 0;
++ /* When no more in-flight URBs available, try to process the pending
++ * outputs here
++ */
++ if (!ep->active_mask)
++ snd_usb_queue_pending_output_urbs(ep, true);
++ return 0;
++}
++
+ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+ {
+@@ -1457,8 +1549,10 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
+ prepare_playback_urb,
+ retire_playback_urb,
+ subs);
+- if (!subs->early_playback_start &&
++ if (subs->lowlatency_playback &&
+ cmd == SNDRV_PCM_TRIGGER_START) {
++ if (in_free_wheeling_mode(substream->runtime))
++ subs->lowlatency_playback = false;
+ err = start_endpoints(subs);
+ if (err < 0) {
+ snd_usb_endpoint_set_callback(subs->data_endpoint,
+@@ -1473,7 +1567,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
+ return 0;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+- stop_endpoints(subs);
++ stop_endpoints(subs, substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING);
+ snd_usb_endpoint_set_callback(subs->data_endpoint,
+ NULL, NULL, NULL);
+ subs->running = 0;
+@@ -1521,7 +1615,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
+ return 0;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+- stop_endpoints(subs);
++ stop_endpoints(subs, false);
+ fallthrough;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ snd_usb_endpoint_set_callback(subs->data_endpoint,
+@@ -1545,6 +1639,7 @@ static const struct snd_pcm_ops snd_usb_playback_ops = {
+ .trigger = snd_usb_substream_playback_trigger,
+ .sync_stop = snd_usb_pcm_sync_stop,
+ .pointer = snd_usb_pcm_pointer,
++ .ack = snd_usb_pcm_playback_ack,
+ };
+
+ static const struct snd_pcm_ops snd_usb_capture_ops = {
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index 2af8c68fac275..b1522e43173e1 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -3892,6 +3892,64 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ }
+ }
+ },
++{
++ /*
++ * Pioneer DJ DJM-750MK2
++ * 10 channels playback & 12 channels capture @ 48kHz S24LE
++ */
++ USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001b),
++ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++ .ifnum = QUIRK_ANY_INTERFACE,
++ .type = QUIRK_COMPOSITE,
++ .data = (const struct snd_usb_audio_quirk[]) {
++ {
++ .ifnum = 0,
++ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
++ .data = &(const struct audioformat) {
++ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
++ .channels = 10,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x01,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC|
++ USB_ENDPOINT_SYNC_ASYNC,
++ .rates = SNDRV_PCM_RATE_48000,
++ .rate_min = 48000,
++ .rate_max = 48000,
++ .nr_rates = 1,
++ .rate_table = (unsigned int[]) {
++ 48000
++ }
++ }
++ },
++ {
++ .ifnum = 0,
++ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
++ .data = &(const struct audioformat) {
++ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
++ .channels = 12,
++ .iface = 0,
++ .altsetting = 1,
++ .altset_idx = 1,
++ .endpoint = 0x82,
++ .ep_idx = 1,
++ .ep_attr = USB_ENDPOINT_XFER_ISOC|
++ USB_ENDPOINT_SYNC_ASYNC|
++ USB_ENDPOINT_USAGE_IMPLICIT_FB,
++ .rates = SNDRV_PCM_RATE_48000,
++ .rate_min = 48000,
++ .rate_max = 48000,
++ .nr_rates = 1,
++ .rate_table = (unsigned int[]) { 48000 }
++ }
++ },
++ {
++ .ifnum = -1
++ }
++ }
++ }
++},
+ {
+ /*
+ * Pioneer DJ DJM-850
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 8929d9abe8aa8..64e1c20311ed4 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1749,6 +1749,7 @@ static const struct registration_quirk registration_quirks[] = {
+ REG_QUIRK_ENTRY(0x0951, 0x16ea, 2), /* Kingston HyperX Cloud Flight S */
+ REG_QUIRK_ENTRY(0x0ecb, 0x1f46, 2), /* JBL Quantum 600 */
+ REG_QUIRK_ENTRY(0x0ecb, 0x1f47, 2), /* JBL Quantum 800 */
++ REG_QUIRK_ENTRY(0x0ecb, 0x1f4c, 2), /* JBL Quantum 400 */
+ REG_QUIRK_ENTRY(0x0ecb, 0x2039, 2), /* JBL Quantum 400 */
+ REG_QUIRK_ENTRY(0x0ecb, 0x203c, 2), /* JBL Quantum 600 */
+ REG_QUIRK_ENTRY(0x0ecb, 0x203e, 2), /* JBL Quantum 800 */
+@@ -1887,6 +1888,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
++ DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */
++ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */
+diff --git a/tools/arch/x86/lib/insn.c b/tools/arch/x86/lib/insn.c
+index 797699462cd8e..8fd63a067308a 100644
+--- a/tools/arch/x86/lib/insn.c
++++ b/tools/arch/x86/lib/insn.c
+@@ -13,6 +13,7 @@
+ #endif
+ #include "../include/asm/inat.h" /* __ignore_sync_check__ */
+ #include "../include/asm/insn.h" /* __ignore_sync_check__ */
++#include "../include/asm-generic/unaligned.h" /* __ignore_sync_check__ */
+
+ #include <linux/errno.h>
+ #include <linux/kconfig.h>
+@@ -37,10 +38,10 @@
+ ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
+
+ #define __get_next(t, insn) \
+- ({ t r; memcpy(&r, insn->next_byte, sizeof(t)); insn->next_byte += sizeof(t); leXX_to_cpu(t, r); })
++ ({ t r = get_unaligned((t *)(insn)->next_byte); (insn)->next_byte += sizeof(t); leXX_to_cpu(t, r); })
+
+ #define __peek_nbyte_next(t, insn, n) \
+- ({ t r; memcpy(&r, (insn)->next_byte + n, sizeof(t)); leXX_to_cpu(t, r); })
++ ({ t r = get_unaligned((t *)(insn)->next_byte + n); leXX_to_cpu(t, r); })
+
+ #define get_next(t, insn) \
+ ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); })
+diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
+index 9c3e343b7d872..fe59404e87046 100644
+--- a/tools/bpf/bpftool/prog.c
++++ b/tools/bpf/bpftool/prog.c
+@@ -308,18 +308,12 @@ static void show_prog_metadata(int fd, __u32 num_maps)
+ if (printed_header)
+ jsonw_end_object(json_wtr);
+ } else {
+- json_writer_t *btf_wtr = jsonw_new(stdout);
++ json_writer_t *btf_wtr;
+ struct btf_dumper d = {
+ .btf = btf,
+- .jw = btf_wtr,
+ .is_plain_text = true,
+ };
+
+- if (!btf_wtr) {
+- p_err("jsonw alloc failed");
+- goto out_free;
+- }
+-
+ for (i = 0; i < vlen; i++, vsi++) {
+ t_var = btf__type_by_id(btf, vsi->type);
+ name = btf__name_by_offset(btf, t_var->name_off);
+@@ -329,6 +323,14 @@ static void show_prog_metadata(int fd, __u32 num_maps)
+
+ if (!printed_header) {
+ printf("\tmetadata:");
++
++ btf_wtr = jsonw_new(stdout);
++ if (!btf_wtr) {
++ p_err("jsonw alloc failed");
++ goto out_free;
++ }
++ d.jw = btf_wtr,
++
+ printed_header = true;
+ }
+
+diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
+index 3dd2f68366f95..88dd7db55d385 100644
+--- a/tools/build/Makefile.feature
++++ b/tools/build/Makefile.feature
+@@ -48,7 +48,6 @@ FEATURE_TESTS_BASIC := \
+ numa_num_possible_cpus \
+ libperl \
+ libpython \
+- libpython-version \
+ libslang \
+ libslang-include-subdir \
+ libtraceevent \
+diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
+index eff55d287db1f..e1e670014bd0c 100644
+--- a/tools/build/feature/Makefile
++++ b/tools/build/feature/Makefile
+@@ -32,7 +32,6 @@ FILES= \
+ test-numa_num_possible_cpus.bin \
+ test-libperl.bin \
+ test-libpython.bin \
+- test-libpython-version.bin \
+ test-libslang.bin \
+ test-libslang-include-subdir.bin \
+ test-libtraceevent.bin \
+@@ -223,9 +222,6 @@ $(OUTPUT)test-libperl.bin:
+ $(OUTPUT)test-libpython.bin:
+ $(BUILD) $(FLAGS_PYTHON_EMBED)
+
+-$(OUTPUT)test-libpython-version.bin:
+- $(BUILD)
+-
+ $(OUTPUT)test-libbfd.bin:
+ $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+
+diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
+index 9204395272912..5ffafb967b6e4 100644
+--- a/tools/build/feature/test-all.c
++++ b/tools/build/feature/test-all.c
+@@ -14,10 +14,6 @@
+ # include "test-libpython.c"
+ #undef main
+
+-#define main main_test_libpython_version
+-# include "test-libpython-version.c"
+-#undef main
+-
+ #define main main_test_libperl
+ # include "test-libperl.c"
+ #undef main
+@@ -177,7 +173,6 @@
+ int main(int argc, char *argv[])
+ {
+ main_test_libpython();
+- main_test_libpython_version();
+ main_test_libperl();
+ main_test_hello();
+ main_test_libelf();
+@@ -200,7 +195,6 @@ int main(int argc, char *argv[])
+ main_test_timerfd();
+ main_test_stackprotector_all();
+ main_test_libdw_dwarf_unwind();
+- main_test_sync_compare_and_swap(argc, argv);
+ main_test_zlib();
+ main_test_pthread_attr_setaffinity_np();
+ main_test_pthread_barrier();
+diff --git a/tools/build/feature/test-libpython-version.c b/tools/build/feature/test-libpython-version.c
+deleted file mode 100644
+index 47714b942d4d3..0000000000000
+--- a/tools/build/feature/test-libpython-version.c
++++ /dev/null
+@@ -1,11 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include <Python.h>
+-
+-#if PY_VERSION_HEX >= 0x03000000
+- #error
+-#endif
+-
+-int main(void)
+-{
+- return 0;
+-}
+diff --git a/tools/include/asm-generic/unaligned.h b/tools/include/asm-generic/unaligned.h
+new file mode 100644
+index 0000000000000..47387c607035e
+--- /dev/null
++++ b/tools/include/asm-generic/unaligned.h
+@@ -0,0 +1,23 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ * Copied from the kernel sources to tools/perf/:
++ */
++
++#ifndef __TOOLS_LINUX_ASM_GENERIC_UNALIGNED_H
++#define __TOOLS_LINUX_ASM_GENERIC_UNALIGNED_H
++
++#define __get_unaligned_t(type, ptr) ({ \
++ const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
++ __pptr->x; \
++})
++
++#define __put_unaligned_t(type, val, ptr) do { \
++ struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
++ __pptr->x = (val); \
++} while (0)
++
++#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
++#define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr))
++
++#endif /* __TOOLS_LINUX_ASM_GENERIC_UNALIGNED_H */
++
+diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
+index 2401fad090c52..bfd1ce9fe2110 100644
+--- a/tools/lib/bpf/bpf.c
++++ b/tools/lib/bpf/bpf.c
+@@ -480,6 +480,7 @@ int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
+ int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, __u64 flags)
+ {
+ union bpf_attr attr;
++ int ret;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = fd;
+@@ -487,7 +488,8 @@ int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, _
+ attr.value = ptr_to_u64(value);
+ attr.flags = flags;
+
+- return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
++ ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
++ return libbpf_err_errno(ret);
+ }
+
+ int bpf_map_delete_elem(int fd, const void *key)
+diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h
+index 09ebe3db5f2f8..e4aa9996a5501 100644
+--- a/tools/lib/bpf/bpf_core_read.h
++++ b/tools/lib/bpf/bpf_core_read.h
+@@ -40,7 +40,7 @@ enum bpf_enum_value_kind {
+ #define __CORE_RELO(src, field, info) \
+ __builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
+
+-#if __BYTE_ORDER == __LITTLE_ENDIAN
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ #define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
+ bpf_probe_read_kernel( \
+ (void *)dst, \
+diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
+index 77dc24d58302d..1b9341ef638b0 100644
+--- a/tools/lib/bpf/btf.c
++++ b/tools/lib/bpf/btf.c
+@@ -231,17 +231,23 @@ static int btf_parse_hdr(struct btf *btf)
+ }
+ btf_bswap_hdr(hdr);
+ } else if (hdr->magic != BTF_MAGIC) {
+- pr_debug("Invalid BTF magic:%x\n", hdr->magic);
++ pr_debug("Invalid BTF magic: %x\n", hdr->magic);
+ return -EINVAL;
+ }
+
+- meta_left = btf->raw_size - sizeof(*hdr);
+- if (meta_left < hdr->str_off + hdr->str_len) {
+- pr_debug("Invalid BTF total size:%u\n", btf->raw_size);
++ if (btf->raw_size < hdr->hdr_len) {
++ pr_debug("BTF header len %u larger than data size %u\n",
++ hdr->hdr_len, btf->raw_size);
+ return -EINVAL;
+ }
+
+- if (hdr->type_off + hdr->type_len > hdr->str_off) {
++ meta_left = btf->raw_size - hdr->hdr_len;
++ if (meta_left < (long long)hdr->str_off + hdr->str_len) {
++ pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
++ return -EINVAL;
++ }
++
++ if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
+ pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
+ hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
+ return -EINVAL;
+@@ -2914,8 +2920,10 @@ int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
+ return libbpf_err(-EINVAL);
+ }
+
+- if (btf_ensure_modifiable(btf))
+- return libbpf_err(-ENOMEM);
++ if (btf_ensure_modifiable(btf)) {
++ err = -ENOMEM;
++ goto done;
++ }
+
+ err = btf_dedup_prep(d);
+ if (err) {
+diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
+index e4f83c304ec92..7145463a4a562 100644
+--- a/tools/lib/bpf/libbpf.c
++++ b/tools/lib/bpf/libbpf.c
+@@ -2993,6 +2993,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
+ }
+ }
+
++ if (!obj->efile.symbols) {
++ pr_warn("elf: couldn't find symbol table in %s, stripped object file?\n",
++ obj->path);
++ return -ENOENT;
++ }
++
+ scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ idx++;
+@@ -5132,7 +5138,7 @@ static int bpf_core_apply_relo(struct bpf_program *prog,
+ * relocated, so it's enough to just subtract in-section offset
+ */
+ insn_idx = insn_idx - prog->sec_insn_off;
+- if (insn_idx > prog->insns_cnt)
++ if (insn_idx >= prog->insns_cnt)
+ return -EINVAL;
+ insn = &prog->insns[insn_idx];
+
+diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
+index b22b50c1b173e..9cf66702fa8dd 100644
+--- a/tools/lib/bpf/skel_internal.h
++++ b/tools/lib/bpf/skel_internal.h
+@@ -105,10 +105,12 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
+ err = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));
+ if (err < 0 || (int)attr.test.retval < 0) {
+ opts->errstr = "failed to execute loader prog";
+- if (err < 0)
++ if (err < 0) {
+ err = -errno;
+- else
++ } else {
+ err = (int)attr.test.retval;
++ errno = -err;
++ }
+ goto out;
+ }
+ err = 0;
+diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
+index 0893436cc09f8..77b51600e3e94 100644
+--- a/tools/objtool/arch/x86/decode.c
++++ b/tools/objtool/arch/x86/decode.c
+@@ -659,6 +659,26 @@ const char *arch_nop_insn(int len)
+ return nops[len-1];
+ }
+
++#define BYTE_RET 0xC3
++
++const char *arch_ret_insn(int len)
++{
++ static const char ret[5][5] = {
++ { BYTE_RET },
++ { BYTE_RET, BYTES_NOP1 },
++ { BYTE_RET, BYTES_NOP2 },
++ { BYTE_RET, BYTES_NOP3 },
++ { BYTE_RET, BYTES_NOP4 },
++ };
++
++ if (len < 1 || len > 5) {
++ WARN("invalid RET size: %d\n", len);
++ return NULL;
++ }
++
++ return ret[len-1];
++}
++
+ /* asm/alternative.h ? */
+
+ #define ALTINSTR_FLAG_INV (1 << 15)
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 06b5c164ae931..81982948f981d 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -173,6 +173,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
+ "rewind_stack_do_exit",
+ "kunit_try_catch_throw",
+ "xen_start_kernel",
++ "cpu_bringup_and_idle",
+ };
+
+ if (!func)
+@@ -828,6 +829,79 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
+ return insn->reloc;
+ }
+
++static void remove_insn_ops(struct instruction *insn)
++{
++ struct stack_op *op, *tmp;
++
++ list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
++ list_del(&op->list);
++ free(op);
++ }
++}
++
++static void add_call_dest(struct objtool_file *file, struct instruction *insn,
++ struct symbol *dest, bool sibling)
++{
++ struct reloc *reloc = insn_reloc(file, insn);
++
++ insn->call_dest = dest;
++ if (!dest)
++ return;
++
++ if (insn->call_dest->static_call_tramp) {
++ list_add_tail(&insn->call_node,
++ &file->static_call_list);
++ }
++
++ /*
++ * Many compilers cannot disable KCOV with a function attribute
++ * so they need a little help, NOP out any KCOV calls from noinstr
++ * text.
++ */
++ if (insn->sec->noinstr &&
++ !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
++ if (reloc) {
++ reloc->type = R_NONE;
++ elf_write_reloc(file->elf, reloc);
++ }
++
++ elf_write_insn(file->elf, insn->sec,
++ insn->offset, insn->len,
++ sibling ? arch_ret_insn(insn->len)
++ : arch_nop_insn(insn->len));
++
++ insn->type = sibling ? INSN_RETURN : INSN_NOP;
++ }
++
++ if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
++ if (sibling)
++ WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset);
++
++ if (reloc) {
++ reloc->type = R_NONE;
++ elf_write_reloc(file->elf, reloc);
++ }
++
++ elf_write_insn(file->elf, insn->sec,
++ insn->offset, insn->len,
++ arch_nop_insn(insn->len));
++
++ insn->type = INSN_NOP;
++
++ list_add_tail(&insn->mcount_loc_node,
++ &file->mcount_loc_list);
++ }
++
++ /*
++ * Whatever stack impact regular CALLs have, should be undone
++ * by the RETURN of the called function.
++ *
++ * Annotated intra-function calls retain the stack_ops but
++ * are converted to JUMP, see read_intra_function_calls().
++ */
++ remove_insn_ops(insn);
++}
++
+ /*
+ * Find the destination instructions for all jumps.
+ */
+@@ -866,11 +940,7 @@ static int add_jump_destinations(struct objtool_file *file)
+ continue;
+ } else if (insn->func) {
+ /* internal or external sibling call (with reloc) */
+- insn->call_dest = reloc->sym;
+- if (insn->call_dest->static_call_tramp) {
+- list_add_tail(&insn->call_node,
+- &file->static_call_list);
+- }
++ add_call_dest(file, insn, reloc->sym, true);
+ continue;
+ } else if (reloc->sym->sec->idx) {
+ dest_sec = reloc->sym->sec;
+@@ -926,13 +996,8 @@ static int add_jump_destinations(struct objtool_file *file)
+
+ } else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
+ insn->jump_dest->offset == insn->jump_dest->func->offset) {
+-
+ /* internal sibling call (without reloc) */
+- insn->call_dest = insn->jump_dest->func;
+- if (insn->call_dest->static_call_tramp) {
+- list_add_tail(&insn->call_node,
+- &file->static_call_list);
+- }
++ add_call_dest(file, insn, insn->jump_dest->func, true);
+ }
+ }
+ }
+@@ -940,16 +1005,6 @@ static int add_jump_destinations(struct objtool_file *file)
+ return 0;
+ }
+
+-static void remove_insn_ops(struct instruction *insn)
+-{
+- struct stack_op *op, *tmp;
+-
+- list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
+- list_del(&op->list);
+- free(op);
+- }
+-}
+-
+ static struct symbol *find_call_destination(struct section *sec, unsigned long offset)
+ {
+ struct symbol *call_dest;
+@@ -968,6 +1023,7 @@ static int add_call_destinations(struct objtool_file *file)
+ {
+ struct instruction *insn;
+ unsigned long dest_off;
++ struct symbol *dest;
+ struct reloc *reloc;
+
+ for_each_insn(file, insn) {
+@@ -977,7 +1033,9 @@ static int add_call_destinations(struct objtool_file *file)
+ reloc = insn_reloc(file, insn);
+ if (!reloc) {
+ dest_off = arch_jump_destination(insn);
+- insn->call_dest = find_call_destination(insn->sec, dest_off);
++ dest = find_call_destination(insn->sec, dest_off);
++
++ add_call_dest(file, insn, dest, false);
+
+ if (insn->ignore)
+ continue;
+@@ -995,9 +1053,8 @@ static int add_call_destinations(struct objtool_file *file)
+
+ } else if (reloc->sym->type == STT_SECTION) {
+ dest_off = arch_dest_reloc_offset(reloc->addend);
+- insn->call_dest = find_call_destination(reloc->sym->sec,
+- dest_off);
+- if (!insn->call_dest) {
++ dest = find_call_destination(reloc->sym->sec, dest_off);
++ if (!dest) {
+ WARN_FUNC("can't find call dest symbol at %s+0x%lx",
+ insn->sec, insn->offset,
+ reloc->sym->sec->name,
+@@ -1005,6 +1062,8 @@ static int add_call_destinations(struct objtool_file *file)
+ return -1;
+ }
+
++ add_call_dest(file, insn, dest, false);
++
+ } else if (arch_is_retpoline(reloc->sym)) {
+ /*
+ * Retpoline calls are really dynamic calls in
+@@ -1020,55 +1079,7 @@ static int add_call_destinations(struct objtool_file *file)
+ continue;
+
+ } else
+- insn->call_dest = reloc->sym;
+-
+- if (insn->call_dest && insn->call_dest->static_call_tramp) {
+- list_add_tail(&insn->call_node,
+- &file->static_call_list);
+- }
+-
+- /*
+- * Many compilers cannot disable KCOV with a function attribute
+- * so they need a little help, NOP out any KCOV calls from noinstr
+- * text.
+- */
+- if (insn->sec->noinstr &&
+- !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+- if (reloc) {
+- reloc->type = R_NONE;
+- elf_write_reloc(file->elf, reloc);
+- }
+-
+- elf_write_insn(file->elf, insn->sec,
+- insn->offset, insn->len,
+- arch_nop_insn(insn->len));
+- insn->type = INSN_NOP;
+- }
+-
+- if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
+- if (reloc) {
+- reloc->type = R_NONE;
+- elf_write_reloc(file->elf, reloc);
+- }
+-
+- elf_write_insn(file->elf, insn->sec,
+- insn->offset, insn->len,
+- arch_nop_insn(insn->len));
+-
+- insn->type = INSN_NOP;
+-
+- list_add_tail(&insn->mcount_loc_node,
+- &file->mcount_loc_list);
+- }
+-
+- /*
+- * Whatever stack impact regular CALLs have, should be undone
+- * by the RETURN of the called function.
+- *
+- * Annotated intra-function calls retain the stack_ops but
+- * are converted to JUMP, see read_intra_function_calls().
+- */
+- remove_insn_ops(insn);
++ add_call_dest(file, insn, reloc->sym, false);
+ }
+
+ return 0;
+diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
+index 062bb6e9b8658..478e054fcdf71 100644
+--- a/tools/objtool/include/objtool/arch.h
++++ b/tools/objtool/include/objtool/arch.h
+@@ -82,6 +82,7 @@ unsigned long arch_jump_destination(struct instruction *insn);
+ unsigned long arch_dest_reloc_offset(int addend);
+
+ const char *arch_nop_insn(int len);
++const char *arch_ret_insn(int len);
+
+ int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);
+
+diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
+index 14e3e8d702a02..3c077f61d676d 100644
+--- a/tools/perf/Makefile.config
++++ b/tools/perf/Makefile.config
+@@ -271,8 +271,6 @@ endif
+
+ FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
+ FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
+-FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
+-FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
+
+ FEATURE_CHECK_LDFLAGS-libaio = -lrt
+
+diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
+index 5d1fe9c35807a..137890f78e17a 100644
+--- a/tools/perf/bench/futex-lock-pi.c
++++ b/tools/perf/bench/futex-lock-pi.c
+@@ -233,6 +233,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
+ print_summary();
+
+ free(worker);
++ perf_cpu_map__put(cpu);
+ return ret;
+ err:
+ usage_with_options(bench_futex_lock_pi_usage, options);
+diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
+index 97fe31fd3a236..f7a5ffebb9408 100644
+--- a/tools/perf/bench/futex-requeue.c
++++ b/tools/perf/bench/futex-requeue.c
+@@ -294,6 +294,7 @@ int bench_futex_requeue(int argc, const char **argv)
+ print_summary();
+
+ free(worker);
++ perf_cpu_map__put(cpu);
+ return ret;
+ err:
+ usage_with_options(bench_futex_requeue_usage, options);
+diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
+index e970e6b9ad535..0983f40b4b408 100644
+--- a/tools/perf/bench/futex-wake-parallel.c
++++ b/tools/perf/bench/futex-wake-parallel.c
+@@ -329,6 +329,7 @@ int bench_futex_wake_parallel(int argc, const char **argv)
+ print_summary();
+
+ free(blocked_worker);
++ perf_cpu_map__put(cpu);
+ return ret;
+ }
+ #endif /* HAVE_PTHREAD_BARRIER */
+diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
+index 77f058a477903..2226a475e782b 100644
+--- a/tools/perf/bench/futex-wake.c
++++ b/tools/perf/bench/futex-wake.c
+@@ -222,5 +222,6 @@ int bench_futex_wake(int argc, const char **argv)
+ print_summary();
+
+ free(worker);
++ perf_cpu_map__put(cpu);
+ return ret;
+ }
+diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
+index 6ad191e731fc9..50c2e6892b3e9 100644
+--- a/tools/perf/builtin-inject.c
++++ b/tools/perf/builtin-inject.c
+@@ -755,12 +755,16 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
+ return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
+ }
+
++static int output_fd(struct perf_inject *inject)
++{
++ return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
++}
++
+ static int __cmd_inject(struct perf_inject *inject)
+ {
+ int ret = -EINVAL;
+ struct perf_session *session = inject->session;
+- struct perf_data *data_out = &inject->output;
+- int fd = inject->in_place_update ? -1 : perf_data__fd(data_out);
++ int fd = output_fd(inject);
+ u64 output_data_offset;
+
+ signal(SIGINT, sig_handler);
+@@ -819,7 +823,7 @@ static int __cmd_inject(struct perf_inject *inject)
+ inject->tool.ordered_events = true;
+ inject->tool.ordering_requires_timestamps = true;
+ /* Allow space in the header for new attributes */
+- output_data_offset = 4096;
++ output_data_offset = roundup(8192 + session->header.data_offset, 4096);
+ if (inject->strip)
+ strip_init(inject);
+ }
+@@ -1006,7 +1010,7 @@ int cmd_inject(int argc, const char **argv)
+ }
+
+ inject.session = __perf_session__new(&data, repipe,
+- perf_data__fd(&inject.output),
++ output_fd(&inject),
+ &inject.tool);
+ if (IS_ERR(inject.session)) {
+ ret = PTR_ERR(inject.session);
+@@ -1069,7 +1073,8 @@ out_delete:
+ zstd_fini(&(inject.session->zstd_data));
+ perf_session__delete(inject.session);
+ out_close_output:
+- perf_data__close(&inject.output);
++ if (!inject.in_place_update)
++ perf_data__close(&inject.output);
+ free(inject.itrace_synth_opts.vm_tm_corr_args);
+ return ret;
+ }
+diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
+index a0316ce910db6..997e0a4b0902a 100644
+--- a/tools/perf/builtin-report.c
++++ b/tools/perf/builtin-report.c
+@@ -619,14 +619,17 @@ static int report__browse_hists(struct report *rep)
+ int ret;
+ struct perf_session *session = rep->session;
+ struct evlist *evlist = session->evlist;
+- const char *help = perf_tip(system_path(TIPDIR));
++ char *help = NULL, *path = NULL;
+
+- if (help == NULL) {
++ path = system_path(TIPDIR);
++ if (perf_tip(&help, path) || help == NULL) {
+ /* fallback for people who don't install perf ;-) */
+- help = perf_tip(DOCDIR);
+- if (help == NULL)
+- help = "Cannot load tips.txt file, please install perf!";
++ free(path);
++ path = system_path(DOCDIR);
++ if (perf_tip(&help, path) || help == NULL)
++ help = strdup("Cannot load tips.txt file, please install perf!");
+ }
++ free(path);
+
+ switch (use_browser) {
+ case 1:
+@@ -651,7 +654,7 @@ static int report__browse_hists(struct report *rep)
+ ret = evlist__tty_browse_hists(evlist, rep, help);
+ break;
+ }
+-
++ free(help);
+ return ret;
+ }
+
+diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh
+index 8a168cf8bacca..49bd875d51227 100755
+--- a/tools/perf/tests/shell/record+zstd_comp_decomp.sh
++++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh
+@@ -12,7 +12,7 @@ skip_if_no_z_record() {
+
+ collect_z_record() {
+ echo "Collecting compressed record file:"
+- [[ "$(uname -m)" != s390x ]] && gflag='-g'
++ [ "$(uname -m)" != s390x ] && gflag='-g'
+ $perf_tool record -o $trace_file $gflag -z -F 5000 -- \
+ dd count=500 if=/dev/urandom of=/dev/null
+ }
+diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
+index c1f24d0048527..5075ecead5f3d 100644
+--- a/tools/perf/ui/hist.c
++++ b/tools/perf/ui/hist.c
+@@ -535,6 +535,18 @@ struct perf_hpp_list perf_hpp_list = {
+ #undef __HPP_SORT_ACC_FN
+ #undef __HPP_SORT_RAW_FN
+
++static void fmt_free(struct perf_hpp_fmt *fmt)
++{
++ /*
++ * At this point fmt should be completely
++ * unhooked, if not it's a bug.
++ */
++ BUG_ON(!list_empty(&fmt->list));
++ BUG_ON(!list_empty(&fmt->sort_list));
++
++ if (fmt->free)
++ fmt->free(fmt);
++}
+
+ void perf_hpp__init(void)
+ {
+@@ -598,9 +610,10 @@ void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,
+ list_add(&format->sort_list, &list->sorts);
+ }
+
+-void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
++static void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
+ {
+ list_del_init(&format->list);
++ fmt_free(format);
+ }
+
+ void perf_hpp__cancel_cumulate(void)
+@@ -672,19 +685,6 @@ next:
+ }
+
+
+-static void fmt_free(struct perf_hpp_fmt *fmt)
+-{
+- /*
+- * At this point fmt should be completely
+- * unhooked, if not it's a bug.
+- */
+- BUG_ON(!list_empty(&fmt->list));
+- BUG_ON(!list_empty(&fmt->sort_list));
+-
+- if (fmt->free)
+- fmt->free(fmt);
+-}
+-
+ void perf_hpp__reset_output_field(struct perf_hpp_list *list)
+ {
+ struct perf_hpp_fmt *fmt, *tmp;
+diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
+index 58b7069c5a5f8..7054f23150e1b 100644
+--- a/tools/perf/util/arm-spe.c
++++ b/tools/perf/util/arm-spe.c
+@@ -51,6 +51,7 @@ struct arm_spe {
+ u8 timeless_decoding;
+ u8 data_queued;
+
++ u64 sample_type;
+ u8 sample_flc;
+ u8 sample_llc;
+ u8 sample_tlb;
+@@ -248,6 +249,12 @@ static void arm_spe_prep_sample(struct arm_spe *spe,
+ event->sample.header.size = sizeof(struct perf_event_header);
+ }
+
++static int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type)
++{
++ event->header.size = perf_event__sample_event_size(sample, type, 0);
++ return perf_event__synthesize_sample(event, type, 0, sample);
++}
++
+ static inline int
+ arm_spe_deliver_synth_event(struct arm_spe *spe,
+ struct arm_spe_queue *speq __maybe_unused,
+@@ -256,6 +263,12 @@ arm_spe_deliver_synth_event(struct arm_spe *spe,
+ {
+ int ret;
+
++ if (spe->synth_opts.inject) {
++ ret = arm_spe__inject_event(event, sample, spe->sample_type);
++ if (ret)
++ return ret;
++ }
++
+ ret = perf_session__deliver_synth_event(spe->session, event, sample);
+ if (ret)
+ pr_err("ARM SPE: failed to deliver event, error %d\n", ret);
+@@ -920,6 +933,8 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session)
+ else
+ attr.sample_type |= PERF_SAMPLE_TIME;
+
++ spe->sample_type = attr.sample_type;
++
+ attr.exclude_user = evsel->core.attr.exclude_user;
+ attr.exclude_kernel = evsel->core.attr.exclude_kernel;
+ attr.exclude_hv = evsel->core.attr.exclude_hv;
+diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
+index 1a7112a87736a..16ad0e6e9e9c5 100644
+--- a/tools/perf/util/bpf-event.c
++++ b/tools/perf/util/bpf-event.c
+@@ -120,7 +120,11 @@ static int perf_env__fetch_btf(struct perf_env *env,
+ node->data_size = data_size;
+ memcpy(node->data, data, data_size);
+
+- perf_env__insert_btf(env, node);
++ if (!perf_env__insert_btf(env, node)) {
++ /* Insertion failed because of a duplicate. */
++ free(node);
++ return -1;
++ }
+ return 0;
+ }
+
+@@ -576,7 +580,7 @@ void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
+ synthesize_bpf_prog_name(name, KSYM_NAME_LEN, info, btf, 0);
+ fprintf(fp, "# bpf_prog_info %u: %s addr 0x%llx size %u\n",
+ info->id, name, prog_addrs[0], prog_lens[0]);
+- return;
++ goto out;
+ }
+
+ fprintf(fp, "# bpf_prog_info %u:\n", info->id);
+@@ -586,4 +590,6 @@ void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
+ fprintf(fp, "# \tsub_prog %u: %s addr 0x%llx size %u\n",
+ i, name, prog_addrs[i], prog_lens[i]);
+ }
++out:
++ btf__free(btf);
+ }
+diff --git a/tools/perf/util/bpf_skel/bperf.h b/tools/perf/util/bpf_skel/bperf.h
+deleted file mode 100644
+index 186a5551ddb9d..0000000000000
+--- a/tools/perf/util/bpf_skel/bperf.h
++++ /dev/null
+@@ -1,14 +0,0 @@
+-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+-// Copyright (c) 2021 Facebook
+-
+-#ifndef __BPERF_STAT_H
+-#define __BPERF_STAT_H
+-
+-typedef struct {
+- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+- __uint(key_size, sizeof(__u32));
+- __uint(value_size, sizeof(struct bpf_perf_event_value));
+- __uint(max_entries, 1);
+-} reading_map;
+-
+-#endif /* __BPERF_STAT_H */
+diff --git a/tools/perf/util/bpf_skel/bperf_follower.bpf.c b/tools/perf/util/bpf_skel/bperf_follower.bpf.c
+index b8fa3cb2da230..6d2ea67b161ac 100644
+--- a/tools/perf/util/bpf_skel/bperf_follower.bpf.c
++++ b/tools/perf/util/bpf_skel/bperf_follower.bpf.c
+@@ -4,11 +4,21 @@
+ #include <linux/perf_event.h>
+ #include <bpf/bpf_helpers.h>
+ #include <bpf/bpf_tracing.h>
+-#include "bperf.h"
+ #include "bperf_u.h"
+
+-reading_map diff_readings SEC(".maps");
+-reading_map accum_readings SEC(".maps");
++struct {
++ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
++ __uint(key_size, sizeof(__u32));
++ __uint(value_size, sizeof(struct bpf_perf_event_value));
++ __uint(max_entries, 1);
++} diff_readings SEC(".maps");
++
++struct {
++ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
++ __uint(key_size, sizeof(__u32));
++ __uint(value_size, sizeof(struct bpf_perf_event_value));
++ __uint(max_entries, 1);
++} accum_readings SEC(".maps");
+
+ struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+diff --git a/tools/perf/util/bpf_skel/bperf_leader.bpf.c b/tools/perf/util/bpf_skel/bperf_leader.bpf.c
+index 4f70d1459e86c..d82e1633a2e0a 100644
+--- a/tools/perf/util/bpf_skel/bperf_leader.bpf.c
++++ b/tools/perf/util/bpf_skel/bperf_leader.bpf.c
+@@ -4,7 +4,6 @@
+ #include <linux/perf_event.h>
+ #include <bpf/bpf_helpers.h>
+ #include <bpf/bpf_tracing.h>
+-#include "bperf.h"
+
+ struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+@@ -13,8 +12,19 @@ struct {
+ __uint(map_flags, BPF_F_PRESERVE_ELEMS);
+ } events SEC(".maps");
+
+-reading_map prev_readings SEC(".maps");
+-reading_map diff_readings SEC(".maps");
++struct {
++ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
++ __uint(key_size, sizeof(__u32));
++ __uint(value_size, sizeof(struct bpf_perf_event_value));
++ __uint(max_entries, 1);
++} prev_readings SEC(".maps");
++
++struct {
++ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
++ __uint(key_size, sizeof(__u32));
++ __uint(value_size, sizeof(struct bpf_perf_event_value));
++ __uint(max_entries, 1);
++} diff_readings SEC(".maps");
+
+ SEC("raw_tp/sched_switch")
+ int BPF_PROG(on_switch)
+diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
+index cf773f0dec384..5b24eb010336c 100644
+--- a/tools/perf/util/env.c
++++ b/tools/perf/util/env.c
+@@ -74,12 +74,13 @@ out:
+ return node;
+ }
+
+-void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
++bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
+ {
+ struct rb_node *parent = NULL;
+ __u32 btf_id = btf_node->id;
+ struct btf_node *node;
+ struct rb_node **p;
++ bool ret = true;
+
+ down_write(&env->bpf_progs.lock);
+ p = &env->bpf_progs.btfs.rb_node;
+@@ -93,6 +94,7 @@ void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
+ p = &(*p)->rb_right;
+ } else {
+ pr_debug("duplicated btf %u\n", btf_id);
++ ret = false;
+ goto out;
+ }
+ }
+@@ -102,6 +104,7 @@ void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
+ env->bpf_progs.btfs_cnt++;
+ out:
+ up_write(&env->bpf_progs.lock);
++ return ret;
+ }
+
+ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
+diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
+index 1383876f72b37..163e5ec503a26 100644
+--- a/tools/perf/util/env.h
++++ b/tools/perf/util/env.h
+@@ -167,7 +167,7 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env,
+ struct bpf_prog_info_node *info_node);
+ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
+ __u32 prog_id);
+-void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
++bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
+ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
+
+ int perf_env__numa_node(struct perf_env *env, int cpu);
+diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
+index 65fe65ba03c25..b776465e04ef3 100644
+--- a/tools/perf/util/hist.c
++++ b/tools/perf/util/hist.c
+@@ -289,15 +289,10 @@ static long hist_time(unsigned long htime)
+ return htime;
+ }
+
+-static void he_stat__add_period(struct he_stat *he_stat, u64 period,
+- u64 weight, u64 ins_lat, u64 p_stage_cyc)
++static void he_stat__add_period(struct he_stat *he_stat, u64 period)
+ {
+-
+ he_stat->period += period;
+- he_stat->weight += weight;
+ he_stat->nr_events += 1;
+- he_stat->ins_lat += ins_lat;
+- he_stat->p_stage_cyc += p_stage_cyc;
+ }
+
+ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
+@@ -308,9 +303,6 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
+ dest->period_guest_sys += src->period_guest_sys;
+ dest->period_guest_us += src->period_guest_us;
+ dest->nr_events += src->nr_events;
+- dest->weight += src->weight;
+- dest->ins_lat += src->ins_lat;
+- dest->p_stage_cyc += src->p_stage_cyc;
+ }
+
+ static void he_stat__decay(struct he_stat *he_stat)
+@@ -598,9 +590,6 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
+ struct hist_entry *he;
+ int64_t cmp;
+ u64 period = entry->stat.period;
+- u64 weight = entry->stat.weight;
+- u64 ins_lat = entry->stat.ins_lat;
+- u64 p_stage_cyc = entry->stat.p_stage_cyc;
+ bool leftmost = true;
+
+ p = &hists->entries_in->rb_root.rb_node;
+@@ -619,11 +608,11 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
+
+ if (!cmp) {
+ if (sample_self) {
+- he_stat__add_period(&he->stat, period, weight, ins_lat, p_stage_cyc);
++ he_stat__add_period(&he->stat, period);
+ hist_entry__add_callchain_period(he, period);
+ }
+ if (symbol_conf.cumulate_callchain)
+- he_stat__add_period(he->stat_acc, period, weight, ins_lat, p_stage_cyc);
++ he_stat__add_period(he->stat_acc, period);
+
+ /*
+ * This mem info was allocated from sample__resolve_mem
+@@ -733,9 +722,6 @@ __hists__add_entry(struct hists *hists,
+ .stat = {
+ .nr_events = 1,
+ .period = sample->period,
+- .weight = sample->weight,
+- .ins_lat = sample->ins_lat,
+- .p_stage_cyc = sample->p_stage_cyc,
+ },
+ .parent = sym_parent,
+ .filtered = symbol__parent_filter(sym_parent) | al->filtered,
+@@ -748,6 +734,9 @@ __hists__add_entry(struct hists *hists,
+ .raw_size = sample->raw_size,
+ .ops = ops,
+ .time = hist_time(sample->time),
++ .weight = sample->weight,
++ .ins_lat = sample->ins_lat,
++ .p_stage_cyc = sample->p_stage_cyc,
+ }, *he = hists__findnew_entry(hists, &entry, al, sample_self);
+
+ if (!hists->has_callchains && he && he->callchain_size != 0)
+diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
+index 5343b62476e60..621f35ae1efa5 100644
+--- a/tools/perf/util/hist.h
++++ b/tools/perf/util/hist.h
+@@ -369,7 +369,6 @@ enum {
+ };
+
+ void perf_hpp__init(void);
+-void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
+ void perf_hpp__cancel_cumulate(void);
+ void perf_hpp__setup_output_field(struct perf_hpp_list *list);
+ void perf_hpp__reset_output_field(struct perf_hpp_list *list);
+diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build
+index bc629359826fb..b41c2e9c6f887 100644
+--- a/tools/perf/util/intel-pt-decoder/Build
++++ b/tools/perf/util/intel-pt-decoder/Build
+@@ -18,3 +18,5 @@ CFLAGS_intel-pt-insn-decoder.o += -I$(OUTPUT)util/intel-pt-decoder
+ ifeq ($(CC_NO_CLANG), 1)
+ CFLAGS_intel-pt-insn-decoder.o += -Wno-override-init
+ endif
++
++CFLAGS_intel-pt-insn-decoder.o += -Wno-packed
+diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+index 5ab631702769b..b0034ee4bba50 100644
+--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
++++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+@@ -1204,61 +1204,69 @@ out_no_progress:
+
+ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
+ {
++ enum intel_pt_sample_type type = decoder->state.type;
+ bool ret = false;
+
++ decoder->state.type &= ~INTEL_PT_BRANCH;
++
+ if (decoder->set_fup_tx_flags) {
+ decoder->set_fup_tx_flags = false;
+ decoder->tx_flags = decoder->fup_tx_flags;
+- decoder->state.type = INTEL_PT_TRANSACTION;
++ decoder->state.type |= INTEL_PT_TRANSACTION;
+ if (decoder->fup_tx_flags & INTEL_PT_ABORT_TX)
+ decoder->state.type |= INTEL_PT_BRANCH;
+- decoder->state.from_ip = decoder->ip;
+- decoder->state.to_ip = 0;
+ decoder->state.flags = decoder->fup_tx_flags;
+- return true;
++ ret = true;
+ }
+ if (decoder->set_fup_ptw) {
+ decoder->set_fup_ptw = false;
+- decoder->state.type = INTEL_PT_PTW;
++ decoder->state.type |= INTEL_PT_PTW;
+ decoder->state.flags |= INTEL_PT_FUP_IP;
+- decoder->state.from_ip = decoder->ip;
+- decoder->state.to_ip = 0;
+ decoder->state.ptw_payload = decoder->fup_ptw_payload;
+- return true;
++ ret = true;
+ }
+ if (decoder->set_fup_mwait) {
+ decoder->set_fup_mwait = false;
+- decoder->state.type = INTEL_PT_MWAIT_OP;
+- decoder->state.from_ip = decoder->ip;
+- decoder->state.to_ip = 0;
++ decoder->state.type |= INTEL_PT_MWAIT_OP;
+ decoder->state.mwait_payload = decoder->fup_mwait_payload;
+ ret = true;
+ }
+ if (decoder->set_fup_pwre) {
+ decoder->set_fup_pwre = false;
+ decoder->state.type |= INTEL_PT_PWR_ENTRY;
+- decoder->state.type &= ~INTEL_PT_BRANCH;
+- decoder->state.from_ip = decoder->ip;
+- decoder->state.to_ip = 0;
+ decoder->state.pwre_payload = decoder->fup_pwre_payload;
+ ret = true;
+ }
+ if (decoder->set_fup_exstop) {
+ decoder->set_fup_exstop = false;
+ decoder->state.type |= INTEL_PT_EX_STOP;
+- decoder->state.type &= ~INTEL_PT_BRANCH;
+ decoder->state.flags |= INTEL_PT_FUP_IP;
+- decoder->state.from_ip = decoder->ip;
+- decoder->state.to_ip = 0;
+ ret = true;
+ }
+ if (decoder->set_fup_bep) {
+ decoder->set_fup_bep = false;
+ decoder->state.type |= INTEL_PT_BLK_ITEMS;
+- decoder->state.type &= ~INTEL_PT_BRANCH;
++ ret = true;
++ }
++ if (decoder->overflow) {
++ decoder->overflow = false;
++ if (!ret && !decoder->pge) {
++ if (decoder->hop) {
++ decoder->state.type = 0;
++ decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
++ }
++ decoder->pge = true;
++ decoder->state.type |= INTEL_PT_BRANCH | INTEL_PT_TRACE_BEGIN;
++ decoder->state.from_ip = 0;
++ decoder->state.to_ip = decoder->ip;
++ return true;
++ }
++ }
++ if (ret) {
+ decoder->state.from_ip = decoder->ip;
+ decoder->state.to_ip = 0;
+- ret = true;
++ } else {
++ decoder->state.type = type;
+ }
+ return ret;
+ }
+@@ -1607,7 +1615,16 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder)
+ intel_pt_clear_tx_flags(decoder);
+ intel_pt_set_nr(decoder);
+ decoder->timestamp_insn_cnt = 0;
+- decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
++ decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
++ decoder->state.from_ip = decoder->ip;
++ decoder->ip = 0;
++ decoder->pge = false;
++ decoder->set_fup_tx_flags = false;
++ decoder->set_fup_ptw = false;
++ decoder->set_fup_mwait = false;
++ decoder->set_fup_pwre = false;
++ decoder->set_fup_exstop = false;
++ decoder->set_fup_bep = false;
+ decoder->overflow = true;
+ return -EOVERFLOW;
+ }
+@@ -2665,6 +2682,8 @@ static int intel_pt_scan_for_psb(struct intel_pt_decoder *decoder);
+ /* Hop mode: Ignore TNT, do not walk code, but get ip from FUPs and TIPs */
+ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, int *err)
+ {
++ *err = 0;
++
+ /* Leap from PSB to PSB, getting ip from FUP within PSB+ */
+ if (decoder->leap && !decoder->in_psb && decoder->packet.type != INTEL_PT_PSB) {
+ *err = intel_pt_scan_for_psb(decoder);
+@@ -2677,6 +2696,7 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
+ return HOP_IGNORE;
+
+ case INTEL_PT_TIP_PGD:
++ decoder->pge = false;
+ if (!decoder->packet.count) {
+ intel_pt_set_nr(decoder);
+ return HOP_IGNORE;
+@@ -2704,18 +2724,21 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
+ if (!decoder->packet.count)
+ return HOP_IGNORE;
+ intel_pt_set_ip(decoder);
+- if (intel_pt_fup_event(decoder))
+- return HOP_RETURN;
+- if (!decoder->branch_enable)
++ if (decoder->set_fup_mwait || decoder->set_fup_pwre)
++ *no_tip = true;
++ if (!decoder->branch_enable || !decoder->pge)
+ *no_tip = true;
+ if (*no_tip) {
+ decoder->state.type = INTEL_PT_INSTRUCTION;
+ decoder->state.from_ip = decoder->ip;
+ decoder->state.to_ip = 0;
++ intel_pt_fup_event(decoder);
+ return HOP_RETURN;
+ }
++ intel_pt_fup_event(decoder);
++ decoder->state.type |= INTEL_PT_INSTRUCTION | INTEL_PT_BRANCH;
+ *err = intel_pt_walk_fup_tip(decoder);
+- if (!*err)
++ if (!*err && decoder->state.to_ip)
+ decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
+ return HOP_RETURN;
+
+@@ -2896,7 +2919,7 @@ static bool intel_pt_psb_with_fup(struct intel_pt_decoder *decoder, int *err)
+ {
+ struct intel_pt_psb_info data = { .fup = false };
+
+- if (!decoder->branch_enable || !decoder->pge)
++ if (!decoder->branch_enable)
+ return false;
+
+ intel_pt_pkt_lookahead(decoder, intel_pt_psb_lookahead_cb, &data);
+@@ -2923,6 +2946,7 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
+ if (err)
+ return err;
+ next:
++ err = 0;
+ if (decoder->cyc_threshold) {
+ if (decoder->sample_cyc && last_packet_type != INTEL_PT_CYC)
+ decoder->sample_cyc = false;
+@@ -2961,6 +2985,7 @@ next:
+
+ case INTEL_PT_TIP_PGE: {
+ decoder->pge = true;
++ decoder->overflow = false;
+ intel_pt_mtc_cyc_cnt_pge(decoder);
+ intel_pt_set_nr(decoder);
+ if (decoder->packet.count == 0) {
+@@ -2998,7 +3023,7 @@ next:
+ break;
+ }
+ intel_pt_set_last_ip(decoder);
+- if (!decoder->branch_enable) {
++ if (!decoder->branch_enable || !decoder->pge) {
+ decoder->ip = decoder->last_ip;
+ if (intel_pt_fup_event(decoder))
+ return 0;
+@@ -3466,10 +3491,10 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
+ decoder->set_fup_pwre = false;
+ decoder->set_fup_exstop = false;
+ decoder->set_fup_bep = false;
++ decoder->overflow = false;
+
+ if (!decoder->branch_enable) {
+ decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+- decoder->overflow = false;
+ decoder->state.type = 0; /* Do not have a sample */
+ return 0;
+ }
+@@ -3484,7 +3509,6 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
+ decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
+ else
+ decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+- decoder->overflow = false;
+
+ decoder->state.from_ip = 0;
+ decoder->state.to_ip = decoder->ip;
+@@ -3606,7 +3630,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder)
+ }
+
+ decoder->have_last_ip = true;
+- decoder->pkt_state = INTEL_PT_STATE_NO_IP;
++ decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+
+ err = intel_pt_walk_psb(decoder);
+ if (err)
+@@ -3703,7 +3727,8 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
+
+ if (err) {
+ decoder->state.err = intel_pt_ext_err(err);
+- decoder->state.from_ip = decoder->ip;
++ if (err != -EOVERFLOW)
++ decoder->state.from_ip = decoder->ip;
+ intel_pt_update_sample_time(decoder);
+ decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt;
+ intel_pt_set_nr(decoder);
+diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
+index 6f852b305e92b..824bceb063bfe 100644
+--- a/tools/perf/util/intel-pt.c
++++ b/tools/perf/util/intel-pt.c
+@@ -2510,6 +2510,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
+ ptq->sync_switch = false;
+ intel_pt_next_tid(pt, ptq);
+ }
++ ptq->timestamp = state->est_timestamp;
+ if (pt->synth_opts.errors) {
+ err = intel_ptq_synth_error(ptq, state);
+ if (err)
+diff --git a/tools/perf/util/smt.c b/tools/perf/util/smt.c
+index 20bacd5972ade..34f1b1b1176c7 100644
+--- a/tools/perf/util/smt.c
++++ b/tools/perf/util/smt.c
+@@ -15,7 +15,7 @@ int smt_on(void)
+ if (cached)
+ return cached_result;
+
+- if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) > 0)
++ if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0)
+ goto done;
+
+ ncpu = sysconf(_SC_NPROCESSORS_CONF);
+diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
+index 568a88c001c6c..a111065b484ef 100644
+--- a/tools/perf/util/sort.c
++++ b/tools/perf/util/sort.c
+@@ -1325,88 +1325,68 @@ struct sort_entry sort_mispredict = {
+ .se_width_idx = HISTC_MISPREDICT,
+ };
+
+-static u64 he_weight(struct hist_entry *he)
+-{
+- return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
+-}
+-
+ static int64_t
+-sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
++sort__weight_cmp(struct hist_entry *left, struct hist_entry *right)
+ {
+- return he_weight(left) - he_weight(right);
++ return left->weight - right->weight;
+ }
+
+ static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+- return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
++ return repsep_snprintf(bf, size, "%-*llu", width, he->weight);
+ }
+
+ struct sort_entry sort_local_weight = {
+ .se_header = "Local Weight",
+- .se_cmp = sort__local_weight_cmp,
++ .se_cmp = sort__weight_cmp,
+ .se_snprintf = hist_entry__local_weight_snprintf,
+ .se_width_idx = HISTC_LOCAL_WEIGHT,
+ };
+
+-static int64_t
+-sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
+-{
+- return left->stat.weight - right->stat.weight;
+-}
+-
+ static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+- return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
++ return repsep_snprintf(bf, size, "%-*llu", width,
++ he->weight * he->stat.nr_events);
+ }
+
+ struct sort_entry sort_global_weight = {
+ .se_header = "Weight",
+- .se_cmp = sort__global_weight_cmp,
++ .se_cmp = sort__weight_cmp,
+ .se_snprintf = hist_entry__global_weight_snprintf,
+ .se_width_idx = HISTC_GLOBAL_WEIGHT,
+ };
+
+-static u64 he_ins_lat(struct hist_entry *he)
+-{
+- return he->stat.nr_events ? he->stat.ins_lat / he->stat.nr_events : 0;
+-}
+-
+ static int64_t
+-sort__local_ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
++sort__ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
+ {
+- return he_ins_lat(left) - he_ins_lat(right);
++ return left->ins_lat - right->ins_lat;
+ }
+
+ static int hist_entry__local_ins_lat_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+- return repsep_snprintf(bf, size, "%-*u", width, he_ins_lat(he));
++ return repsep_snprintf(bf, size, "%-*u", width, he->ins_lat);
+ }
+
+ struct sort_entry sort_local_ins_lat = {
+ .se_header = "Local INSTR Latency",
+- .se_cmp = sort__local_ins_lat_cmp,
++ .se_cmp = sort__ins_lat_cmp,
+ .se_snprintf = hist_entry__local_ins_lat_snprintf,
+ .se_width_idx = HISTC_LOCAL_INS_LAT,
+ };
+
+-static int64_t
+-sort__global_ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
+-{
+- return left->stat.ins_lat - right->stat.ins_lat;
+-}
+-
+ static int hist_entry__global_ins_lat_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+- return repsep_snprintf(bf, size, "%-*u", width, he->stat.ins_lat);
++ return repsep_snprintf(bf, size, "%-*u", width,
++ he->ins_lat * he->stat.nr_events);
+ }
+
+ struct sort_entry sort_global_ins_lat = {
+ .se_header = "INSTR Latency",
+- .se_cmp = sort__global_ins_lat_cmp,
++ .se_cmp = sort__ins_lat_cmp,
+ .se_snprintf = hist_entry__global_ins_lat_snprintf,
+ .se_width_idx = HISTC_GLOBAL_INS_LAT,
+ };
+@@ -1414,13 +1394,13 @@ struct sort_entry sort_global_ins_lat = {
+ static int64_t
+ sort__global_p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
+ {
+- return left->stat.p_stage_cyc - right->stat.p_stage_cyc;
++ return left->p_stage_cyc - right->p_stage_cyc;
+ }
+
+ static int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+ {
+- return repsep_snprintf(bf, size, "%-*u", width, he->stat.p_stage_cyc);
++ return repsep_snprintf(bf, size, "%-*u", width, he->p_stage_cyc);
+ }
+
+ struct sort_entry sort_p_stage_cyc = {
+diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
+index b67c469aba795..7b7145501933f 100644
+--- a/tools/perf/util/sort.h
++++ b/tools/perf/util/sort.h
+@@ -49,9 +49,6 @@ struct he_stat {
+ u64 period_us;
+ u64 period_guest_sys;
+ u64 period_guest_us;
+- u64 weight;
+- u64 ins_lat;
+- u64 p_stage_cyc;
+ u32 nr_events;
+ };
+
+@@ -109,6 +106,9 @@ struct hist_entry {
+ s32 socket;
+ s32 cpu;
+ u64 code_page_size;
++ u64 weight;
++ u64 ins_lat;
++ u64 p_stage_cyc;
+ u8 cpumode;
+ u8 depth;
+
+diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
+index 37a9492edb3eb..df3c4671be72a 100644
+--- a/tools/perf/util/util.c
++++ b/tools/perf/util/util.c
+@@ -379,32 +379,32 @@ fetch_kernel_version(unsigned int *puint, char *str,
+ return 0;
+ }
+
+-const char *perf_tip(const char *dirpath)
++int perf_tip(char **strp, const char *dirpath)
+ {
+ struct strlist *tips;
+ struct str_node *node;
+- char *tip = NULL;
+ struct strlist_config conf = {
+ .dirname = dirpath,
+ .file_only = true,
+ };
++ int ret = 0;
+
++ *strp = NULL;
+ tips = strlist__new("tips.txt", &conf);
+ if (tips == NULL)
+- return errno == ENOENT ? NULL :
+- "Tip: check path of tips.txt or get more memory! ;-p";
++ return -errno;
+
+ if (strlist__nr_entries(tips) == 0)
+ goto out;
+
+ node = strlist__entry(tips, random() % strlist__nr_entries(tips));
+- if (asprintf(&tip, "Tip: %s", node->s) < 0)
+- tip = (char *)"Tip: get more memory! ;-)";
++ if (asprintf(strp, "Tip: %s", node->s) < 0)
++ ret = -ENOMEM;
+
+ out:
+ strlist__delete(tips);
+
+- return tip;
++ return ret;
+ }
+
+ char *perf_exe(char *buf, int len)
+diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
+index ad737052e5977..9f0d36ba77f2d 100644
+--- a/tools/perf/util/util.h
++++ b/tools/perf/util/util.h
+@@ -39,7 +39,7 @@ int fetch_kernel_version(unsigned int *puint,
+ #define KVER_FMT "%d.%d.%d"
+ #define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
+
+-const char *perf_tip(const char *dirpath);
++int perf_tip(char **strp, const char *dirpath);
+
+ #ifndef HAVE_SCHED_GETCPU_SUPPORT
+ int sched_getcpu(void);
+diff --git a/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c b/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
+index 762f6a9da8b5e..664ffc0364f4f 100644
+--- a/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
++++ b/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
+@@ -90,7 +90,7 @@ static void print_err_line(void)
+
+ static void test_conn(void)
+ {
+- int listen_fd = -1, cli_fd = -1, err;
++ int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
+ socklen_t addrlen = sizeof(srv_sa6);
+ int srv_port;
+
+@@ -112,6 +112,10 @@ static void test_conn(void)
+ if (CHECK_FAIL(cli_fd == -1))
+ goto done;
+
++ srv_fd = accept(listen_fd, NULL, NULL);
++ if (CHECK_FAIL(srv_fd == -1))
++ goto done;
++
+ if (CHECK(skel->bss->listen_tp_sport != srv_port ||
+ skel->bss->req_sk_sport != srv_port,
+ "Unexpected sk src port",
+@@ -134,11 +138,13 @@ done:
+ close(listen_fd);
+ if (cli_fd != -1)
+ close(cli_fd);
++ if (srv_fd != -1)
++ close(srv_fd);
+ }
+
+ static void test_syncookie(void)
+ {
+- int listen_fd = -1, cli_fd = -1, err;
++ int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
+ socklen_t addrlen = sizeof(srv_sa6);
+ int srv_port;
+
+@@ -161,6 +167,10 @@ static void test_syncookie(void)
+ if (CHECK_FAIL(cli_fd == -1))
+ goto done;
+
++ srv_fd = accept(listen_fd, NULL, NULL);
++ if (CHECK_FAIL(srv_fd == -1))
++ goto done;
++
+ if (CHECK(skel->bss->listen_tp_sport != srv_port,
+ "Unexpected tp src port",
+ "listen_tp_sport:%u expected:%u\n",
+@@ -188,6 +198,8 @@ done:
+ close(listen_fd);
+ if (cli_fd != -1)
+ close(cli_fd);
++ if (srv_fd != -1)
++ close(srv_fd);
+ }
+
+ struct test {
+diff --git a/tools/testing/selftests/bpf/prog_tests/perf_buffer.c b/tools/testing/selftests/bpf/prog_tests/perf_buffer.c
+index 6490e9673002f..7daaaab13681b 100644
+--- a/tools/testing/selftests/bpf/prog_tests/perf_buffer.c
++++ b/tools/testing/selftests/bpf/prog_tests/perf_buffer.c
+@@ -107,8 +107,8 @@ void test_perf_buffer(void)
+ "expect %d, seen %d\n", nr_on_cpus, CPU_COUNT(&cpu_seen)))
+ goto out_free_pb;
+
+- if (CHECK(perf_buffer__buffer_cnt(pb) != nr_cpus, "buf_cnt",
+- "got %zu, expected %d\n", perf_buffer__buffer_cnt(pb), nr_cpus))
++ if (CHECK(perf_buffer__buffer_cnt(pb) != nr_on_cpus, "buf_cnt",
++ "got %zu, expected %d\n", perf_buffer__buffer_cnt(pb), nr_on_cpus))
+ goto out_close;
+
+ for (i = 0; i < nr_cpus; i++) {
+diff --git a/tools/testing/selftests/bpf/prog_tests/sk_lookup.c b/tools/testing/selftests/bpf/prog_tests/sk_lookup.c
+index aee41547e7f45..6db07401bc493 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sk_lookup.c
++++ b/tools/testing/selftests/bpf/prog_tests/sk_lookup.c
+@@ -598,7 +598,7 @@ close:
+
+ static void run_lookup_prog(const struct test *t)
+ {
+- int server_fds[MAX_SERVERS] = { -1 };
++ int server_fds[] = { [0 ... MAX_SERVERS - 1] = -1 };
+ int client_fd, reuse_conn_fd = -1;
+ struct bpf_link *lookup_link;
+ int i, err;
+@@ -1053,7 +1053,7 @@ static void run_sk_assign(struct test_sk_lookup *skel,
+ struct bpf_program *lookup_prog,
+ const char *remote_ip, const char *local_ip)
+ {
+- int server_fds[MAX_SERVERS] = { -1 };
++ int server_fds[] = { [0 ... MAX_SERVERS - 1] = -1 };
+ struct bpf_sk_lookup ctx;
+ __u64 server_cookie;
+ int i, err;
+diff --git a/tools/testing/selftests/bpf/prog_tests/test_ima.c b/tools/testing/selftests/bpf/prog_tests/test_ima.c
+index 0252f61d611a9..97d8a6f84f4ab 100644
+--- a/tools/testing/selftests/bpf/prog_tests/test_ima.c
++++ b/tools/testing/selftests/bpf/prog_tests/test_ima.c
+@@ -43,7 +43,7 @@ static int process_sample(void *ctx, void *data, size_t len)
+ void test_test_ima(void)
+ {
+ char measured_dir_template[] = "/tmp/ima_measuredXXXXXX";
+- struct ring_buffer *ringbuf;
++ struct ring_buffer *ringbuf = NULL;
+ const char *measured_dir;
+ char cmd[256];
+
+@@ -85,5 +85,6 @@ close_clean:
+ err = system(cmd);
+ CHECK(err, "failed to run command", "%s, errno = %d\n", cmd, errno);
+ close_prog:
++ ring_buffer__free(ringbuf);
+ ima__destroy(skel);
+ }
+diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h
+index 7de534f38c3f1..60c93aee2f4ad 100644
+--- a/tools/testing/selftests/bpf/progs/strobemeta.h
++++ b/tools/testing/selftests/bpf/progs/strobemeta.h
+@@ -358,7 +358,7 @@ static __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg,
+ void *payload)
+ {
+ void *location;
+- uint32_t len;
++ uint64_t len;
+
+ data->str_lens[idx] = 0;
+ location = calc_location(&cfg->str_locs[idx], tls_base);
+@@ -390,7 +390,7 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
+ struct strobe_map_descr* descr = &data->map_descrs[idx];
+ struct strobe_map_raw map;
+ void *location;
+- uint32_t len;
++ uint64_t len;
+ int i;
+
+ descr->tag_len = 0; /* presume no tag is set */
+diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
+index cc1cd240445d2..e3fea6f281e4b 100644
+--- a/tools/testing/selftests/bpf/test_progs.c
++++ b/tools/testing/selftests/bpf/test_progs.c
+@@ -370,7 +370,7 @@ int extract_build_id(char *build_id, size_t size)
+
+ if (getline(&line, &len, fp) == -1)
+ goto err;
+- fclose(fp);
++ pclose(fp);
+
+ if (len > size)
+ len = size;
+@@ -379,7 +379,7 @@ int extract_build_id(char *build_id, size_t size)
+ free(line);
+ return 0;
+ err:
+- fclose(fp);
++ pclose(fp);
+ return -1;
+ }
+
+diff --git a/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh b/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh
+index 1538373157e3c..bedff7aa7023f 100755
+--- a/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh
++++ b/tools/testing/selftests/bpf/test_xdp_redirect_multi.sh
+@@ -2,11 +2,11 @@
+ # SPDX-License-Identifier: GPL-2.0
+ #
+ # Test topology:
+-# - - - - - - - - - - - - - - - - - - - - - - - - -
+-# | veth1 veth2 veth3 | ... init net
++# - - - - - - - - - - - - - - - - - - -
++# | veth1 veth2 veth3 | ns0
+ # - -| - - - - - - | - - - - - - | - -
+ # --------- --------- ---------
+-# | veth0 | | veth0 | | veth0 | ...
++# | veth0 | | veth0 | | veth0 |
+ # --------- --------- ---------
+ # ns1 ns2 ns3
+ #
+@@ -31,6 +31,7 @@ IFACES=""
+ DRV_MODE="xdpgeneric xdpdrv xdpegress"
+ PASS=0
+ FAIL=0
++LOG_DIR=$(mktemp -d)
+
+ test_pass()
+ {
+@@ -50,6 +51,7 @@ clean_up()
+ ip link del veth$i 2> /dev/null
+ ip netns del ns$i 2> /dev/null
+ done
++ ip netns del ns0 2> /dev/null
+ }
+
+ # Kselftest framework requirement - SKIP code is 4.
+@@ -77,10 +79,12 @@ setup_ns()
+ mode="xdpdrv"
+ fi
+
++ ip netns add ns0
+ for i in $(seq $NUM); do
+ ip netns add ns$i
+- ip link add veth$i type veth peer name veth0 netns ns$i
+- ip link set veth$i up
++ ip -n ns$i link add veth0 index 2 type veth \
++ peer name veth$i netns ns0 index $((1 + $i))
++ ip -n ns0 link set veth$i up
+ ip -n ns$i link set veth0 up
+
+ ip -n ns$i addr add 192.0.2.$i/24 dev veth0
+@@ -91,7 +95,7 @@ setup_ns()
+ xdp_dummy.o sec xdp_dummy &> /dev/null || \
+ { test_fail "Unable to load dummy xdp" && exit 1; }
+ IFACES="$IFACES veth$i"
+- veth_mac[$i]=$(ip link show veth$i | awk '/link\/ether/ {print $2}')
++ veth_mac[$i]=$(ip -n ns0 link show veth$i | awk '/link\/ether/ {print $2}')
+ done
+ }
+
+@@ -100,17 +104,17 @@ do_egress_tests()
+ local mode=$1
+
+ # mac test
+- ip netns exec ns2 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-2_${mode}.log &
+- ip netns exec ns3 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-3_${mode}.log &
++ ip netns exec ns2 tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-2_${mode}.log &
++ ip netns exec ns3 tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-3_${mode}.log &
+ sleep 0.5
+ ip netns exec ns1 ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null
+ sleep 0.5
+- pkill -9 tcpdump
++ pkill tcpdump
+
+ # mac check
+- grep -q "${veth_mac[2]} > ff:ff:ff:ff:ff:ff" mac_ns1-2_${mode}.log && \
++ grep -q "${veth_mac[2]} > ff:ff:ff:ff:ff:ff" ${LOG_DIR}/mac_ns1-2_${mode}.log && \
+ test_pass "$mode mac ns1-2" || test_fail "$mode mac ns1-2"
+- grep -q "${veth_mac[3]} > ff:ff:ff:ff:ff:ff" mac_ns1-3_${mode}.log && \
++ grep -q "${veth_mac[3]} > ff:ff:ff:ff:ff:ff" ${LOG_DIR}/mac_ns1-3_${mode}.log && \
+ test_pass "$mode mac ns1-3" || test_fail "$mode mac ns1-3"
+ }
+
+@@ -121,46 +125,46 @@ do_ping_tests()
+ # ping6 test: echo request should be redirect back to itself, not others
+ ip netns exec ns1 ip neigh add 2001:db8::2 dev veth0 lladdr 00:00:00:00:00:02
+
+- ip netns exec ns1 tcpdump -i veth0 -nn -l -e &> ns1-1_${mode}.log &
+- ip netns exec ns2 tcpdump -i veth0 -nn -l -e &> ns1-2_${mode}.log &
+- ip netns exec ns3 tcpdump -i veth0 -nn -l -e &> ns1-3_${mode}.log &
++ ip netns exec ns1 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-1_${mode}.log &
++ ip netns exec ns2 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-2_${mode}.log &
++ ip netns exec ns3 tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-3_${mode}.log &
+ sleep 0.5
+ # ARP test
+- ip netns exec ns1 ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null
++ ip netns exec ns1 arping -q -c 2 -I veth0 192.0.2.254
+ # IPv4 test
+ ip netns exec ns1 ping 192.0.2.253 -i 0.1 -c 4 &> /dev/null
+ # IPv6 test
+ ip netns exec ns1 ping6 2001:db8::2 -i 0.1 -c 2 &> /dev/null
+ sleep 0.5
+- pkill -9 tcpdump
++ pkill tcpdump
+
+ # All netns should receive the redirect arp requests
+- [ $(grep -c "who-has 192.0.2.254" ns1-1_${mode}.log) -gt 4 ] && \
++ [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \
+ test_pass "$mode arp(F_BROADCAST) ns1-1" || \
+ test_fail "$mode arp(F_BROADCAST) ns1-1"
+- [ $(grep -c "who-has 192.0.2.254" ns1-2_${mode}.log) -le 4 ] && \
++ [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-2_${mode}.log) -eq 2 ] && \
+ test_pass "$mode arp(F_BROADCAST) ns1-2" || \
+ test_fail "$mode arp(F_BROADCAST) ns1-2"
+- [ $(grep -c "who-has 192.0.2.254" ns1-3_${mode}.log) -le 4 ] && \
++ [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-3_${mode}.log) -eq 2 ] && \
+ test_pass "$mode arp(F_BROADCAST) ns1-3" || \
+ test_fail "$mode arp(F_BROADCAST) ns1-3"
+
+ # ns1 should not receive the redirect echo request, others should
+- [ $(grep -c "ICMP echo request" ns1-1_${mode}.log) -eq 4 ] && \
++ [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \
+ test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1" || \
+ test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1"
+- [ $(grep -c "ICMP echo request" ns1-2_${mode}.log) -eq 4 ] && \
++ [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-2_${mode}.log) -eq 4 ] && \
+ test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2" || \
+ test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2"
+- [ $(grep -c "ICMP echo request" ns1-3_${mode}.log) -eq 4 ] && \
++ [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-3_${mode}.log) -eq 4 ] && \
+ test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3" || \
+ test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3"
+
+ # ns1 should receive the echo request, ns2 should not
+- [ $(grep -c "ICMP6, echo request" ns1-1_${mode}.log) -eq 4 ] && \
++ [ $(grep -c "ICMP6, echo request" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \
+ test_pass "$mode IPv6 (no flags) ns1-1" || \
+ test_fail "$mode IPv6 (no flags) ns1-1"
+- [ $(grep -c "ICMP6, echo request" ns1-2_${mode}.log) -eq 0 ] && \
++ [ $(grep -c "ICMP6, echo request" ${LOG_DIR}/ns1-2_${mode}.log) -eq 0 ] && \
+ test_pass "$mode IPv6 (no flags) ns1-2" || \
+ test_fail "$mode IPv6 (no flags) ns1-2"
+ }
+@@ -176,9 +180,13 @@ do_tests()
+ xdpgeneric) drv_p="-S";;
+ esac
+
+- ./xdp_redirect_multi $drv_p $IFACES &> xdp_redirect_${mode}.log &
++ ip netns exec ns0 ./xdp_redirect_multi $drv_p $IFACES &> ${LOG_DIR}/xdp_redirect_${mode}.log &
+ xdp_pid=$!
+ sleep 1
++ if ! ps -p $xdp_pid > /dev/null; then
++ test_fail "$mode xdp_redirect_multi start failed"
++ return 1
++ fi
+
+ if [ "$mode" = "xdpegress" ]; then
+ do_egress_tests $mode
+@@ -189,16 +197,16 @@ do_tests()
+ kill $xdp_pid
+ }
+
+-trap clean_up 0 2 3 6 9
++trap clean_up EXIT
+
+ check_env
+-rm -f xdp_redirect_*.log ns*.log mac_ns*.log
+
+ for mode in ${DRV_MODE}; do
+ setup_ns $mode
+ do_tests $mode
+ clean_up
+ done
++rm -rf ${LOG_DIR}
+
+ echo "Summary: PASS $PASS, FAIL $FAIL"
+ [ $FAIL -eq 0 ] && exit 0 || exit 1
+diff --git a/tools/testing/selftests/bpf/verifier/array_access.c b/tools/testing/selftests/bpf/verifier/array_access.c
+index 1b1c798e92489..1b138cd2b187d 100644
+--- a/tools/testing/selftests/bpf/verifier/array_access.c
++++ b/tools/testing/selftests/bpf/verifier/array_access.c
+@@ -186,7 +186,7 @@
+ },
+ .fixup_map_hash_48b = { 3 },
+ .errstr_unpriv = "R0 leaks addr",
+- .errstr = "R0 unbounded memory access",
++ .errstr = "invalid access to map value, value_size=48 off=44 size=8",
+ .result_unpriv = REJECT,
+ .result = REJECT,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+diff --git a/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c b/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c
+index 6e52dfc644153..6fb52d8cfd889 100644
+--- a/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c
++++ b/tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c
+@@ -71,6 +71,8 @@
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
++ .result_unpriv = REJECT,
++ .errstr_unpriv = "R0 leaks addr into mem",
+ },
+ {
+ "Can't use cmpxchg on uninit src reg",
+@@ -118,4 +120,88 @@
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
++ .result_unpriv = REJECT,
++ .errstr_unpriv = "R0 leaks addr into mem",
++},
++{
++ "Dest pointer in r0 - succeed, check 2",
++ .insns = {
++ /* r0 = &val */
++ BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
++ /* val = r0; */
++ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
++ /* r5 = &val */
++ BPF_MOV64_REG(BPF_REG_5, BPF_REG_10),
++ /* r0 = atomic_cmpxchg(&val, r0, r5); */
++ BPF_ATOMIC_OP(BPF_DW, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
++ /* r1 = *r0 */
++ BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8),
++ /* exit(0); */
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .result_unpriv = REJECT,
++ .errstr_unpriv = "R0 leaks addr into mem",
++},
++{
++ "Dest pointer in r0 - succeed, check 3",
++ .insns = {
++ /* r0 = &val */
++ BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
++ /* val = r0; */
++ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
++ /* r5 = &val */
++ BPF_MOV64_REG(BPF_REG_5, BPF_REG_10),
++ /* r0 = atomic_cmpxchg(&val, r0, r5); */
++ BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
++ /* exit(0); */
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = REJECT,
++ .errstr = "invalid size of register fill",
++ .errstr_unpriv = "R0 leaks addr into mem",
++},
++{
++ "Dest pointer in r0 - succeed, check 4",
++ .insns = {
++ /* r0 = &val */
++ BPF_MOV32_REG(BPF_REG_0, BPF_REG_10),
++ /* val = r0; */
++ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -8),
++ /* r5 = &val */
++ BPF_MOV32_REG(BPF_REG_5, BPF_REG_10),
++ /* r0 = atomic_cmpxchg(&val, r0, r5); */
++ BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
++ /* r1 = *r10 */
++ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -8),
++ /* exit(0); */
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .result_unpriv = REJECT,
++ .errstr_unpriv = "R10 partial copy of pointer",
++},
++{
++ "Dest pointer in r0 - succeed, check 5",
++ .insns = {
++ /* r0 = &val */
++ BPF_MOV32_REG(BPF_REG_0, BPF_REG_10),
++ /* val = r0; */
++ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -8),
++ /* r5 = &val */
++ BPF_MOV32_REG(BPF_REG_5, BPF_REG_10),
++ /* r0 = atomic_cmpxchg(&val, r0, r5); */
++ BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
++ /* r1 = *r0 */
++ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -8),
++ /* exit(0); */
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = REJECT,
++ .errstr = "R0 invalid mem access",
++ .errstr_unpriv = "R10 partial copy of pointer",
+ },
+diff --git a/tools/testing/selftests/bpf/verifier/value_ptr_arith.c b/tools/testing/selftests/bpf/verifier/value_ptr_arith.c
+index 2debba4e8a3a8..4d347bc53aa28 100644
+--- a/tools/testing/selftests/bpf/verifier/value_ptr_arith.c
++++ b/tools/testing/selftests/bpf/verifier/value_ptr_arith.c
+@@ -1077,6 +1077,29 @@
+ .errstr = "R0 invalid mem access 'inv'",
+ .errstr_unpriv = "R0 pointer -= pointer prohibited",
+ },
++{
++ "map access: trying to leak tained dst reg",
++ .insns = {
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
++ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
++ BPF_LD_MAP_FD(BPF_REG_1, 0),
++ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
++ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
++ BPF_EXIT_INSN(),
++ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
++ BPF_MOV32_IMM(BPF_REG_1, 0xFFFFFFFF),
++ BPF_MOV32_REG(BPF_REG_1, BPF_REG_1),
++ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
++ BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .fixup_map_array_48b = { 4 },
++ .result = REJECT,
++ .errstr = "math between map_value pointer and 4294967295 is not allowed",
++},
+ {
+ "32bit pkt_ptr -= scalar",
+ .insns = {
+diff --git a/tools/testing/selftests/bpf/verifier/xdp_direct_packet_access.c b/tools/testing/selftests/bpf/verifier/xdp_direct_packet_access.c
+index bfb97383e6b5a..b4ec228eb95d0 100644
+--- a/tools/testing/selftests/bpf/verifier/xdp_direct_packet_access.c
++++ b/tools/testing/selftests/bpf/verifier/xdp_direct_packet_access.c
+@@ -35,7 +35,7 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ },
+ {
+- "XDP pkt read, pkt_data' > pkt_end, good access",
++ "XDP pkt read, pkt_data' > pkt_end, corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+@@ -87,6 +87,41 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_data' > pkt_end, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data' > pkt_end, corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_end > pkt_data', good access",
+ .insns = {
+@@ -106,16 +141,16 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_end > pkt_data', bad access 1",
++ "XDP pkt read, pkt_end > pkt_data', corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct xdp_md, data_end)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -142,6 +177,42 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_end > pkt_data', corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end > pkt_data', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_data' < pkt_end, good access",
+ .insns = {
+@@ -161,16 +232,16 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data' < pkt_end, bad access 1",
++ "XDP pkt read, pkt_data' < pkt_end, corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct xdp_md, data_end)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -198,7 +269,43 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_end < pkt_data', good access",
++ "XDP pkt read, pkt_data' < pkt_end, corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data' < pkt_end, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end < pkt_data', corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+@@ -250,6 +357,41 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_end < pkt_data', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end < pkt_data', corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_data' >= pkt_end, good access",
+ .insns = {
+@@ -268,15 +410,15 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data' >= pkt_end, bad access 1",
++ "XDP pkt read, pkt_data' >= pkt_end, corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct xdp_md, data_end)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -304,7 +446,41 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_end >= pkt_data', good access",
++ "XDP pkt read, pkt_data' >= pkt_end, corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data' >= pkt_end, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end >= pkt_data', corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+@@ -359,7 +535,44 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data' <= pkt_end, good access",
++ "XDP pkt read, pkt_end >= pkt_data', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end >= pkt_data', corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data' <= pkt_end, corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+@@ -413,6 +626,43 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_data' <= pkt_end, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data' <= pkt_end, corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_end <= pkt_data', good access",
+ .insns = {
+@@ -431,15 +681,15 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_end <= pkt_data', bad access 1",
++ "XDP pkt read, pkt_end <= pkt_data', corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+ offsetof(struct xdp_md, data_end)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -467,7 +717,41 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_meta' > pkt_data, good access",
++ "XDP pkt read, pkt_end <= pkt_data', corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_end <= pkt_data', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
++ offsetof(struct xdp_md, data_end)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' > pkt_data, corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+@@ -519,6 +803,41 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_meta' > pkt_data, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' > pkt_data, corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_data > pkt_meta', good access",
+ .insns = {
+@@ -538,16 +857,16 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data > pkt_meta', bad access 1",
++ "XDP pkt read, pkt_data > pkt_meta', corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -574,6 +893,42 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_data > pkt_meta', corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data > pkt_meta', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_meta' < pkt_data, good access",
+ .insns = {
+@@ -593,16 +948,16 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_meta' < pkt_data, bad access 1",
++ "XDP pkt read, pkt_meta' < pkt_data, corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -630,7 +985,43 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data < pkt_meta', good access",
++ "XDP pkt read, pkt_meta' < pkt_data, corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' < pkt_data, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data < pkt_meta', corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+@@ -682,6 +1073,41 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_data < pkt_meta', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data < pkt_meta', corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_meta' >= pkt_data, good access",
+ .insns = {
+@@ -700,15 +1126,15 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_meta' >= pkt_data, bad access 1",
++ "XDP pkt read, pkt_meta' >= pkt_data, corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -736,7 +1162,41 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data >= pkt_meta', good access",
++ "XDP pkt read, pkt_meta' >= pkt_data, corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' >= pkt_data, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data >= pkt_meta', corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+@@ -791,7 +1251,44 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_meta' <= pkt_data, good access",
++ "XDP pkt read, pkt_data >= pkt_meta', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data >= pkt_meta', corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' <= pkt_data, corner case, good access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+@@ -845,6 +1342,43 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_meta' <= pkt_data, corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_meta' <= pkt_data, corner case -1, bad access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
++ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .errstr = "R1 offset is outside of the packet",
++ .result = REJECT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+ {
+ "XDP pkt read, pkt_data <= pkt_meta', good access",
+ .insns = {
+@@ -863,15 +1397,15 @@
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
+ {
+- "XDP pkt read, pkt_data <= pkt_meta', bad access 1",
++ "XDP pkt read, pkt_data <= pkt_meta', corner case -1, bad access",
+ .insns = {
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+ offsetof(struct xdp_md, data_meta)),
+ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+- BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
+ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+- BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+@@ -898,3 +1432,37 @@
+ .prog_type = BPF_PROG_TYPE_XDP,
+ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+ },
++{
++ "XDP pkt read, pkt_data <= pkt_meta', corner case, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
++{
++ "XDP pkt read, pkt_data <= pkt_meta', corner case +1, good access",
++ .insns = {
++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
++ offsetof(struct xdp_md, data_meta)),
++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
++ BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
++ BPF_MOV64_IMM(BPF_REG_0, 0),
++ BPF_EXIT_INSN(),
++ },
++ .result = ACCEPT,
++ .prog_type = BPF_PROG_TYPE_XDP,
++ .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
++},
+diff --git a/tools/testing/selftests/bpf/xdp_redirect_multi.c b/tools/testing/selftests/bpf/xdp_redirect_multi.c
+index 3696a8f32c235..f5ffba341c174 100644
+--- a/tools/testing/selftests/bpf/xdp_redirect_multi.c
++++ b/tools/testing/selftests/bpf/xdp_redirect_multi.c
+@@ -129,7 +129,7 @@ int main(int argc, char **argv)
+ goto err_out;
+ }
+
+- printf("Get interfaces");
++ printf("Get interfaces:");
+ for (i = 0; i < MAX_IFACE_NUM && argv[optind + i]; i++) {
+ ifaces[i] = if_nametoindex(argv[optind + i]);
+ if (!ifaces[i])
+@@ -139,7 +139,7 @@ int main(int argc, char **argv)
+ goto err_out;
+ }
+ if (ifaces[i] > MAX_INDEX_NUM) {
+- printf("Interface index to large\n");
++ printf(" interface index too large\n");
+ goto err_out;
+ }
+ printf(" %d", ifaces[i]);
+diff --git a/tools/testing/selftests/core/close_range_test.c b/tools/testing/selftests/core/close_range_test.c
+index 73eb29c916d1b..aa7d13d91963f 100644
+--- a/tools/testing/selftests/core/close_range_test.c
++++ b/tools/testing/selftests/core/close_range_test.c
+@@ -54,7 +54,7 @@ static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+ #endif
+
+-TEST(close_range)
++TEST(core_close_range)
+ {
+ int i, ret;
+ int open_fds[101];
+diff --git a/tools/testing/selftests/damon/.gitignore b/tools/testing/selftests/damon/.gitignore
+new file mode 100644
+index 0000000000000..c6c2965a66075
+--- /dev/null
++++ b/tools/testing/selftests/damon/.gitignore
+@@ -0,0 +1,2 @@
++# SPDX-License-Identifier: GPL-2.0-only
++huge_count_read_write
+diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile
+index 8a3f2cd9fec0c..f0aa954b5d135 100644
+--- a/tools/testing/selftests/damon/Makefile
++++ b/tools/testing/selftests/damon/Makefile
+@@ -1,6 +1,8 @@
+ # SPDX-License-Identifier: GPL-2.0
+ # Makefile for damon selftests
+
++TEST_GEN_FILES += huge_count_read_write
++
+ TEST_FILES = _chk_dependency.sh
+ TEST_PROGS = debugfs_attrs.sh
+
+diff --git a/tools/testing/selftests/damon/debugfs_attrs.sh b/tools/testing/selftests/damon/debugfs_attrs.sh
+index bfabb19dc0d3d..ecda972e87775 100644
+--- a/tools/testing/selftests/damon/debugfs_attrs.sh
++++ b/tools/testing/selftests/damon/debugfs_attrs.sh
+@@ -72,4 +72,22 @@ test_write_succ "$file" "" "$orig_content" "empty input"
+ test_content "$file" "$orig_content" "" "empty input written"
+ echo "$orig_content" > "$file"
+
++# Test huge count read write
++# ==========================
++
++dmesg -C
++
++for file in "$DBGFS/"*
++do
++ ./huge_count_read_write "$file"
++done
++
++if dmesg | grep -q WARNING
++then
++ dmesg
++ exit 1
++else
++ exit 0
++fi
++
+ echo "PASS"
+diff --git a/tools/testing/selftests/damon/huge_count_read_write.c b/tools/testing/selftests/damon/huge_count_read_write.c
+new file mode 100644
+index 0000000000000..ad7a6b4cf3387
+--- /dev/null
++++ b/tools/testing/selftests/damon/huge_count_read_write.c
+@@ -0,0 +1,39 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Author: SeongJae Park <sj@kernel.org>
++ */
++
++#include <fcntl.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++
++void write_read_with_huge_count(char *file)
++{
++ int filedesc = open(file, O_RDWR);
++ char buf[25];
++ int ret;
++
++ printf("%s %s\n", __func__, file);
++ if (filedesc < 0) {
++ fprintf(stderr, "failed opening %s\n", file);
++ exit(1);
++ }
++
++ write(filedesc, "", 0xfffffffful);
++ perror("after write: ");
++ ret = read(filedesc, buf, 0xfffffffful);
++ perror("after read: ");
++ close(filedesc);
++}
++
++int main(int argc, char *argv[])
++{
++ if (argc != 2) {
++ fprintf(stderr, "Usage: %s <file>\n", argv[0]);
++ exit(1);
++ }
++ write_read_with_huge_count(argv[1]);
++
++ return 0;
++}
+diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
+index 39f2bbe8dd3df..42ea7d2aa8440 100644
+--- a/tools/testing/selftests/gpio/Makefile
++++ b/tools/testing/selftests/gpio/Makefile
+@@ -3,5 +3,6 @@
+ TEST_PROGS := gpio-mockup.sh
+ TEST_FILES := gpio-mockup-sysfs.sh
+ TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev
++CFLAGS += -I../../../../usr/include
+
+ include ../lib.mk
+diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
+index 010b59b139176..35314277fb586 100644
+--- a/tools/testing/selftests/kvm/include/kvm_util.h
++++ b/tools/testing/selftests/kvm/include/kvm_util.h
+@@ -69,6 +69,15 @@ enum vm_guest_mode {
+
+ #endif
+
++#if defined(__x86_64__)
++unsigned long vm_compute_max_gfn(struct kvm_vm *vm);
++#else
++static inline unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
++{
++ return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
++}
++#endif
++
+ #define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
+ #define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE)
+
+diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
+index 0299cd81b8ba2..aa3795cd7bd3d 100644
+--- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
++++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
+@@ -12,6 +12,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <sys/resource.h>
+
+ #include "test_util.h"
+
+@@ -40,10 +41,39 @@ int main(int argc, char *argv[])
+ {
+ int kvm_max_vcpu_id = kvm_check_cap(KVM_CAP_MAX_VCPU_ID);
+ int kvm_max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
++ /*
++ * Number of file descriptors reqired, KVM_CAP_MAX_VCPUS for vCPU fds +
++ * an arbitrary number for everything else.
++ */
++ int nr_fds_wanted = kvm_max_vcpus + 100;
++ struct rlimit rl;
+
+ pr_info("KVM_CAP_MAX_VCPU_ID: %d\n", kvm_max_vcpu_id);
+ pr_info("KVM_CAP_MAX_VCPUS: %d\n", kvm_max_vcpus);
+
++ /*
++ * Check that we're allowed to open nr_fds_wanted file descriptors and
++ * try raising the limits if needed.
++ */
++ TEST_ASSERT(!getrlimit(RLIMIT_NOFILE, &rl), "getrlimit() failed!");
++
++ if (rl.rlim_cur < nr_fds_wanted) {
++ rl.rlim_cur = nr_fds_wanted;
++ if (rl.rlim_max < nr_fds_wanted) {
++ int old_rlim_max = rl.rlim_max;
++ rl.rlim_max = nr_fds_wanted;
++
++ int r = setrlimit(RLIMIT_NOFILE, &rl);
++ if (r < 0) {
++ printf("RLIMIT_NOFILE hard limit is too low (%d, wanted %d)\n",
++ old_rlim_max, nr_fds_wanted);
++ exit(KSFT_SKIP);
++ }
++ } else {
++ TEST_ASSERT(!setrlimit(RLIMIT_NOFILE, &rl), "setrlimit() failed!");
++ }
++ }
++
+ /*
+ * Upstream KVM prior to 4.8 does not support KVM_CAP_MAX_VCPU_ID.
+ * Userspace is supposed to use KVM_CAP_MAX_VCPUS as the maximum ID
+diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
+index 10a8ed691c669..c439fb653fde2 100644
+--- a/tools/testing/selftests/kvm/lib/kvm_util.c
++++ b/tools/testing/selftests/kvm/lib/kvm_util.c
+@@ -307,7 +307,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm)
+ (1ULL << (vm->va_bits - 1)) >> vm->page_shift);
+
+ /* Limit physical addresses to PA-bits. */
+- vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
++ vm->max_gfn = vm_compute_max_gfn(vm);
+
+ /* Allocate and setup memory for guest. */
+ vm->vpages_mapped = sparsebit_alloc();
+diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c
+index 28cb881f440d0..da73b97e1e6dc 100644
+--- a/tools/testing/selftests/kvm/lib/x86_64/processor.c
++++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c
+@@ -1433,3 +1433,71 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpui
+
+ return cpuid;
+ }
++
++#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
++#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
++#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
++
++static inline unsigned x86_family(unsigned int eax)
++{
++ unsigned int x86;
++
++ x86 = (eax >> 8) & 0xf;
++
++ if (x86 == 0xf)
++ x86 += (eax >> 20) & 0xff;
++
++ return x86;
++}
++
++unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
++{
++ const unsigned long num_ht_pages = 12 << (30 - vm->page_shift); /* 12 GiB */
++ unsigned long ht_gfn, max_gfn, max_pfn;
++ uint32_t eax, ebx, ecx, edx, max_ext_leaf;
++
++ max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
++
++ /* Avoid reserved HyperTransport region on AMD processors. */
++ eax = ecx = 0;
++ cpuid(&eax, &ebx, &ecx, &edx);
++ if (ebx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx ||
++ ecx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx ||
++ edx != X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
++ return max_gfn;
++
++ /* On parts with <40 physical address bits, the area is fully hidden */
++ if (vm->pa_bits < 40)
++ return max_gfn;
++
++ /* Before family 17h, the HyperTransport area is just below 1T. */
++ ht_gfn = (1 << 28) - num_ht_pages;
++ eax = 1;
++ cpuid(&eax, &ebx, &ecx, &edx);
++ if (x86_family(eax) < 0x17)
++ goto done;
++
++ /*
++ * Otherwise it's at the top of the physical address space, possibly
++ * reduced due to SME by bits 11:6 of CPUID[0x8000001f].EBX. Use
++ * the old conservative value if MAXPHYADDR is not enumerated.
++ */
++ eax = 0x80000000;
++ cpuid(&eax, &ebx, &ecx, &edx);
++ max_ext_leaf = eax;
++ if (max_ext_leaf < 0x80000008)
++ goto done;
++
++ eax = 0x80000008;
++ cpuid(&eax, &ebx, &ecx, &edx);
++ max_pfn = (1ULL << ((eax & 0xff) - vm->page_shift)) - 1;
++ if (max_ext_leaf >= 0x8000001f) {
++ eax = 0x8000001f;
++ cpuid(&eax, &ebx, &ecx, &edx);
++ max_pfn >>= (ebx >> 6) & 0x3f;
++ }
++
++ ht_gfn = max_pfn - num_ht_pages;
++done:
++ return min(max_gfn, ht_gfn - 1);
++}
+diff --git a/tools/testing/selftests/kvm/lib/x86_64/svm.c b/tools/testing/selftests/kvm/lib/x86_64/svm.c
+index 2ac98d70d02bd..161eba7cd1289 100644
+--- a/tools/testing/selftests/kvm/lib/x86_64/svm.c
++++ b/tools/testing/selftests/kvm/lib/x86_64/svm.c
+@@ -54,6 +54,18 @@ static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
+ seg->base = base;
+ }
+
++/*
++ * Avoid using memset to clear the vmcb, since libc may not be
++ * available in L1 (and, even if it is, features that libc memset may
++ * want to use, like AVX, may not be enabled).
++ */
++static void clear_vmcb(struct vmcb *vmcb)
++{
++ int n = sizeof(*vmcb) / sizeof(u32);
++
++ asm volatile ("rep stosl" : "+c"(n), "+D"(vmcb) : "a"(0) : "memory");
++}
++
+ void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp)
+ {
+ struct vmcb *vmcb = svm->vmcb;
+@@ -70,7 +82,7 @@ void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_r
+ wrmsr(MSR_EFER, efer | EFER_SVME);
+ wrmsr(MSR_VM_HSAVE_PA, svm->save_area_gpa);
+
+- memset(vmcb, 0, sizeof(*vmcb));
++ clear_vmcb(vmcb);
+ asm volatile ("vmsave %0\n\t" : : "a" (vmcb_gpa) : "memory");
+ vmcb_set_seg(&save->es, get_es(), 0, -1U, data_seg_attr);
+ vmcb_set_seg(&save->cs, get_cs(), 0, -1U, code_seg_attr);
+diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
+index 8039e1eff9388..9f55ccd169a13 100644
+--- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
++++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
+@@ -84,7 +84,7 @@ int get_warnings_count(void)
+ f = popen("dmesg | grep \"WARNING:\" | wc -l", "r");
+ if (fscanf(f, "%d", &warnings) < 1)
+ warnings = 0;
+- fclose(f);
++ pclose(f);
+
+ return warnings;
+ }
+diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
+index 492b273743b4e..6a953ec793ced 100644
+--- a/tools/testing/selftests/net/Makefile
++++ b/tools/testing/selftests/net/Makefile
+@@ -12,7 +12,7 @@ TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_a
+ TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
+ TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh traceroute.sh
+ TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh
+-TEST_PROGS += altnames.sh icmp_redirect.sh ip6_gre_headroom.sh
++TEST_PROGS += altnames.sh icmp.sh icmp_redirect.sh ip6_gre_headroom.sh
+ TEST_PROGS += route_localnet.sh
+ TEST_PROGS += reuseaddr_ports_exhausted.sh
+ TEST_PROGS += txtimestamp.sh
+@@ -28,7 +28,12 @@ TEST_PROGS += veth.sh
+ TEST_PROGS += ioam6.sh
+ TEST_PROGS += gro.sh
+ TEST_PROGS += gre_gso.sh
+-TEST_PROGS_EXTENDED := in_netns.sh
++TEST_PROGS += srv6_end_dt46_l3vpn_test.sh
++TEST_PROGS += srv6_end_dt4_l3vpn_test.sh
++TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
++TEST_PROGS += vrf_strict_mode_test.sh
++TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
++TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
+ TEST_GEN_FILES = socket nettest
+ TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
+ TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite
+diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
+index 3313566ce9062..aec9e784d0b46 100755
+--- a/tools/testing/selftests/net/fcnal-test.sh
++++ b/tools/testing/selftests/net/fcnal-test.sh
+@@ -455,6 +455,22 @@ cleanup()
+ ip netns del ${NSC} >/dev/null 2>&1
+ }
+
++cleanup_vrf_dup()
++{
++ ip link del ${NSA_DEV2} >/dev/null 2>&1
++ ip netns pids ${NSC} | xargs kill 2>/dev/null
++ ip netns del ${NSC} >/dev/null 2>&1
++}
++
++setup_vrf_dup()
++{
++ # some VRF tests use ns-C which has the same config as
++ # ns-B but for a device NOT in the VRF
++ create_ns ${NSC} "-" "-"
++ connect_ns ${NSA} ${NSA_DEV2} ${NSA_IP}/24 ${NSA_IP6}/64 \
++ ${NSC} ${NSC_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
++}
++
+ setup()
+ {
+ local with_vrf=${1}
+@@ -484,12 +500,6 @@ setup()
+
+ ip -netns ${NSB} ro add ${VRF_IP}/32 via ${NSA_IP} dev ${NSB_DEV}
+ ip -netns ${NSB} -6 ro add ${VRF_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV}
+-
+- # some VRF tests use ns-C which has the same config as
+- # ns-B but for a device NOT in the VRF
+- create_ns ${NSC} "-" "-"
+- connect_ns ${NSA} ${NSA_DEV2} ${NSA_IP}/24 ${NSA_IP6}/64 \
+- ${NSC} ${NSC_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
+ else
+ ip -netns ${NSA} ro add ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV}
+ ip -netns ${NSA} ro add ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV}
+@@ -1240,7 +1250,9 @@ ipv4_tcp_vrf()
+ log_test_addr ${a} $? 1 "Global server, local connection"
+
+ # run MD5 tests
++ setup_vrf_dup
+ ipv4_tcp_md5
++ cleanup_vrf_dup
+
+ #
+ # enable VRF global server
+@@ -1798,8 +1810,9 @@ ipv4_addr_bind_vrf()
+ for a in ${NSA_IP} ${VRF_IP}
+ do
+ log_start
++ show_hint "Socket not bound to VRF, but address is in VRF"
+ run_cmd nettest -s -R -P icmp -l ${a} -b
+- log_test_addr ${a} $? 0 "Raw socket bind to local address"
++ log_test_addr ${a} $? 1 "Raw socket bind to local address"
+
+ log_start
+ run_cmd nettest -s -R -P icmp -l ${a} -I ${NSA_DEV} -b
+@@ -2191,7 +2204,7 @@ ipv6_ping_vrf()
+ log_start
+ show_hint "Fails since VRF device does not support linklocal or multicast"
+ run_cmd ${ping6} -c1 -w1 ${a}
+- log_test_addr ${a} $? 2 "ping out, VRF bind"
++ log_test_addr ${a} $? 1 "ping out, VRF bind"
+ done
+
+ for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+@@ -2719,7 +2732,9 @@ ipv6_tcp_vrf()
+ log_test_addr ${a} $? 1 "Global server, local connection"
+
+ # run MD5 tests
++ setup_vrf_dup
+ ipv6_tcp_md5
++ cleanup_vrf_dup
+
+ #
+ # enable VRF global server
+@@ -3414,11 +3429,14 @@ ipv6_addr_bind_novrf()
+ run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
+ log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind"
+
++ # Sadly, the kernel allows binding a socket to a device and then
++ # binding to an address not on the device. So this test passes
++ # when it really should not
+ a=${NSA_LO_IP6}
+ log_start
+- show_hint "Should fail with 'Cannot assign requested address'"
++ show_hint "Tecnically should fail since address is not on device but kernel allows"
+ run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
+- log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address"
++ log_test_addr ${a} $? 0 "TCP socket bind to out of scope local address"
+ }
+
+ ipv6_addr_bind_vrf()
+@@ -3459,10 +3477,15 @@ ipv6_addr_bind_vrf()
+ run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
+ log_test_addr ${a} $? 0 "TCP socket bind to local address with device bind"
+
++ # Sadly, the kernel allows binding a socket to a device and then
++ # binding to an address not on the device. The only restriction
++ # is that the address is valid in the L3 domain. So this test
++ # passes when it really should not
+ a=${VRF_IP6}
+ log_start
++ show_hint "Tecnically should fail since address is not on device but kernel allows"
+ run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
+- log_test_addr ${a} $? 1 "TCP socket bind to VRF address with device bind"
++ log_test_addr ${a} $? 0 "TCP socket bind to VRF address with device bind"
+
+ a=${NSA_LO_IP6}
+ log_start
+@@ -4002,8 +4025,8 @@ EOF
+ ################################################################################
+ # main
+
+-TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime ipv4_netfilter"
+-TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime ipv6_netfilter"
++TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_bind ipv4_runtime ipv4_netfilter"
++TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_bind ipv6_runtime ipv6_netfilter"
+ TESTS_OTHER="use_cases"
+
+ PAUSE_ON_FAIL=no
+diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
+index 0d293391e9a44..b5a69ad191b07 100755
+--- a/tools/testing/selftests/net/fib_nexthops.sh
++++ b/tools/testing/selftests/net/fib_nexthops.sh
+@@ -2078,6 +2078,7 @@ basic_res()
+ "id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
+ log_test $? 0 "Dump all nexthop buckets in a group"
+
++ sleep 0.1
+ (( $($IP -j nexthop bucket list id 101 |
+ jq '[.[] | select(.bucket.idle_time > 0 and
+ .bucket.idle_time < 2)] | length') == 4 ))
+diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
+index 5abe92d55b696..996af1ae3d3dd 100755
+--- a/tools/testing/selftests/net/fib_tests.sh
++++ b/tools/testing/selftests/net/fib_tests.sh
+@@ -444,24 +444,63 @@ fib_rp_filter_test()
+ setup
+
+ set -e
++ ip netns add ns2
++ ip netns set ns2 auto
++
++ ip -netns ns2 link set dev lo up
++
++ $IP link add name veth1 type veth peer name veth2
++ $IP link set dev veth2 netns ns2
++ $IP address add 192.0.2.1/24 dev veth1
++ ip -netns ns2 address add 192.0.2.1/24 dev veth2
++ $IP link set dev veth1 up
++ ip -netns ns2 link set dev veth2 up
++
+ $IP link set dev lo address 52:54:00:6a:c7:5e
+- $IP link set dummy0 address 52:54:00:6a:c7:5e
+- $IP link add dummy1 type dummy
+- $IP link set dummy1 address 52:54:00:6a:c7:5e
+- $IP link set dev dummy1 up
++ $IP link set dev veth1 address 52:54:00:6a:c7:5e
++ ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
++ ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
++
++ # 1. (ns2) redirect lo's egress to veth2's egress
++ ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
++ ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
++ action mirred egress redirect dev veth2
++ ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
++ action mirred egress redirect dev veth2
++
++ # 2. (ns1) redirect veth1's ingress to lo's ingress
++ $NS_EXEC tc qdisc add dev veth1 ingress
++ $NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
++ action mirred ingress redirect dev lo
++ $NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
++ action mirred ingress redirect dev lo
++
++ # 3. (ns1) redirect lo's egress to veth1's egress
++ $NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
++ $NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
++ action mirred egress redirect dev veth1
++ $NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
++ action mirred egress redirect dev veth1
++
++ # 4. (ns2) redirect veth2's ingress to lo's ingress
++ ip netns exec ns2 tc qdisc add dev veth2 ingress
++ ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
++ action mirred ingress redirect dev lo
++ ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
++ action mirred ingress redirect dev lo
++
+ $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
+ $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
+ $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
+-
+- $NS_EXEC tc qd add dev dummy1 parent root handle 1: fq_codel
+- $NS_EXEC tc filter add dev dummy1 parent 1: protocol arp basic action mirred egress redirect dev lo
+- $NS_EXEC tc filter add dev dummy1 parent 1: protocol ip basic action mirred egress redirect dev lo
++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
+ set +e
+
+- run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 198.51.100.1"
++ run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
+ log_test $? 0 "rp_filter passes local packets"
+
+- run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 127.0.0.1"
++ run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
+ log_test $? 0 "rp_filter passes loopback packets"
+
+ cleanup
+diff --git a/tools/testing/selftests/net/forwarding/bridge_igmp.sh b/tools/testing/selftests/net/forwarding/bridge_igmp.sh
+index 675eff45b0371..1162836f8f329 100755
+--- a/tools/testing/selftests/net/forwarding/bridge_igmp.sh
++++ b/tools/testing/selftests/net/forwarding/bridge_igmp.sh
+@@ -482,10 +482,15 @@ v3exc_timeout_test()
+ local X=("192.0.2.20" "192.0.2.30")
+
+ # GMI should be 3 seconds
+- ip link set dev br0 type bridge mcast_query_interval 100 mcast_query_response_interval 100
++ ip link set dev br0 type bridge mcast_query_interval 100 \
++ mcast_query_response_interval 100 \
++ mcast_membership_interval 300
+
+ v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
+- ip link set dev br0 type bridge mcast_query_interval 500 mcast_query_response_interval 500
++ ip link set dev br0 type bridge mcast_query_interval 500 \
++ mcast_query_response_interval 500 \
++ mcast_membership_interval 1500
++
+ $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q
+ sleep 3
+ bridge -j -d -s mdb show dev br0 \
+@@ -517,7 +522,8 @@ v3exc_timeout_test()
+ log_test "IGMPv3 group $TEST_GROUP exclude timeout"
+
+ ip link set dev br0 type bridge mcast_query_interval 12500 \
+- mcast_query_response_interval 1000
++ mcast_query_response_interval 1000 \
++ mcast_membership_interval 26000
+
+ v3cleanup $swp1 $TEST_GROUP
+ }
+diff --git a/tools/testing/selftests/net/forwarding/bridge_mld.sh b/tools/testing/selftests/net/forwarding/bridge_mld.sh
+index ffdcfa87ca2ba..e2b9ff773c6b6 100755
+--- a/tools/testing/selftests/net/forwarding/bridge_mld.sh
++++ b/tools/testing/selftests/net/forwarding/bridge_mld.sh
+@@ -479,10 +479,15 @@ mldv2exc_timeout_test()
+ local X=("2001:db8:1::20" "2001:db8:1::30")
+
+ # GMI should be 3 seconds
+- ip link set dev br0 type bridge mcast_query_interval 100 mcast_query_response_interval 100
++ ip link set dev br0 type bridge mcast_query_interval 100 \
++ mcast_query_response_interval 100 \
++ mcast_membership_interval 300
+
+ mldv2exclude_prepare $h1
+- ip link set dev br0 type bridge mcast_query_interval 500 mcast_query_response_interval 500
++ ip link set dev br0 type bridge mcast_query_interval 500 \
++ mcast_query_response_interval 500 \
++ mcast_membership_interval 1500
++
+ $MZ $h1 -c 1 $MZPKT_ALLOW2 -q
+ sleep 3
+ bridge -j -d -s mdb show dev br0 \
+@@ -514,7 +519,8 @@ mldv2exc_timeout_test()
+ log_test "MLDv2 group $TEST_GROUP exclude timeout"
+
+ ip link set dev br0 type bridge mcast_query_interval 12500 \
+- mcast_query_response_interval 1000
++ mcast_query_response_interval 1000 \
++ mcast_membership_interval 26000
+
+ mldv2cleanup $swp1
+ }
+diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample
+index e5e2fbeca22ec..e51def39fd801 100644
+--- a/tools/testing/selftests/net/forwarding/forwarding.config.sample
++++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample
+@@ -13,6 +13,8 @@ NETIFS[p5]=veth4
+ NETIFS[p6]=veth5
+ NETIFS[p7]=veth6
+ NETIFS[p8]=veth7
++NETIFS[p9]=veth8
++NETIFS[p10]=veth9
+
+ # Port that does not have a cable connected.
+ NETIF_NO_CABLE=eth8
+diff --git a/tools/testing/selftests/net/gre_gso.sh b/tools/testing/selftests/net/gre_gso.sh
+index facbb0c804439..3224651db97b8 100755
+--- a/tools/testing/selftests/net/gre_gso.sh
++++ b/tools/testing/selftests/net/gre_gso.sh
+@@ -116,17 +116,20 @@ gre_gst_test_checks()
+ {
+ local name=$1
+ local addr=$2
++ local proto=$3
+
+- $NS_EXEC nc -kl $port >/dev/null &
++ [ "$proto" == 6 ] && addr="[$addr]"
++
++ $NS_EXEC socat - tcp${proto}-listen:$port,reuseaddr,fork >/dev/null &
+ PID=$!
+ while ! $NS_EXEC ss -ltn | grep -q $port; do ((i++)); sleep 0.01; done
+
+- cat $TMPFILE | timeout 1 nc $addr $port
++ cat $TMPFILE | timeout 1 socat -u STDIN TCP:$addr:$port
+ log_test $? 0 "$name - copy file w/ TSO"
+
+ ethtool -K veth0 tso off
+
+- cat $TMPFILE | timeout 1 nc $addr $port
++ cat $TMPFILE | timeout 1 socat -u STDIN TCP:$addr:$port
+ log_test $? 0 "$name - copy file w/ GSO"
+
+ ethtool -K veth0 tso on
+@@ -154,8 +157,8 @@ gre6_gso_test()
+
+ sleep 2
+
+- gre_gst_test_checks GREv6/v4 172.16.2.2
+- gre_gst_test_checks GREv6/v6 2001:db8:1::2
++ gre_gst_test_checks GREv6/v4 172.16.2.2 4
++ gre_gst_test_checks GREv6/v6 2001:db8:1::2 6
+
+ cleanup
+ }
+@@ -211,8 +214,8 @@ if [ ! -x "$(command -v ip)" ]; then
+ exit $ksft_skip
+ fi
+
+-if [ ! -x "$(command -v nc)" ]; then
+- echo "SKIP: Could not run test without nc tool"
++if [ ! -x "$(command -v socat)" ]; then
++ echo "SKIP: Could not run test without socat tool"
+ exit $ksft_skip
+ fi
+
+diff --git a/tools/testing/selftests/net/icmp_redirect.sh b/tools/testing/selftests/net/icmp_redirect.sh
+index ecbf57f264ed9..7b9d6e31b8e7d 100755
+--- a/tools/testing/selftests/net/icmp_redirect.sh
++++ b/tools/testing/selftests/net/icmp_redirect.sh
+@@ -311,7 +311,7 @@ check_exception()
+ ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
+ grep -E -v 'mtu|redirected' | grep -q "cache"
+ fi
+- log_test $? 0 "IPv4: ${desc}"
++ log_test $? 0 "IPv4: ${desc}" 0
+
+ # No PMTU info for test "redirect" and "mtu exception plus redirect"
+ if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then
+diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
+index 255793c5ac4ff..586af88194e56 100755
+--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
+@@ -297,7 +297,7 @@ do_transfer()
+ if [ "$test_link_fail" -eq 2 ];then
+ timeout ${timeout_test} \
+ ip netns exec ${listener_ns} \
+- $mptcp_connect -t ${timeout_poll} -l -p $port -s ${cl_proto} \
++ $mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \
+ ${local_addr} < "$sinfail" > "$sout" &
+ else
+ timeout ${timeout_test} \
+diff --git a/tools/testing/selftests/net/toeplitz.c b/tools/testing/selftests/net/toeplitz.c
+index 710ac956bdb33..c5489341cfb80 100644
+--- a/tools/testing/selftests/net/toeplitz.c
++++ b/tools/testing/selftests/net/toeplitz.c
+@@ -498,7 +498,7 @@ static void parse_opts(int argc, char **argv)
+ bool have_toeplitz = false;
+ int index, c;
+
+- while ((c = getopt_long(argc, argv, "46C:d:i:k:r:stT:u:v", long_options, &index)) != -1) {
++ while ((c = getopt_long(argc, argv, "46C:d:i:k:r:stT:uv", long_options, &index)) != -1) {
+ switch (c) {
+ case '4':
+ cfg_family = AF_INET;
+diff --git a/tools/testing/selftests/net/udpgso_bench_rx.c b/tools/testing/selftests/net/udpgso_bench_rx.c
+index 76a24052f4b47..6a193425c367f 100644
+--- a/tools/testing/selftests/net/udpgso_bench_rx.c
++++ b/tools/testing/selftests/net/udpgso_bench_rx.c
+@@ -293,19 +293,17 @@ static void usage(const char *filepath)
+
+ static void parse_opts(int argc, char **argv)
+ {
++ const char *bind_addr = NULL;
+ int c;
+
+- /* bind to any by default */
+- setup_sockaddr(PF_INET6, "::", &cfg_bind_addr);
+ while ((c = getopt(argc, argv, "4b:C:Gl:n:p:rR:S:tv")) != -1) {
+ switch (c) {
+ case '4':
+ cfg_family = PF_INET;
+ cfg_alen = sizeof(struct sockaddr_in);
+- setup_sockaddr(PF_INET, "0.0.0.0", &cfg_bind_addr);
+ break;
+ case 'b':
+- setup_sockaddr(cfg_family, optarg, &cfg_bind_addr);
++ bind_addr = optarg;
+ break;
+ case 'C':
+ cfg_connect_timeout_ms = strtoul(optarg, NULL, 0);
+@@ -341,6 +339,11 @@ static void parse_opts(int argc, char **argv)
+ }
+ }
+
++ if (!bind_addr)
++ bind_addr = cfg_family == PF_INET6 ? "::" : "0.0.0.0";
++
++ setup_sockaddr(cfg_family, bind_addr, &cfg_bind_addr);
++
+ if (optind != argc)
+ usage(argv[0]);
+
+diff --git a/tools/testing/selftests/netfilter/Makefile b/tools/testing/selftests/netfilter/Makefile
+index 8748199ac1098..ffca314897c4c 100644
+--- a/tools/testing/selftests/netfilter/Makefile
++++ b/tools/testing/selftests/netfilter/Makefile
+@@ -5,7 +5,8 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
+ conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
+ nft_concat_range.sh nft_conntrack_helper.sh \
+ nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
+- ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh
++ ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \
++ conntrack_vrf.sh
+
+ LDLIBS = -lmnl
+ TEST_GEN_FILES = nf-queue
+diff --git a/tools/testing/selftests/netfilter/conntrack_vrf.sh b/tools/testing/selftests/netfilter/conntrack_vrf.sh
+new file mode 100755
+index 0000000000000..8b5ea92345882
+--- /dev/null
++++ b/tools/testing/selftests/netfilter/conntrack_vrf.sh
+@@ -0,0 +1,241 @@
++#!/bin/sh
++
++# This script demonstrates interaction of conntrack and vrf.
++# The vrf driver calls the netfilter hooks again, with oif/iif
++# pointing at the VRF device.
++#
++# For ingress, this means first iteration has iifname of lower/real
++# device. In this script, thats veth0.
++# Second iteration is iifname set to vrf device, tvrf in this script.
++#
++# For egress, this is reversed: first iteration has the vrf device,
++# second iteration is done with the lower/real/veth0 device.
++#
++# test_ct_zone_in demonstrates unexpected change of nftables
++# behavior # caused by commit 09e856d54bda5f28 "vrf: Reset skb conntrack
++# connection on VRF rcv"
++#
++# It was possible to assign conntrack zone to a packet (or mark it for
++# `notracking`) in the prerouting chain before conntrack, based on real iif.
++#
++# After the change, the zone assignment is lost and the zone is assigned based
++# on the VRF master interface (in case such a rule exists).
++# assignment is lost. Instead, assignment based on the `iif` matching
++# Thus it is impossible to distinguish packets based on the original
++# interface.
++#
++# test_masquerade_vrf and test_masquerade_veth0 demonstrate the problem
++# that was supposed to be fixed by the commit mentioned above to make sure
++# that any fix to test case 1 won't break masquerade again.
++
++ksft_skip=4
++
++IP0=172.30.30.1
++IP1=172.30.30.2
++PFXL=30
++ret=0
++
++sfx=$(mktemp -u "XXXXXXXX")
++ns0="ns0-$sfx"
++ns1="ns1-$sfx"
++
++cleanup()
++{
++ ip netns pids $ns0 | xargs kill 2>/dev/null
++ ip netns pids $ns1 | xargs kill 2>/dev/null
++
++ ip netns del $ns0 $ns1
++}
++
++nft --version > /dev/null 2>&1
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not run test without nft tool"
++ exit $ksft_skip
++fi
++
++ip -Version > /dev/null 2>&1
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not run test without ip tool"
++ exit $ksft_skip
++fi
++
++ip netns add "$ns0"
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not create net namespace $ns0"
++ exit $ksft_skip
++fi
++ip netns add "$ns1"
++
++trap cleanup EXIT
++
++ip netns exec $ns0 sysctl -q -w net.ipv4.conf.default.rp_filter=0
++ip netns exec $ns0 sysctl -q -w net.ipv4.conf.all.rp_filter=0
++ip netns exec $ns0 sysctl -q -w net.ipv4.conf.all.rp_filter=0
++
++ip link add veth0 netns "$ns0" type veth peer name veth0 netns "$ns1" > /dev/null 2>&1
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not add veth device"
++ exit $ksft_skip
++fi
++
++ip -net $ns0 li add tvrf type vrf table 9876
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not add vrf device"
++ exit $ksft_skip
++fi
++
++ip -net $ns0 li set lo up
++
++ip -net $ns0 li set veth0 master tvrf
++ip -net $ns0 li set tvrf up
++ip -net $ns0 li set veth0 up
++ip -net $ns1 li set veth0 up
++
++ip -net $ns0 addr add $IP0/$PFXL dev veth0
++ip -net $ns1 addr add $IP1/$PFXL dev veth0
++
++ip netns exec $ns1 iperf3 -s > /dev/null 2>&1&
++if [ $? -ne 0 ];then
++ echo "SKIP: Could not start iperf3"
++ exit $ksft_skip
++fi
++
++# test vrf ingress handling.
++# The incoming connection should be placed in conntrack zone 1,
++# as decided by the first iteration of the ruleset.
++test_ct_zone_in()
++{
++ip netns exec $ns0 nft -f - <<EOF
++table testct {
++ chain rawpre {
++ type filter hook prerouting priority raw;
++
++ iif { veth0, tvrf } counter meta nftrace set 1
++ iif veth0 counter ct zone set 1 counter return
++ iif tvrf counter ct zone set 2 counter return
++ ip protocol icmp counter
++ notrack counter
++ }
++
++ chain rawout {
++ type filter hook output priority raw;
++
++ oif veth0 counter ct zone set 1 counter return
++ oif tvrf counter ct zone set 2 counter return
++ notrack counter
++ }
++}
++EOF
++ ip netns exec $ns1 ping -W 1 -c 1 -I veth0 $IP0 > /dev/null
++
++ # should be in zone 1, not zone 2
++ count=$(ip netns exec $ns0 conntrack -L -s $IP1 -d $IP0 -p icmp --zone 1 2>/dev/null | wc -l)
++ if [ $count -eq 1 ]; then
++ echo "PASS: entry found in conntrack zone 1"
++ else
++ echo "FAIL: entry not found in conntrack zone 1"
++ count=$(ip netns exec $ns0 conntrack -L -s $IP1 -d $IP0 -p icmp --zone 2 2> /dev/null | wc -l)
++ if [ $count -eq 1 ]; then
++ echo "FAIL: entry found in zone 2 instead"
++ else
++ echo "FAIL: entry not in zone 1 or 2, dumping table"
++ ip netns exec $ns0 conntrack -L
++ ip netns exec $ns0 nft list ruleset
++ fi
++ fi
++}
++
++# add masq rule that gets evaluated w. outif set to vrf device.
++# This tests the first iteration of the packet through conntrack,
++# oifname is the vrf device.
++test_masquerade_vrf()
++{
++ local qdisc=$1
++
++ if [ "$qdisc" != "default" ]; then
++ tc -net $ns0 qdisc add dev tvrf root $qdisc
++ fi
++
++ ip netns exec $ns0 conntrack -F 2>/dev/null
++
++ip netns exec $ns0 nft -f - <<EOF
++flush ruleset
++table ip nat {
++ chain rawout {
++ type filter hook output priority raw;
++
++ oif tvrf ct state untracked counter
++ }
++ chain postrouting2 {
++ type filter hook postrouting priority mangle;
++
++ oif tvrf ct state untracked counter
++ }
++ chain postrouting {
++ type nat hook postrouting priority 0;
++ # NB: masquerade should always be combined with 'oif(name) bla',
++ # lack of this is intentional here, we want to exercise double-snat.
++ ip saddr 172.30.30.0/30 counter masquerade random
++ }
++}
++EOF
++ ip netns exec $ns0 ip vrf exec tvrf iperf3 -t 1 -c $IP1 >/dev/null
++ if [ $? -ne 0 ]; then
++ echo "FAIL: iperf3 connect failure with masquerade + sport rewrite on vrf device"
++ ret=1
++ return
++ fi
++
++ # must also check that nat table was evaluated on second (lower device) iteration.
++ ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' &&
++ ip netns exec $ns0 nft list table ip nat |grep -q 'untracked counter packets [1-9]'
++ if [ $? -eq 0 ]; then
++ echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device ($qdisc qdisc)"
++ else
++ echo "FAIL: vrf rules have unexpected counter value"
++ ret=1
++ fi
++
++ if [ "$qdisc" != "default" ]; then
++ tc -net $ns0 qdisc del dev tvrf root
++ fi
++}
++
++# add masq rule that gets evaluated w. outif set to veth device.
++# This tests the 2nd iteration of the packet through conntrack,
++# oifname is the lower device (veth0 in this case).
++test_masquerade_veth()
++{
++ ip netns exec $ns0 conntrack -F 2>/dev/null
++ip netns exec $ns0 nft -f - <<EOF
++flush ruleset
++table ip nat {
++ chain postrouting {
++ type nat hook postrouting priority 0;
++ meta oif veth0 ip saddr 172.30.30.0/30 counter masquerade random
++ }
++}
++EOF
++ ip netns exec $ns0 ip vrf exec tvrf iperf3 -t 1 -c $IP1 > /dev/null
++ if [ $? -ne 0 ]; then
++ echo "FAIL: iperf3 connect failure with masquerade + sport rewrite on veth device"
++ ret=1
++ return
++ fi
++
++ # must also check that nat table was evaluated on second (lower device) iteration.
++ ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2'
++ if [ $? -eq 0 ]; then
++ echo "PASS: iperf3 connect with masquerade + sport rewrite on veth device"
++ else
++ echo "FAIL: vrf masq rule has unexpected counter value"
++ ret=1
++ fi
++}
++
++test_ct_zone_in
++test_masquerade_vrf "default"
++test_masquerade_vrf "pfifo"
++test_masquerade_veth
++
++exit $ret
+diff --git a/tools/testing/selftests/sched/cs_prctl_test.c b/tools/testing/selftests/sched/cs_prctl_test.c
+index 7db9cf822dc75..8109b17dc764c 100644
+--- a/tools/testing/selftests/sched/cs_prctl_test.c
++++ b/tools/testing/selftests/sched/cs_prctl_test.c
+@@ -62,6 +62,17 @@ enum pid_type {PIDTYPE_PID = 0, PIDTYPE_TGID, PIDTYPE_PGID};
+
+ const int THREAD_CLONE_FLAGS = CLONE_THREAD | CLONE_SIGHAND | CLONE_FS | CLONE_VM | CLONE_FILES;
+
++struct child_args {
++ int num_threads;
++ int pfd[2];
++ int cpid;
++ int thr_tids[MAX_THREADS];
++};
++
++static struct child_args procs[MAX_PROCESSES];
++static int num_processes = 2;
++static int need_cleanup = 0;
++
+ static int _prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4,
+ unsigned long arg5)
+ {
+@@ -78,8 +89,14 @@ static int _prctl(int option, unsigned long arg2, unsigned long arg3, unsigned l
+ #define handle_error(msg) __handle_error(__FILE__, __LINE__, msg)
+ static void __handle_error(char *fn, int ln, char *msg)
+ {
++ int pidx;
+ printf("(%s:%d) - ", fn, ln);
+ perror(msg);
++ if (need_cleanup) {
++ for (pidx = 0; pidx < num_processes; ++pidx)
++ kill(procs[pidx].cpid, 15);
++ need_cleanup = 0;
++ }
+ exit(EXIT_FAILURE);
+ }
+
+@@ -106,13 +123,6 @@ static unsigned long get_cs_cookie(int pid)
+ return cookie;
+ }
+
+-struct child_args {
+- int num_threads;
+- int pfd[2];
+- int cpid;
+- int thr_tids[MAX_THREADS];
+-};
+-
+ static int child_func_thread(void __attribute__((unused))*arg)
+ {
+ while (1)
+@@ -212,10 +222,7 @@ void _validate(int line, int val, char *msg)
+
+ int main(int argc, char *argv[])
+ {
+- struct child_args procs[MAX_PROCESSES];
+-
+ int keypress = 0;
+- int num_processes = 2;
+ int num_threads = 3;
+ int delay = 0;
+ int res = 0;
+@@ -262,6 +269,7 @@ int main(int argc, char *argv[])
+
+ printf("\n## Create a thread/process/process group hiearchy\n");
+ create_processes(num_processes, num_threads, procs);
++ need_cleanup = 1;
+ disp_processes(num_processes, procs);
+ validate(get_cs_cookie(0) == 0);
+
+diff --git a/tools/testing/selftests/wireguard/netns.sh b/tools/testing/selftests/wireguard/netns.sh
+index ebc4ee0fe179f..8a9461aa0878a 100755
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -276,7 +276,11 @@ n0 ping -W 1 -c 1 192.168.241.2
+ n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
+ ip2 link del wg0
+ ip2 link del wg1
+-! n0 ping -W 1 -c 10 -f 192.168.241.2 || false # Should not crash kernel
++read _ _ tx_bytes_before < <(n0 wg show wg1 transfer)
++! n0 ping -W 1 -c 10 -f 192.168.241.2 || false
++sleep 1
++read _ _ tx_bytes_after < <(n0 wg show wg1 transfer)
++(( tx_bytes_after - tx_bytes_before < 70000 ))
+
+ ip0 link del wg1
+ ip1 link del wg0
+@@ -609,6 +613,28 @@ ip0 link set wg0 up
+ kill $ncat_pid
+ ip0 link del wg0
+
++# Ensure that dst_cache references don't outlive netns lifetime
++ip1 link add dev wg0 type wireguard
++ip2 link add dev wg0 type wireguard
++configure_peers
++ip1 link add veth1 type veth peer name veth2
++ip1 link set veth2 netns $netns2
++ip1 addr add fd00:aa::1/64 dev veth1
++ip2 addr add fd00:aa::2/64 dev veth2
++ip1 link set veth1 up
++ip2 link set veth2 up
++waitiface $netns1 veth1
++waitiface $netns2 veth2
++ip1 -6 route add default dev veth1 via fd00:aa::2
++ip2 -6 route add default dev veth2 via fd00:aa::1
++n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
++n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
++n1 ping6 -c 1 fd00::2
++pp ip netns delete $netns1
++pp ip netns delete $netns2
++pp ip netns add $netns1
++pp ip netns add $netns2
++
+ # Ensure there aren't circular reference loops
+ ip1 link add wg1 type wireguard
+ ip2 link add wg2 type wireguard
+@@ -627,7 +653,7 @@ while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
+ done < /dev/kmsg
+ alldeleted=1
+ for object in "${!objects[@]}"; do
+- if [[ ${objects["$object"]} != *createddestroyed ]]; then
++ if [[ ${objects["$object"]} != *createddestroyed && ${objects["$object"]} != *createdcreateddestroyeddestroyed ]]; then
+ echo "Error: $object: merely ${objects["$object"]}" >&3
+ alldeleted=0
+ fi
+diff --git a/tools/testing/selftests/wireguard/qemu/debug.config b/tools/testing/selftests/wireguard/qemu/debug.config
+index fe07d97df9fa8..2b321b8a96cf3 100644
+--- a/tools/testing/selftests/wireguard/qemu/debug.config
++++ b/tools/testing/selftests/wireguard/qemu/debug.config
+@@ -47,7 +47,7 @@ CONFIG_DEBUG_ATOMIC_SLEEP=y
+ CONFIG_TRACE_IRQFLAGS=y
+ CONFIG_DEBUG_BUGVERBOSE=y
+ CONFIG_DEBUG_LIST=y
+-CONFIG_DEBUG_PI_LIST=y
++CONFIG_DEBUG_PLIST=y
+ CONFIG_PROVE_RCU=y
+ CONFIG_SPARSE_RCU_POINTER=y
+ CONFIG_RCU_CPU_STALL_TIMEOUT=21
+diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config
+index 74db83a0aedd8..a9b5a520a1d22 100644
+--- a/tools/testing/selftests/wireguard/qemu/kernel.config
++++ b/tools/testing/selftests/wireguard/qemu/kernel.config
+@@ -66,6 +66,7 @@ CONFIG_PROC_SYSCTL=y
+ CONFIG_SYSFS=y
+ CONFIG_TMPFS=y
+ CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
++CONFIG_LOG_BUF_SHIFT=18
+ CONFIG_PRINTK_TIME=y
+ CONFIG_BLK_DEV_INITRD=y
+ CONFIG_LEGACY_VSYSCALL_NONE=y
+diff --git a/tools/testing/selftests/x86/iopl.c b/tools/testing/selftests/x86/iopl.c
+index bab2f6e06b63d..7e3e09c1abac6 100644
+--- a/tools/testing/selftests/x86/iopl.c
++++ b/tools/testing/selftests/x86/iopl.c
+@@ -85,48 +85,88 @@ static void expect_gp_outb(unsigned short port)
+ printf("[OK]\toutb to 0x%02hx failed\n", port);
+ }
+
+-static bool try_cli(void)
++#define RET_FAULTED 0
++#define RET_FAIL 1
++#define RET_EMUL 2
++
++static int try_cli(void)
+ {
++ unsigned long flags;
++
+ sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
+ if (sigsetjmp(jmpbuf, 1) != 0) {
+- return false;
++ return RET_FAULTED;
+ } else {
+- asm volatile ("cli");
+- return true;
++ asm volatile("cli; pushf; pop %[flags]"
++ : [flags] "=rm" (flags));
++
++ /* X86_FLAGS_IF */
++ if (!(flags & (1 << 9)))
++ return RET_FAIL;
++ else
++ return RET_EMUL;
+ }
+ clearhandler(SIGSEGV);
+ }
+
+-static bool try_sti(void)
++static int try_sti(bool irqs_off)
+ {
++ unsigned long flags;
++
+ sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
+ if (sigsetjmp(jmpbuf, 1) != 0) {
+- return false;
++ return RET_FAULTED;
+ } else {
+- asm volatile ("sti");
+- return true;
++ asm volatile("sti; pushf; pop %[flags]"
++ : [flags] "=rm" (flags));
++
++ /* X86_FLAGS_IF */
++ if (irqs_off && (flags & (1 << 9)))
++ return RET_FAIL;
++ else
++ return RET_EMUL;
+ }
+ clearhandler(SIGSEGV);
+ }
+
+-static void expect_gp_sti(void)
++static void expect_gp_sti(bool irqs_off)
+ {
+- if (try_sti()) {
++ int ret = try_sti(irqs_off);
++
++ switch (ret) {
++ case RET_FAULTED:
++ printf("[OK]\tSTI faulted\n");
++ break;
++ case RET_EMUL:
++ printf("[OK]\tSTI NOPped\n");
++ break;
++ default:
+ printf("[FAIL]\tSTI worked\n");
+ nerrs++;
+- } else {
+- printf("[OK]\tSTI faulted\n");
+ }
+ }
+
+-static void expect_gp_cli(void)
++/*
++ * Returns whether it managed to disable interrupts.
++ */
++static bool test_cli(void)
+ {
+- if (try_cli()) {
++ int ret = try_cli();
++
++ switch (ret) {
++ case RET_FAULTED:
++ printf("[OK]\tCLI faulted\n");
++ break;
++ case RET_EMUL:
++ printf("[OK]\tCLI NOPped\n");
++ break;
++ default:
+ printf("[FAIL]\tCLI worked\n");
+ nerrs++;
+- } else {
+- printf("[OK]\tCLI faulted\n");
++ return true;
+ }
++
++ return false;
+ }
+
+ int main(void)
+@@ -152,8 +192,7 @@ int main(void)
+ }
+
+ /* Make sure that CLI/STI are blocked even with IOPL level 3 */
+- expect_gp_cli();
+- expect_gp_sti();
++ expect_gp_sti(test_cli());
+ expect_ok_outb(0x80);
+
+ /* Establish an I/O bitmap to test the restore */
+@@ -204,8 +243,7 @@ int main(void)
+ printf("[RUN]\tparent: write to 0x80 (should fail)\n");
+
+ expect_gp_outb(0x80);
+- expect_gp_cli();
+- expect_gp_sti();
++ expect_gp_sti(test_cli());
+
+ /* Test the capability checks. */
+ printf("\tiopl(3)\n");
+diff --git a/tools/tracing/latency/latency-collector.c b/tools/tracing/latency/latency-collector.c
+index 3a2e6bb781a8c..59a7f2346eab4 100644
+--- a/tools/tracing/latency/latency-collector.c
++++ b/tools/tracing/latency/latency-collector.c
+@@ -1538,7 +1538,7 @@ static void tracing_loop(void)
+ mutex_lock(&print_mtx);
+ check_signals();
+ write_or_die(fd_stdout, queue_full_warning,
+- sizeof(queue_full_warning));
++ strlen(queue_full_warning));
+ mutex_unlock(&print_mtx);
+ }
+ modified--;
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index 7851f3a1b5f7c..c6bfd4e15d28a 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -1523,11 +1523,10 @@ static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
+
+ static int kvm_set_memslot(struct kvm *kvm,
+ const struct kvm_userspace_memory_region *mem,
+- struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new, int as_id,
+ enum kvm_mr_change change)
+ {
+- struct kvm_memory_slot *slot;
++ struct kvm_memory_slot *slot, old;
+ struct kvm_memslots *slots;
+ int r;
+
+@@ -1558,7 +1557,7 @@ static int kvm_set_memslot(struct kvm *kvm,
+ * Note, the INVALID flag needs to be in the appropriate entry
+ * in the freshly allocated memslots, not in @old or @new.
+ */
+- slot = id_to_memslot(slots, old->id);
++ slot = id_to_memslot(slots, new->id);
+ slot->flags |= KVM_MEMSLOT_INVALID;
+
+ /*
+@@ -1589,6 +1588,26 @@ static int kvm_set_memslot(struct kvm *kvm,
+ kvm_copy_memslots(slots, __kvm_memslots(kvm, as_id));
+ }
+
++ /*
++ * Make a full copy of the old memslot, the pointer will become stale
++ * when the memslots are re-sorted by update_memslots(), and the old
++ * memslot needs to be referenced after calling update_memslots(), e.g.
++ * to free its resources and for arch specific behavior. This needs to
++ * happen *after* (re)acquiring slots_arch_lock.
++ */
++ slot = id_to_memslot(slots, new->id);
++ if (slot) {
++ old = *slot;
++ } else {
++ WARN_ON_ONCE(change != KVM_MR_CREATE);
++ memset(&old, 0, sizeof(old));
++ old.id = new->id;
++ old.as_id = as_id;
++ }
++
++ /* Copy the arch-specific data, again after (re)acquiring slots_arch_lock. */
++ memcpy(&new->arch, &old.arch, sizeof(old.arch));
++
+ r = kvm_arch_prepare_memory_region(kvm, new, mem, change);
+ if (r)
+ goto out_slots;
+@@ -1596,14 +1615,18 @@ static int kvm_set_memslot(struct kvm *kvm,
+ update_memslots(slots, new, change);
+ slots = install_new_memslots(kvm, as_id, slots);
+
+- kvm_arch_commit_memory_region(kvm, mem, old, new, change);
++ kvm_arch_commit_memory_region(kvm, mem, &old, new, change);
++
++ /* Free the old memslot's metadata. Note, this is the full copy!!! */
++ if (change == KVM_MR_DELETE)
++ kvm_free_memslot(kvm, &old);
+
+ kvfree(slots);
+ return 0;
+
+ out_slots:
+ if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
+- slot = id_to_memslot(slots, old->id);
++ slot = id_to_memslot(slots, new->id);
+ slot->flags &= ~KVM_MEMSLOT_INVALID;
+ slots = install_new_memslots(kvm, as_id, slots);
+ } else {
+@@ -1618,7 +1641,6 @@ static int kvm_delete_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *old, int as_id)
+ {
+ struct kvm_memory_slot new;
+- int r;
+
+ if (!old->npages)
+ return -EINVAL;
+@@ -1631,12 +1653,7 @@ static int kvm_delete_memslot(struct kvm *kvm,
+ */
+ new.as_id = as_id;
+
+- r = kvm_set_memslot(kvm, mem, old, &new, as_id, KVM_MR_DELETE);
+- if (r)
+- return r;
+-
+- kvm_free_memslot(kvm, old);
+- return 0;
++ return kvm_set_memslot(kvm, mem, &new, as_id, KVM_MR_DELETE);
+ }
+
+ /*
+@@ -1664,7 +1681,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
+ id = (u16)mem->slot;
+
+ /* General sanity checks */
+- if (mem->memory_size & (PAGE_SIZE - 1))
++ if ((mem->memory_size & (PAGE_SIZE - 1)) ||
++ (mem->memory_size != (unsigned long)mem->memory_size))
+ return -EINVAL;
+ if (mem->guest_phys_addr & (PAGE_SIZE - 1))
+ return -EINVAL;
+@@ -1710,7 +1728,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
+ if (!old.npages) {
+ change = KVM_MR_CREATE;
+ new.dirty_bitmap = NULL;
+- memset(&new.arch, 0, sizeof(new.arch));
+ } else { /* Modify an existing slot. */
+ if ((new.userspace_addr != old.userspace_addr) ||
+ (new.npages != old.npages) ||
+@@ -1724,9 +1741,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
+ else /* Nothing to change. */
+ return 0;
+
+- /* Copy dirty_bitmap and arch from the current memslot. */
++ /* Copy dirty_bitmap from the current memslot. */
+ new.dirty_bitmap = old.dirty_bitmap;
+- memcpy(&new.arch, &old.arch, sizeof(new.arch));
+ }
+
+ if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) {
+@@ -1752,7 +1768,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
+ bitmap_set(new.dirty_bitmap, 0, new.npages);
+ }
+
+- r = kvm_set_memslot(kvm, mem, &old, &new, as_id, change);
++ r = kvm_set_memslot(kvm, mem, &new, as_id, change);
+ if (r)
+ goto out_bitmap;
+
+@@ -2985,7 +3001,8 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
+ int r;
+ gpa_t gpa = ghc->gpa + offset;
+
+- BUG_ON(len + offset > ghc->len);
++ if (WARN_ON_ONCE(len + offset > ghc->len))
++ return -EINVAL;
+
+ if (slots->generation != ghc->generation) {
+ if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
+@@ -3022,7 +3039,8 @@ int kvm_read_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
+ int r;
+ gpa_t gpa = ghc->gpa + offset;
+
+- BUG_ON(len + offset > ghc->len);
++ if (WARN_ON_ONCE(len + offset > ghc->len))
++ return -EINVAL;
+
+ if (slots->generation != ghc->generation) {
+ if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
diff --git a/system/easy-kernel/0120-XATTR_USER_PREFIX.patch b/system/easy-kernel/0120-XATTR_USER_PREFIX.patch
new file mode 100644
index 000000000..245dcc29f
--- /dev/null
+++ b/system/easy-kernel/0120-XATTR_USER_PREFIX.patch
@@ -0,0 +1,67 @@
+From: Anthony G. Basile <blueness@gentoo.org>
+
+This patch adds support for a restricted user-controlled namespace on
+tmpfs filesystem used to house PaX flags. The namespace must be of the
+form user.pax.* and its value cannot exceed a size of 8 bytes.
+
+This is needed even on all Gentoo systems so that XATTR_PAX flags
+are preserved for users who might build packages using portage on
+a tmpfs system with a non-hardened kernel and then switch to a
+hardened kernel with XATTR_PAX enabled.
+
+The namespace is added to any user with Extended Attribute support
+enabled for tmpfs. Users who do not enable xattrs will not have
+the XATTR_PAX flags preserved.
+
+diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
+index 1590c49..5eab462 100644
+--- a/include/uapi/linux/xattr.h
++++ b/include/uapi/linux/xattr.h
+@@ -73,5 +73,9 @@
+ #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default"
+ #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
+
++/* User namespace */
++#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax."
++#define XATTR_PAX_FLAGS_SUFFIX "flags"
++#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX
+
+ #endif /* _UAPI_LINUX_XATTR_H */
+--- a/mm/shmem.c 2020-05-04 15:30:27.042035334 -0400
++++ b/mm/shmem.c 2020-05-04 15:34:57.013881725 -0400
+@@ -3238,6 +3238,14 @@ static int shmem_xattr_handler_set(const
+ struct shmem_inode_info *info = SHMEM_I(inode);
+
+ name = xattr_full_name(handler, name);
++
++ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
++ if (strcmp(name, XATTR_NAME_PAX_FLAGS))
++ return -EOPNOTSUPP;
++ if (size > 8)
++ return -EINVAL;
++ }
++
+ return simple_xattr_set(&info->xattrs, name, value, size, flags, NULL);
+ }
+
+@@ -3253,6 +3261,12 @@ static const struct xattr_handler shmem_
+ .set = shmem_xattr_handler_set,
+ };
+
++static const struct xattr_handler shmem_user_xattr_handler = {
++ .prefix = XATTR_USER_PREFIX,
++ .get = shmem_xattr_handler_get,
++ .set = shmem_xattr_handler_set,
++};
++
+ static const struct xattr_handler *shmem_xattr_handlers[] = {
+ #ifdef CONFIG_TMPFS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+@@ -3260,6 +3274,7 @@ static const struct xattr_handler *shmem
+ #endif
+ &shmem_security_xattr_handler,
+ &shmem_trusted_xattr_handler,
++ &shmem_user_xattr_handler,
+ NULL
+ };
+
diff --git a/system/easy-kernel/0122-link-security-restrictions.patch b/system/easy-kernel/0122-link-security-restrictions.patch
new file mode 100644
index 000000000..f0ed144fb
--- /dev/null
+++ b/system/easy-kernel/0122-link-security-restrictions.patch
@@ -0,0 +1,20 @@
+From: Ben Hutchings <ben@decadent.org.uk>
+Subject: fs: Enable link security restrictions by default
+Date: Fri, 02 Nov 2012 05:32:06 +0000
+Bug-Debian: https://bugs.debian.org/609455
+Forwarded: not-needed
+This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415
+('VFS: don't do protected {sym,hard}links by default').
+--- a/fs/namei.c 2018-09-28 07:56:07.770005006 -0400
++++ b/fs/namei.c 2018-09-28 07:56:43.370349204 -0400
+@@ -885,8 +885,8 @@ static inline void put_link(struct namei
+ path_put(&last->link);
+ }
+
+-int sysctl_protected_symlinks __read_mostly = 0;
+-int sysctl_protected_hardlinks __read_mostly = 0;
++int sysctl_protected_symlinks __read_mostly = 1;
++int sysctl_protected_hardlinks __read_mostly = 1;
+ int sysctl_protected_fifos __read_mostly;
+ int sysctl_protected_regular __read_mostly;
+
diff --git a/system/easy-kernel/0124-bluetooth-keysize-check.patch b/system/easy-kernel/0124-bluetooth-keysize-check.patch
new file mode 100644
index 000000000..394ad48fc
--- /dev/null
+++ b/system/easy-kernel/0124-bluetooth-keysize-check.patch
@@ -0,0 +1,37 @@
+The encryption is only mandatory to be enforced when both sides are using
+Secure Simple Pairing and this means the key size check makes only sense
+in that case.
+
+On legacy Bluetooth 2.0 and earlier devices like mice the encryption was
+optional and thus causing an issue if the key size check is not bound to
+using Secure Simple Pairing.
+
+Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections")
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Cc: stable@vger.kernel.org
+---
+ net/bluetooth/hci_conn.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 3cf0764d5793..7516cdde3373 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -1272,8 +1272,13 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
+ return 0;
+ }
+
+- if (hci_conn_ssp_enabled(conn) &&
+- !test_bit(HCI_CONN_ENCRYPT, &conn->flags))
++ /* If Secure Simple Pairing is not enabled, then legacy connection
++ * setup is used and no encryption or key sizes can be enforced.
++ */
++ if (!hci_conn_ssp_enabled(conn))
++ return 1;
++
++ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
+ return 0;
+
+ /* The minimum encryption key size needs to be enforced by the
+--
+2.20.1
diff --git a/system/easy-kernel/0126-sign-file-libressl.patch b/system/easy-kernel/0126-sign-file-libressl.patch
new file mode 100644
index 000000000..e6ec017d4
--- /dev/null
+++ b/system/easy-kernel/0126-sign-file-libressl.patch
@@ -0,0 +1,16 @@
+--- a/scripts/sign-file.c 2020-05-20 18:47:21.282820662 -0400
++++ b/scripts/sign-file.c 2020-05-20 18:48:37.991081899 -0400
+@@ -41,9 +41,10 @@
+ * signing with anything other than SHA1 - so we're stuck with that if such is
+ * the case.
+ */
+-#if defined(LIBRESSL_VERSION_NUMBER) || \
+- OPENSSL_VERSION_NUMBER < 0x10000000L || \
+- defined(OPENSSL_NO_CMS)
++#if defined(OPENSSL_NO_CMS) || \
++ ( defined(LIBRESSL_VERSION_NUMBER) \
++ && (LIBRESSL_VERSION_NUMBER < 0x3010000fL) ) || \
++ OPENSSL_VERSION_NUMBER < 0x10000000L
+ #define USE_PKCS7
+ #endif
+ #ifndef USE_PKCS7
diff --git a/system/easy-kernel/0130-lrng.patch b/system/easy-kernel/0130-lrng.patch
new file mode 100644
index 000000000..89d06d84c
--- /dev/null
+++ b/system/easy-kernel/0130-lrng.patch
@@ -0,0 +1,28362 @@
+diff -urN linux-5.15/MAINTAINERS linux-5.15-lrng/MAINTAINERS
+--- linux-5.15/MAINTAINERS 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/MAINTAINERS 2021-11-29 12:36:52.113279174 +1100
+@@ -10830,6 +10830,13 @@
+ F: Documentation/memory-barriers.txt
+ F: tools/memory-model/
+
++LINUX RANDOM NUMBER GENERATOR (LRNG) DRIVER
++M: Stephan Mueller <smueller@chronox.de>
++S: Maintained
++W: https://www.chronox.de/lrng.html
++F: drivers/char/lrng/*
++F: include/linux/lrng.h
++
+ LIS3LV02D ACCELEROMETER DRIVER
+ M: Eric Piel <eric.piel@tremplin-utc.net>
+ S: Maintained
+diff -urN linux-5.15/MAINTAINERS.orig linux-5.15-lrng/MAINTAINERS.orig
+--- linux-5.15/MAINTAINERS.orig 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/MAINTAINERS.orig 2021-11-29 12:32:21.653280206 +1100
+@@ -0,0 +1,20816 @@
++List of maintainers and how to submit kernel changes
++====================================================
++
++Please try to follow the guidelines below. This will make things
++easier on the maintainers. Not all of these guidelines matter for every
++trivial patch so apply some common sense.
++
++Tips for patch submitters
++-------------------------
++
++1. Always *test* your changes, however small, on at least 4 or
++ 5 people, preferably many more.
++
++2. Try to release a few ALPHA test versions to the net. Announce
++ them onto the kernel channel and await results. This is especially
++ important for device drivers, because often that's the only way
++ you will find things like the fact version 3 firmware needs
++ a magic fix you didn't know about, or some clown changed the
++ chips on a board and not its name. (Don't laugh! Look at the
++ SMC etherpower for that.)
++
++3. Make sure your changes compile correctly in multiple
++ configurations. In particular check that changes work both as a
++ module and built into the kernel.
++
++4. When you are happy with a change make it generally available for
++ testing and await feedback.
++
++5. Make a patch available to the relevant maintainer in the list. Use
++ ``diff -u`` to make the patch easy to merge. Be prepared to get your
++ changes sent back with seemingly silly requests about formatting
++ and variable names. These aren't as silly as they seem. One
++ job the maintainers (and especially Linus) do is to keep things
++ looking the same. Sometimes this means that the clever hack in
++ your driver to get around a problem actually needs to become a
++ generalized kernel feature ready for next time.
++
++ PLEASE check your patch with the automated style checker
++ (scripts/checkpatch.pl) to catch trivial style violations.
++ See Documentation/process/coding-style.rst for guidance here.
++
++ PLEASE CC: the maintainers and mailing lists that are generated
++ by ``scripts/get_maintainer.pl.`` The results returned by the
++ script will be best if you have git installed and are making
++ your changes in a branch derived from Linus' latest git tree.
++ See Documentation/process/submitting-patches.rst for details.
++
++ PLEASE try to include any credit lines you want added with the
++ patch. It avoids people being missed off by mistake and makes
++ it easier to know who wants adding and who doesn't.
++
++ PLEASE document known bugs. If it doesn't work for everything
++ or does something very odd once a month document it.
++
++ PLEASE remember that submissions must be made under the terms
++ of the Linux Foundation certificate of contribution and should
++ include a Signed-off-by: line. The current version of this
++ "Developer's Certificate of Origin" (DCO) is listed in the file
++ Documentation/process/submitting-patches.rst.
++
++6. Make sure you have the right to send any changes you make. If you
++ do changes at work you may find your employer owns the patch
++ not you.
++
++7. When sending security related changes or reports to a maintainer
++ please Cc: security@kernel.org, especially if the maintainer
++ does not respond. Please keep in mind that the security team is
++ a small set of people who can be efficient only when working on
++ verified bugs. Please only Cc: this list when you have identified
++ that the bug would present a short-term risk to other users if it
++ were publicly disclosed. For example, reports of address leaks do
++ not represent an immediate threat and are better handled publicly,
++ and ideally, should come with a patch proposal. Please do not send
++ automated reports to this list either. Such bugs will be handled
++ better and faster in the usual public places. See
++ Documentation/admin-guide/security-bugs.rst for details.
++
++8. Happy hacking.
++
++Descriptions of section entries and preferred order
++---------------------------------------------------
++
++ M: *Mail* patches to: FullName <address@domain>
++ R: Designated *Reviewer*: FullName <address@domain>
++ These reviewers should be CCed on patches.
++ L: *Mailing list* that is relevant to this area
++ S: *Status*, one of the following:
++ Supported: Someone is actually paid to look after this.
++ Maintained: Someone actually looks after it.
++ Odd Fixes: It has a maintainer but they don't have time to do
++ much other than throw the odd patch in. See below..
++ Orphan: No current maintainer [but maybe you could take the
++ role as you write your new code].
++ Obsolete: Old code. Something tagged obsolete generally means
++ it has been replaced by a better system and you
++ should be using that.
++ W: *Web-page* with status/info
++ Q: *Patchwork* web based patch tracking system site
++ B: URI for where to file *bugs*. A web-page with detailed bug
++ filing info, a direct bug tracker link, or a mailto: URI.
++ C: URI for *chat* protocol, server and channel where developers
++ usually hang out, for example irc://server/channel.
++ P: Subsystem Profile document for more details submitting
++ patches to the given subsystem. This is either an in-tree file,
++ or a URI. See Documentation/maintainer/maintainer-entry-profile.rst
++ for details.
++ T: *SCM* tree type and location.
++ Type is one of: git, hg, quilt, stgit, topgit
++ F: *Files* and directories wildcard patterns.
++ A trailing slash includes all files and subdirectory files.
++ F: drivers/net/ all files in and below drivers/net
++ F: drivers/net/* all files in drivers/net, but not below
++ F: */net/* all files in "any top level directory"/net
++ One pattern per line. Multiple F: lines acceptable.
++ X: *Excluded* files and directories that are NOT maintained, same
++ rules as F:. Files exclusions are tested before file matches.
++ Can be useful for excluding a specific subdirectory, for instance:
++ F: net/
++ X: net/ipv6/
++ matches all files in and below net excluding net/ipv6/
++ N: Files and directories *Regex* patterns.
++ N: [^a-z]tegra all files whose path contains tegra
++ (not including files like integrator)
++ One pattern per line. Multiple N: lines acceptable.
++ scripts/get_maintainer.pl has different behavior for files that
++ match F: pattern and matches of N: patterns. By default,
++ get_maintainer will not look at git log history when an F: pattern
++ match occurs. When an N: match occurs, git log history is used
++ to also notify the people that have git commit signatures.
++ K: *Content regex* (perl extended) pattern match in a patch or file.
++ For instance:
++ K: of_get_profile
++ matches patches or files that contain "of_get_profile"
++ K: \b(printk|pr_(info|err))\b
++ matches patches or files that contain one or more of the words
++ printk, pr_info or pr_err
++ One regex pattern per line. Multiple K: lines acceptable.
++
++Maintainers List
++----------------
++
++.. note:: When reading this list, please look for the most precise areas
++ first. When adding to this list, please keep the entries in
++ alphabetical order.
++
++3C59X NETWORK DRIVER
++M: Steffen Klassert <klassert@kernel.org>
++L: netdev@vger.kernel.org
++S: Odd Fixes
++F: Documentation/networking/device_drivers/ethernet/3com/vortex.rst
++F: drivers/net/ethernet/3com/3c59x.c
++
++3CR990 NETWORK DRIVER
++M: David Dillow <dave@thedillows.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/3com/typhoon*
++
++3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
++M: Adam Radford <aradford@gmail.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.lsi.com
++F: drivers/scsi/3w-*
++
++53C700 AND 53C700-66 SCSI DRIVER
++M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/53c700*
++
++6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
++M: Alexander Aring <alex.aring@gmail.com>
++M: Jukka Rissanen <jukka.rissanen@linux.intel.com>
++L: linux-bluetooth@vger.kernel.org
++L: linux-wpan@vger.kernel.org
++S: Maintained
++F: Documentation/networking/6lowpan.rst
++F: include/net/6lowpan.h
++F: net/6lowpan/
++
++6PACK NETWORK DRIVER FOR AX.25
++M: Andreas Koensgen <ajk@comnets.uni-bremen.de>
++L: linux-hams@vger.kernel.org
++S: Maintained
++F: drivers/net/hamradio/6pack.c
++
++802.11 (including CFG80211/NL80211)
++M: Johannes Berg <johannes@sipsolutions.net>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
++F: Documentation/driver-api/80211/cfg80211.rst
++F: Documentation/networking/regulatory.rst
++F: include/linux/ieee80211.h
++F: include/net/cfg80211.h
++F: include/net/ieee80211_radiotap.h
++F: include/net/iw_handler.h
++F: include/net/wext.h
++F: include/uapi/linux/nl80211.h
++F: net/wireless/
++
++8169 10/100/1000 GIGABIT ETHERNET DRIVER
++M: Heiner Kallweit <hkallweit1@gmail.com>
++M: nic_swsd@realtek.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/realtek/r8169*
++
++8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-serial@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
++F: drivers/tty/serial/8250*
++F: include/linux/serial_8250.h
++
++8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
++L: netdev@vger.kernel.org
++S: Orphan / Obsolete
++F: drivers/net/ethernet/8390/
++
++9P FILE SYSTEM
++M: Eric Van Hensbergen <ericvh@gmail.com>
++M: Latchesar Ionkov <lucho@ionkov.net>
++M: Dominique Martinet <asmadeus@codewreck.org>
++L: v9fs-developer@lists.sourceforge.net
++S: Maintained
++W: http://swik.net/v9fs
++Q: http://patchwork.kernel.org/project/v9fs-devel/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git
++T: git git://github.com/martinetd/linux.git
++F: Documentation/filesystems/9p.rst
++F: fs/9p/
++F: include/net/9p/
++F: include/trace/events/9p.h
++F: include/uapi/linux/virtio_9p.h
++F: net/9p/
++
++A8293 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/a8293*
++
++AACRAID SCSI RAID DRIVER
++M: Adaptec OEM Raid Solutions <aacraid@microsemi.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.adaptec.com/
++F: Documentation/scsi/aacraid.rst
++F: drivers/scsi/aacraid/
++
++ABI/API
++L: linux-api@vger.kernel.org
++F: include/linux/syscalls.h
++F: kernel/sys_ni.c
++X: include/uapi/
++X: arch/*/include/uapi/
++
++ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/abituguru.c
++
++ABIT UGURU 3 HARDWARE MONITOR DRIVER
++M: Alistair John Strachan <alistair@devzero.co.uk>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/abituguru3.c
++
++ACCES 104-DIO-48E GPIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-104-dio-48e.c
++
++ACCES 104-IDI-48 GPIO DRIVER
++M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-104-idi-48.c
++
++ACCES 104-IDIO-16 GPIO DRIVER
++M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-104-idio-16.c
++
++ACCES 104-QUAD-8 DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++M: Syed Nayyar Waris <syednwaris@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/counter/104-quad-8.c
++
++ACCES PCI-IDIO-16 GPIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-pci-idio-16.c
++
++ACCES PCIe-IDIO-24 GPIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-pcie-idio-24.c
++
++ACENIC DRIVER
++M: Jes Sorensen <jes@trained-monkey.org>
++L: linux-acenic@sunsite.dk
++S: Maintained
++F: drivers/net/ethernet/alteon/acenic*
++
++ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
++M: Peter Kaestle <peter@piie.net>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://piie.net/?section=acerhdf
++F: drivers/platform/x86/acerhdf.c
++
++ACER WMI LAPTOP EXTRAS
++M: "Lee, Chun-Yi" <jlee@suse.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/acer-wmi.c
++
++ACPI
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Len Brown <lenb@kernel.org>
++L: linux-acpi@vger.kernel.org
++S: Supported
++W: https://01.org/linux-acpi
++Q: https://patchwork.kernel.org/project/linux-acpi/list/
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
++F: Documentation/ABI/testing/configfs-acpi
++F: Documentation/ABI/testing/sysfs-bus-acpi
++F: Documentation/firmware-guide/acpi/
++F: drivers/acpi/
++F: drivers/pci/*/*acpi*
++F: drivers/pci/*acpi*
++F: drivers/pnp/pnpacpi/
++F: include/acpi/
++F: include/linux/acpi.h
++F: include/linux/fwnode.h
++F: tools/power/acpi/
++
++ACPI APEI
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Len Brown <lenb@kernel.org>
++R: James Morse <james.morse@arm.com>
++R: Tony Luck <tony.luck@intel.com>
++R: Borislav Petkov <bp@alien8.de>
++L: linux-acpi@vger.kernel.org
++F: drivers/acpi/apei/
++
++ACPI COMPONENT ARCHITECTURE (ACPICA)
++M: Robert Moore <robert.moore@intel.com>
++M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
++L: linux-acpi@vger.kernel.org
++L: devel@acpica.org
++S: Supported
++W: https://acpica.org/
++W: https://github.com/acpica/acpica/
++Q: https://patchwork.kernel.org/project/linux-acpi/list/
++B: https://bugzilla.kernel.org
++B: https://bugs.acpica.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
++F: drivers/acpi/acpica/
++F: include/acpi/
++F: tools/power/acpi/
++
++ACPI FAN DRIVER
++M: Zhang Rui <rui.zhang@intel.com>
++L: linux-acpi@vger.kernel.org
++S: Supported
++W: https://01.org/linux-acpi
++B: https://bugzilla.kernel.org
++F: drivers/acpi/fan.c
++
++ACPI FOR ARM64 (ACPI/arm64)
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++M: Hanjun Guo <guohanjun@huawei.com>
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-acpi@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/acpi/arm64
++
++ACPI I2C MULTI INSTANTIATE DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/i2c-multi-instantiate.c
++
++ACPI PMIC DRIVERS
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Len Brown <lenb@kernel.org>
++R: Andy Shevchenko <andy@kernel.org>
++R: Mika Westerberg <mika.westerberg@linux.intel.com>
++L: linux-acpi@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-acpi/list/
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
++F: drivers/acpi/pmic/
++
++ACPI THERMAL DRIVER
++M: Rafael J. Wysocki <rafael@kernel.org>
++R: Zhang Rui <rui.zhang@intel.com>
++L: linux-acpi@vger.kernel.org
++S: Supported
++W: https://01.org/linux-acpi
++B: https://bugzilla.kernel.org
++F: drivers/acpi/*thermal*
++
++ACPI VIDEO DRIVER
++M: Zhang Rui <rui.zhang@intel.com>
++L: linux-acpi@vger.kernel.org
++S: Supported
++W: https://01.org/linux-acpi
++B: https://bugzilla.kernel.org
++F: drivers/acpi/acpi_video.c
++
++ACPI VIOT DRIVER
++M: Jean-Philippe Brucker <jean-philippe@linaro.org>
++L: linux-acpi@vger.kernel.org
++L: iommu@lists.linux-foundation.org
++S: Maintained
++F: drivers/acpi/viot.c
++F: include/linux/acpi_viot.h
++
++ACPI WMI DRIVER
++L: platform-driver-x86@vger.kernel.org
++S: Orphan
++F: drivers/platform/x86/wmi.c
++F: include/uapi/linux/wmi.h
++
++ACRN HYPERVISOR SERVICE MODULE
++M: Fei Li <fei1.li@intel.com>
++L: acrn-dev@lists.projectacrn.org (subscribers-only)
++S: Supported
++W: https://projectacrn.org
++F: Documentation/virt/acrn/
++F: drivers/virt/acrn/
++F: include/uapi/linux/acrn.h
++
++AD1889 ALSA SOUND DRIVER
++L: linux-parisc@vger.kernel.org
++S: Maintained
++W: https://parisc.wiki.kernel.org/index.php/AD1889
++F: sound/pci/ad1889.*
++
++AD5110 ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
++M: Mugilraj Dhavachelvan <dmugil2000@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: drivers/iio/potentiometer/ad5110.c
++
++AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/AD5254
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/misc/ad525x_dpot.c
++
++AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/AD5398
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/regulator/ad5398.c
++
++AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/AD7142
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/input/misc/ad714x.c
++
++AD7877 TOUCHSCREEN DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/AD7877
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/input/touchscreen/ad7877.c
++
++AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/AD7879
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/input/touchscreen/ad7879.c
++
++ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
++M: Jiri Kosina <jikos@kernel.org>
++S: Maintained
++
++ADF7242 IEEE 802.15.4 RADIO DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++L: linux-wpan@vger.kernel.org
++S: Supported
++W: https://wiki.analog.com/ADF7242
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
++F: drivers/net/ieee802154/adf7242.c
++
++ADM1025 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/adm1025.rst
++F: drivers/hwmon/adm1025.c
++
++ADM1029 HARDWARE MONITOR DRIVER
++M: Corentin Labbe <clabbe.montjoie@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/adm1029.c
++
++ADM8211 WIRELESS DRIVER
++L: linux-wireless@vger.kernel.org
++S: Orphan
++W: https://wireless.wiki.kernel.org/
++F: drivers/net/wireless/admtek/adm8211.*
++
++ADP1653 FLASH CONTROLLER DRIVER
++M: Sakari Ailus <sakari.ailus@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/adp1653.c
++F: include/media/i2c/adp1653.h
++
++ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/ADP5520
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/gpio/gpio-adp5520.c
++F: drivers/input/keyboard/adp5520-keys.c
++F: drivers/leds/leds-adp5520.c
++F: drivers/mfd/adp5520.c
++F: drivers/video/backlight/adp5520_bl.c
++
++ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/ADP5588
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/gpio/gpio-adp5588.c
++F: drivers/input/keyboard/adp5588-keys.c
++
++ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/ADP8860
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/video/backlight/adp8860_bl.c
++
++ADT746X FAN DRIVER
++M: Colin Leroy <colin@colino.net>
++S: Maintained
++F: drivers/macintosh/therm_adt746x.c
++
++ADT7475 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/adt7475.rst
++F: drivers/hwmon/adt7475.c
++
++ADVANSYS SCSI DRIVER
++M: Matthew Wilcox <willy@infradead.org>
++M: Hannes Reinecke <hare@suse.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: Documentation/scsi/advansys.rst
++F: drivers/scsi/advansys.c
++
++ADVANTECH SWBTN DRIVER
++M: Andrea Ho <Andrea.Ho@advantech.com.tw>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/adv_swbutton.c
++
++ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/ADXL345
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
++F: drivers/input/misc/adxl34x.c
++
++ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
++F: drivers/iio/accel/adxl372.c
++F: drivers/iio/accel/adxl372_i2c.c
++F: drivers/iio/accel/adxl372_spi.c
++
++AF9013 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/af9013*
++
++AF9033 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/af9033*
++
++AFFS FILE SYSTEM
++M: David Sterba <dsterba@suse.com>
++L: linux-fsdevel@vger.kernel.org
++S: Odd Fixes
++F: Documentation/filesystems/affs.rst
++F: fs/affs/
++
++AFS FILESYSTEM
++M: David Howells <dhowells@redhat.com>
++M: Marc Dionne <marc.dionne@auristor.com>
++L: linux-afs@lists.infradead.org
++S: Supported
++W: https://www.infradead.org/~dhowells/kafs/
++F: Documentation/filesystems/afs.rst
++F: fs/afs/
++F: include/trace/events/afs.h
++
++AGPGART DRIVER
++M: David Airlie <airlied@linux.ie>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm
++F: drivers/char/agp/
++F: include/linux/agp*
++F: include/uapi/linux/agp*
++
++AHA152X SCSI DRIVER
++M: "Juergen E. Fischer" <fischer@norbit.de>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/aha152x*
++F: drivers/scsi/pcmcia/aha152x*
++
++AIC7XXX / AIC79XX SCSI DRIVER
++M: Hannes Reinecke <hare@suse.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/aic7xxx/
++
++AIMSLAB FM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-aimslab*
++
++AIO
++M: Benjamin LaHaise <bcrl@kvack.org>
++L: linux-aio@kvack.org
++S: Supported
++F: fs/aio.c
++F: include/linux/*aio*.h
++
++AIRSPY MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/airspy/
++
++ALACRITECH GIGABIT ETHERNET DRIVER
++M: Lino Sanfilippo <LinoSanfilippo@gmx.de>
++S: Maintained
++F: drivers/net/ethernet/alacritech/*
++
++ALCATEL SPEEDTOUCH USB DRIVER
++M: Duncan Sands <duncan.sands@free.fr>
++L: linux-usb@vger.kernel.org
++S: Maintained
++W: http://www.linux-usb.org/SpeedTouch/
++F: drivers/usb/atm/speedtch.c
++F: drivers/usb/atm/usbatm.c
++
++ALCHEMY AU1XX0 MMC DRIVER
++M: Manuel Lauss <manuel.lauss@gmail.com>
++S: Maintained
++F: drivers/mmc/host/au1xmmc.c
++
++ALI1563 I2C DRIVER
++M: Rudolf Marek <r.marek@assembler.cz>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/i2c/busses/i2c-ali1563.rst
++F: drivers/i2c/busses/i2c-ali1563.c
++
++ALIENWARE WMI DRIVER
++L: Dell.Client.Kernel@dell.com
++S: Maintained
++F: drivers/platform/x86/dell/alienware-wmi.c
++
++ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
++M: Tomislav Denis <tomislav.denis@avl.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++W: http://www.allsensors.com/
++F: Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml
++F: drivers/iio/pressure/dlhl60d.c
++
++ALLEGRO DVT VIDEO IP CORE DRIVER
++M: Michael Tretter <m.tretter@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/allegro,al5e.yaml
++F: drivers/media/platform/allegro-dvt/
++
++ALLWINNER A10 CSI DRIVER
++M: Maxime Ripard <mripard@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
++F: drivers/media/platform/sunxi/sun4i-csi/
++
++ALLWINNER CPUFREQ DRIVER
++M: Yangtao Li <tiny.windzz@gmail.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
++F: drivers/cpufreq/sun50i-cpufreq-nvmem.c
++
++ALLWINNER CRYPTO DRIVERS
++M: Corentin Labbe <clabbe.montjoie@gmail.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/allwinner/
++
++ALLWINNER HARDWARE SPINLOCK SUPPORT
++M: Wilken Gottwalt <wilken.gottwalt@posteo.net>
++S: Maintained
++F: Documentation/devicetree/bindings/hwlock/allwinner,sun6i-hwspinlock.yaml
++F: drivers/hwspinlock/sun6i_hwspinlock.c
++
++ALLWINNER THERMAL DRIVER
++M: Vasily Khoruzhick <anarsoul@gmail.com>
++M: Yangtao Li <tiny.windzz@gmail.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml
++F: drivers/thermal/sun8i_thermal.c
++
++ALLWINNER VPU DRIVER
++M: Maxime Ripard <mripard@kernel.org>
++M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/staging/media/sunxi/cedrus/
++
++ALPHA PORT
++M: Richard Henderson <rth@twiddle.net>
++M: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
++M: Matt Turner <mattst88@gmail.com>
++L: linux-alpha@vger.kernel.org
++S: Odd Fixes
++F: arch/alpha/
++
++ALPS PS/2 TOUCHPAD DRIVER
++R: Pali Rohár <pali@kernel.org>
++F: drivers/input/mouse/alps.*
++
++ALTERA I2C CONTROLLER DRIVER
++M: Thor Thayer <thor.thayer@linux.intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-altera.txt
++F: drivers/i2c/busses/i2c-altera.c
++
++ALTERA MAILBOX DRIVER
++M: Joyce Ooi <joyce.ooi@intel.com>
++S: Maintained
++F: drivers/mailbox/mailbox-altera.c
++
++ALTERA MSGDMA IP CORE DRIVER
++M: Olivier Dautricourt <olivier.dautricourt@orolia.com>
++R: Stefan Roese <sr@denx.de>
++L: dmaengine@vger.kernel.org
++S: Odd Fixes
++F: Documentation/devicetree/bindings/dma/altr,msgdma.yaml
++F: drivers/dma/altera-msgdma.c
++
++ALTERA PIO DRIVER
++M: Mun Yew Tham <mun.yew.tham@intel.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-altera.c
++
++ALTERA SYSTEM MANAGER DRIVER
++M: Thor Thayer <thor.thayer@linux.intel.com>
++S: Maintained
++F: drivers/mfd/altera-sysmgr.c
++F: include/linux/mfd/altera-sysmgr.h
++
++ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT
++M: Thor Thayer <thor.thayer@linux.intel.com>
++S: Maintained
++F: drivers/gpio/gpio-altera-a10sr.c
++F: drivers/mfd/altera-a10sr.c
++F: drivers/reset/reset-a10sr.c
++F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h
++F: include/linux/mfd/altera-a10sr.h
++
++ALTERA TRIPLE SPEED ETHERNET DRIVER
++M: Joyce Ooi <joyce.ooi@intel.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/altera/
++
++ALTERA UART/JTAG UART SERIAL DRIVERS
++M: Tobias Klauser <tklauser@distanz.ch>
++L: linux-serial@vger.kernel.org
++S: Maintained
++F: drivers/tty/serial/altera_jtaguart.c
++F: drivers/tty/serial/altera_uart.c
++F: include/linux/altera_jtaguart.h
++F: include/linux/altera_uart.h
++
++AMAZON ANNAPURNA LABS FIC DRIVER
++M: Talel Shenhar <talel@amazon.com>
++S: Maintained
++F: Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
++F: drivers/irqchip/irq-al-fic.c
++
++AMAZON ANNAPURNA LABS MEMORY CONTROLLER EDAC
++M: Talel Shenhar <talel@amazon.com>
++M: Talel Shenhar <talelshenhar@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml
++F: drivers/edac/al_mc_edac.c
++
++AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER
++M: Talel Shenhar <talel@amazon.com>
++S: Maintained
++F: Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt
++F: drivers/thermal/thermal_mmio.c
++
++AMAZON ETHERNET DRIVERS
++M: Netanel Belgazal <netanel@amazon.com>
++M: Arthur Kiyanovski <akiyano@amazon.com>
++R: Guy Tzalik <gtzalik@amazon.com>
++R: Saeed Bishara <saeedb@amazon.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/ethernet/amazon/ena.rst
++F: drivers/net/ethernet/amazon/
++
++AMAZON RDMA EFA DRIVER
++M: Gal Pressman <galpress@amazon.com>
++R: Yossi Leybovich <sleybo@amazon.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/hw/efa/
++F: include/uapi/rdma/efa-abi.h
++
++AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER
++M: Tom Lendacky <thomas.lendacky@amd.com>
++M: John Allen <john.allen@amd.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++F: drivers/crypto/ccp/
++F: include/linux/ccp.h
++
++AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER - SEV SUPPORT
++M: Brijesh Singh <brijesh.singh@amd.com>
++M: Tom Lendacky <thomas.lendacky@amd.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++F: drivers/crypto/ccp/sev*
++F: include/uapi/linux/psp-sev.h
++
++AMD DISPLAY CORE
++M: Harry Wentland <harry.wentland@amd.com>
++M: Leo Li <sunpeng.li@amd.com>
++L: amd-gfx@lists.freedesktop.org
++S: Supported
++T: git https://gitlab.freedesktop.org/agd5f/linux.git
++F: drivers/gpu/drm/amd/display/
++
++AMD FAM15H PROCESSOR POWER MONITORING DRIVER
++M: Huang Rui <ray.huang@amd.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++F: Documentation/hwmon/fam15h_power.rst
++F: drivers/hwmon/fam15h_power.c
++
++AMD FCH GPIO DRIVER
++M: Enrico Weigelt, metux IT consult <info@metux.net>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-amd-fch.c
++F: include/linux/platform_data/gpio/gpio-amd-fch.h
++
++AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
++L: linux-geode@lists.infradead.org (moderated for non-subscribers)
++S: Orphan
++F: drivers/usb/gadget/udc/amd5536udc.*
++
++AMD GEODE PROCESSOR/CHIPSET SUPPORT
++M: Andres Salomon <dilinger@queued.net>
++L: linux-geode@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
++F: arch/x86/include/asm/geode.h
++F: drivers/char/hw_random/geode-rng.c
++F: drivers/crypto/geode*
++F: drivers/video/fbdev/geode/
++
++AMD IOMMU (AMD-VI)
++M: Joerg Roedel <joro@8bytes.org>
++R: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
++L: iommu@lists.linux-foundation.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
++F: drivers/iommu/amd/
++F: include/linux/amd-iommu.h
++
++AMD KFD
++M: Felix Kuehling <Felix.Kuehling@amd.com>
++L: amd-gfx@lists.freedesktop.org
++S: Supported
++T: git https://gitlab.freedesktop.org/agd5f/linux.git
++F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd*.[ch]
++F: drivers/gpu/drm/amd/amdkfd/
++F: drivers/gpu/drm/amd/include/cik_structs.h
++F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h
++F: drivers/gpu/drm/amd/include/v9_structs.h
++F: drivers/gpu/drm/amd/include/vi_structs.h
++F: include/uapi/linux/kfd_ioctl.h
++
++AMD SPI DRIVER
++M: Sanjay R Mehta <sanju.mehta@amd.com>
++S: Maintained
++F: drivers/spi/spi-amd.c
++
++AMD MP2 I2C DRIVER
++M: Elie Morisse <syniurge@gmail.com>
++M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
++M: Shyam Sundar S K <shyam-sundar.s-k@amd.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-amd-mp2*
++
++AMD PMC DRIVER
++M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/amd-pmc.*
++
++AMD POWERPLAY AND SWSMU
++M: Evan Quan <evan.quan@amd.com>
++L: amd-gfx@lists.freedesktop.org
++S: Supported
++T: git https://gitlab.freedesktop.org/agd5f/linux.git
++F: drivers/gpu/drm/amd/pm/
++
++AMD PTDMA DRIVER
++M: Sanjay R Mehta <sanju.mehta@amd.com>
++L: dmaengine@vger.kernel.org
++S: Maintained
++F: drivers/dma/ptdma/
++
++AMD SEATTLE DEVICE TREE SUPPORT
++M: Brijesh Singh <brijeshkumar.singh@amd.com>
++M: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
++M: Tom Lendacky <thomas.lendacky@amd.com>
++S: Supported
++F: arch/arm64/boot/dts/amd/
++
++AMD XGBE DRIVER
++M: Tom Lendacky <thomas.lendacky@amd.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
++F: drivers/net/ethernet/amd/xgbe/
++
++AMD SENSOR FUSION HUB DRIVER
++M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
++M: Basavaraj Natikar <basavaraj.natikar@amd.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/hid/amd-sfh*
++F: drivers/hid/amd-sfh-hid/
++
++AMS AS73211 DRIVER
++M: Christian Eggers <ceggers@arri.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
++F: drivers/iio/light/as73211.c
++
++ANALOG DEVICES INC AD7192 DRIVER
++M: Alexandru Tachici <alexandru.tachici@analog.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
++F: drivers/iio/adc/ad7192.c
++
++ANALOG DEVICES INC AD7292 DRIVER
++M: Marcelo Schmitt <marcelo.schmitt1@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
++F: drivers/iio/adc/ad7292.c
++
++ANALOG DEVICES INC AD7768-1 DRIVER
++M: Michael Hennerich <Michael.Hennerich@analog.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
++F: drivers/iio/adc/ad7768-1.c
++
++ANALOG DEVICES INC AD7780 DRIVER
++M: Michael Hennerich <Michael.Hennerich@analog.com>
++M: Renato Lui Geh <renatogeh@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
++F: drivers/iio/adc/ad7780.c
++
++ANALOG DEVICES INC AD9389B DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/ad9389b*
++
++ANALOG DEVICES INC ADGS1408 DRIVER
++M: Mircea Caprioru <mircea.caprioru@analog.com>
++S: Supported
++F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt
++F: drivers/mux/adgs1408.c
++
++ANALOG DEVICES INC ADIN DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/net/adi,adin.yaml
++F: drivers/net/phy/adin.c
++
++ANALOG DEVICES INC ADIS DRIVER LIBRARY
++M: Nuno Sa <nuno.sa@analog.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: drivers/iio/imu/adis.c
++F: include/linux/iio/imu/adis.h
++
++ANALOG DEVICES INC ADIS16460 DRIVER
++M: Dragos Bogdan <dragos.bogdan@analog.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
++F: drivers/iio/imu/adis16460.c
++
++ANALOG DEVICES INC ADIS16475 DRIVER
++M: Nuno Sa <nuno.sa@analog.com>
++L: linux-iio@vger.kernel.org
++W: http://ez.analog.com/community/linux-device-drivers
++S: Supported
++F: drivers/iio/imu/adis16475.c
++F: Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
++
++ANALOG DEVICES INC ADM1177 DRIVER
++M: Michael Hennerich <Michael.Hennerich@analog.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml
++F: drivers/hwmon/adm1177.c
++
++ANALOG DEVICES INC ADP5061 DRIVER
++M: Michael Hennerich <Michael.Hennerich@analog.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/power/supply/adp5061.c
++
++ANALOG DEVICES INC ADV7180 DRIVER
++M: Lars-Peter Clausen <lars@metafoo.de>
++L: linux-media@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/media/i2c/adv7180.c
++F: Documentation/devicetree/bindings/media/i2c/adv7180.yaml
++
++ANALOG DEVICES INC ADV748X DRIVER
++M: Kieran Bingham <kieran.bingham@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/adv748x/*
++
++ANALOG DEVICES INC ADV7511 DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/adv7511*
++
++ANALOG DEVICES INC ADV7604 DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/adv7604*
++F: Documentation/devicetree/bindings/media/i2c/adv7604.yaml
++
++ANALOG DEVICES INC ADV7842 DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/adv7842*
++
++ANALOG DEVICES INC ADXRS290 DRIVER
++M: Nishant Malpani <nish.malpani25@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: drivers/iio/gyro/adxrs290.c
++F: Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml
++
++ANALOG DEVICES INC ASOC CODEC DRIVERS
++M: Lars-Peter Clausen <lars@metafoo.de>
++M: Nuno Sá <nuno.sa@analog.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++W: http://wiki.analog.com/
++W: http://ez.analog.com/community/linux-device-drivers
++F: sound/soc/codecs/ad1*
++F: sound/soc/codecs/ad7*
++F: sound/soc/codecs/adau*
++F: sound/soc/codecs/adav*
++F: sound/soc/codecs/sigmadsp.*
++F: sound/soc/codecs/ssm*
++
++ANALOG DEVICES INC DMA DRIVERS
++M: Lars-Peter Clausen <lars@metafoo.de>
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: drivers/dma/dma-axi-dmac.c
++
++ANALOG DEVICES INC IIO DRIVERS
++M: Lars-Peter Clausen <lars@metafoo.de>
++M: Michael Hennerich <Michael.Hennerich@analog.com>
++S: Supported
++W: http://wiki.analog.com/
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
++F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
++F: Documentation/devicetree/bindings/iio/*/adi,*
++F: Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml
++F: drivers/iio/*/ad*
++F: drivers/iio/adc/ltc249*
++F: drivers/iio/amplifiers/hmc425a.c
++F: drivers/staging/iio/*/ad*
++X: drivers/iio/*/adjd*
++
++ANALOGBITS PLL LIBRARIES
++M: Paul Walmsley <paul.walmsley@sifive.com>
++S: Supported
++F: drivers/clk/analogbits/*
++F: include/linux/clk/analogbits*
++
++ANDES ARCHITECTURE
++M: Nick Hu <nickhu@andestech.com>
++M: Greentime Hu <green.hu@gmail.com>
++M: Vincent Chen <deanbo422@gmail.com>
++S: Supported
++T: git https://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux.git
++F: Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
++F: Documentation/devicetree/bindings/nds32/
++F: arch/nds32/
++N: nds32
++K: nds32
++
++ANDROID CONFIG FRAGMENTS
++M: Rob Herring <robh@kernel.org>
++S: Supported
++F: kernel/configs/android*
++
++ANDROID DRIVERS
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++M: Arve Hjønnevåg <arve@android.com>
++M: Todd Kjos <tkjos@android.com>
++M: Martijn Coenen <maco@android.com>
++M: Joel Fernandes <joel@joelfernandes.org>
++M: Christian Brauner <christian@brauner.io>
++M: Hridya Valsaraju <hridya@google.com>
++M: Suren Baghdasaryan <surenb@google.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
++F: drivers/android/
++F: drivers/staging/android/
++
++ANDROID GOLDFISH PIC DRIVER
++M: Miodrag Dinic <miodrag.dinic@mips.com>
++S: Supported
++F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt
++F: drivers/irqchip/irq-goldfish-pic.c
++
++ANDROID GOLDFISH RTC DRIVER
++M: Jiaxun Yang <jiaxun.yang@flygoat.com>
++S: Supported
++F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
++F: drivers/rtc/rtc-goldfish.c
++
++AOA (Apple Onboard Audio) ALSA DRIVER
++M: Johannes Berg <johannes@sipsolutions.net>
++L: linuxppc-dev@lists.ozlabs.org
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: sound/aoa/
++
++APEX EMBEDDED SYSTEMS STX104 IIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/iio/adc/stx104.c
++
++APM DRIVER
++M: Jiri Kosina <jikos@kernel.org>
++S: Odd fixes
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/apm.git
++F: arch/x86/kernel/apm_32.c
++F: drivers/char/apm-emulation.c
++F: include/linux/apm_bios.h
++F: include/uapi/linux/apm_bios.h
++
++APPARMOR SECURITY MODULE
++M: John Johansen <john.johansen@canonical.com>
++L: apparmor@lists.ubuntu.com (subscribers-only, general discussion)
++S: Supported
++W: wiki.apparmor.net
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
++F: Documentation/admin-guide/LSM/apparmor.rst
++F: security/apparmor/
++
++APPLE BCM5974 MULTITOUCH DRIVER
++M: Henrik Rydberg <rydberg@bitmath.org>
++L: linux-input@vger.kernel.org
++S: Odd fixes
++F: drivers/input/mouse/bcm5974.c
++
++APPLE DART IOMMU DRIVER
++M: Sven Peter <sven@svenpeter.dev>
++R: Alyssa Rosenzweig <alyssa@rosenzweig.io>
++L: iommu@lists.linux-foundation.org
++S: Maintained
++F: Documentation/devicetree/bindings/iommu/apple,dart.yaml
++F: drivers/iommu/apple-dart.c
++
++APPLE SMC DRIVER
++M: Henrik Rydberg <rydberg@bitmath.org>
++L: linux-hwmon@vger.kernel.org
++S: Odd fixes
++F: drivers/hwmon/applesmc.c
++
++APPLETALK NETWORK LAYER
++L: netdev@vger.kernel.org
++S: Odd fixes
++F: drivers/net/appletalk/
++F: include/linux/atalk.h
++F: include/uapi/linux/atalk.h
++F: net/appletalk/
++
++APPLIED MICRO (APM) X-GENE DEVICE TREE SUPPORT
++M: Khuong Dinh <khuong@os.amperecomputing.com>
++S: Supported
++F: arch/arm64/boot/dts/apm/
++
++APPLIED MICRO (APM) X-GENE SOC EDAC
++M: Khuong Dinh <khuong@os.amperecomputing.com>
++S: Supported
++F: Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
++F: drivers/edac/xgene_edac.c
++
++APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
++M: Iyappan Subramanian <iyappan@os.amperecomputing.com>
++M: Keyur Chudgar <keyur@os.amperecomputing.com>
++S: Supported
++F: drivers/net/ethernet/apm/xgene-v2/
++
++APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
++M: Iyappan Subramanian <iyappan@os.amperecomputing.com>
++M: Keyur Chudgar <keyur@os.amperecomputing.com>
++M: Quan Nguyen <quan@os.amperecomputing.com>
++S: Supported
++F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
++F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
++F: drivers/net/ethernet/apm/xgene/
++F: drivers/net/mdio/mdio-xgene.c
++
++APPLIED MICRO (APM) X-GENE SOC PMU
++M: Khuong Dinh <khuong@os.amperecomputing.com>
++S: Supported
++F: Documentation/admin-guide/perf/xgene-pmu.rst
++F: Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
++F: drivers/perf/xgene_pmu.c
++
++APTINA CAMERA SENSOR PLL
++M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/aptina-pll.*
++
++AQUACOMPUTER D5 NEXT PUMP SENSOR DRIVER
++M: Aleksa Savic <savicaleksa83@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/aquacomputer_d5next.rst
++F: drivers/hwmon/aquacomputer_d5next.c
++
++AQUANTIA ETHERNET DRIVER (atlantic)
++M: Igor Russkikh <irusskikh@marvell.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: https://www.marvell.com/
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst
++F: drivers/net/ethernet/aquantia/atlantic/
++
++AQUANTIA ETHERNET DRIVER PTP SUBSYSTEM
++M: Egor Pomozov <epomozov@marvell.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.aquantia.com
++F: drivers/net/ethernet/aquantia/atlantic/aq_ptp*
++
++ARASAN NAND CONTROLLER DRIVER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++M: Naga Sureshkumar Relli <nagasure@xilinx.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml
++F: drivers/mtd/nand/raw/arasan-nand-controller.c
++
++ARC FRAMEBUFFER DRIVER
++M: Jaya Kumar <jayalk@intworks.biz>
++S: Maintained
++F: drivers/video/fbdev/arcfb.c
++F: drivers/video/fbdev/core/fb_defio.c
++
++ARC PGU DRM DRIVER
++M: Alexey Brodkin <abrodkin@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/display/snps,arcpgu.txt
++F: drivers/gpu/drm/tiny/arcpgu.c
++
++ARCNET NETWORK LAYER
++M: Michael Grzeschik <m.grzeschik@pengutronix.de>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/arcnet/
++F: include/uapi/linux/if_arcnet.h
++
++ARM ARCHITECTED TIMER DRIVER
++M: Mark Rutland <mark.rutland@arm.com>
++M: Marc Zyngier <maz@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/include/asm/arch_timer.h
++F: arch/arm64/include/asm/arch_timer.h
++F: drivers/clocksource/arm_arch_timer.c
++
++ARM HDLCD DRM DRIVER
++M: Liviu Dudau <liviu.dudau@arm.com>
++S: Supported
++F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
++F: drivers/gpu/drm/arm/hdlcd_*
++
++ARM INTEGRATOR, VERSATILE AND REALVIEW SUPPORT
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/arm,integrator.yaml
++F: Documentation/devicetree/bindings/arm/arm,realview.yaml
++F: Documentation/devicetree/bindings/arm/arm,versatile.yaml
++F: Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
++F: Documentation/devicetree/bindings/auxdisplay/arm,versatile-lcd.yaml
++F: Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml
++F: Documentation/devicetree/bindings/i2c/i2c-versatile.txt
++F: Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
++F: Documentation/devicetree/bindings/mtd/arm-versatile.txt
++F: arch/arm/boot/dts/arm-realview-*
++F: arch/arm/boot/dts/integrator*
++F: arch/arm/boot/dts/versatile*
++F: arch/arm/mach-integrator/
++F: arch/arm/mach-realview/
++F: arch/arm/mach-versatile/
++F: arch/arm/plat-versatile/
++F: drivers/bus/arm-integrator-lm.c
++F: drivers/clk/versatile/
++F: drivers/i2c/busses/i2c-versatile.c
++F: drivers/irqchip/irq-versatile-fpga.c
++F: drivers/mtd/maps/physmap-versatile.*
++F: drivers/power/reset/arm-versatile-reboot.c
++F: drivers/soc/versatile/
++
++ARM KOMEDA DRM-KMS DRIVER
++M: James (Qian) Wang <james.qian.wang@arm.com>
++M: Liviu Dudau <liviu.dudau@arm.com>
++M: Mihail Atanassov <mihail.atanassov@arm.com>
++L: Mali DP Maintainers <malidp@foss.arm.com>
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/arm,komeda.txt
++F: Documentation/gpu/komeda-kms.rst
++F: drivers/gpu/drm/arm/display/include/
++F: drivers/gpu/drm/arm/display/komeda/
++
++ARM MALI PANFROST DRM DRIVER
++M: Rob Herring <robh@kernel.org>
++M: Tomeu Vizoso <tomeu.vizoso@collabora.com>
++R: Steven Price <steven.price@arm.com>
++R: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/panfrost/
++F: include/uapi/drm/panfrost_drm.h
++
++ARM MALI-DP DRM DRIVER
++M: Liviu Dudau <liviu.dudau@arm.com>
++M: Brian Starkey <brian.starkey@arm.com>
++L: Mali DP Maintainers <malidp@foss.arm.com>
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/arm,malidp.txt
++F: Documentation/gpu/afbc.rst
++F: drivers/gpu/drm/arm/
++
++ARM MFM AND FLOPPY DRIVERS
++M: Ian Molton <spyro@f2s.com>
++S: Maintained
++F: arch/arm/include/asm/floppy.h
++F: arch/arm/mach-rpc/floppydma.S
++
++ARM PMU PROFILING AND DEBUGGING
++M: Will Deacon <will@kernel.org>
++M: Mark Rutland <mark.rutland@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/pmu.yaml
++F: Documentation/devicetree/bindings/perf/
++F: arch/arm*/include/asm/hw_breakpoint.h
++F: arch/arm*/include/asm/perf_event.h
++F: arch/arm*/kernel/hw_breakpoint.c
++F: arch/arm*/kernel/perf_*
++F: drivers/perf/
++F: include/linux/perf/arm_pmu.h
++
++ARM PORT
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Odd Fixes
++W: http://www.armlinux.org.uk/
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git
++F: arch/arm/
++X: arch/arm/boot/dts/
++
++ARM PRIMECELL AACI PL041 DRIVER
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: sound/arm/aaci.*
++
++ARM PRIMECELL BUS SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: drivers/amba/
++F: include/linux/amba/bus.h
++
++ARM PRIMECELL PL35X NAND CONTROLLER DRIVER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++M: Naga Sureshkumar Relli <nagasure@xilinx.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
++F: drivers/mtd/nand/raw/pl35x-nand-controller.c
++
++ARM PRIMECELL PL35X SMC DRIVER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++M: Naga Sureshkumar Relli <nagasure@xilinx.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
++F: drivers/memory/pl353-smc.c
++
++ARM PRIMECELL CLCD PL110 DRIVER
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: drivers/video/fbdev/amba-clcd.*
++
++ARM PRIMECELL KMI PL050 DRIVER
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: drivers/input/serio/ambakmi.*
++F: include/linux/amba/kmi.h
++
++ARM PRIMECELL MMCI PL180/1 DRIVER
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: drivers/mmc/host/mmci.*
++F: include/linux/amba/mmci.h
++
++ARM PRIMECELL SSP PL022 SPI DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/spi/spi-pl022.yaml
++F: drivers/spi/spi-pl022.c
++
++ARM PRIMECELL UART PL010 AND PL011 DRIVERS
++M: Russell King <linux@armlinux.org.uk>
++S: Odd Fixes
++F: drivers/tty/serial/amba-pl01*.c
++F: include/linux/amba/serial.h
++
++ARM PRIMECELL VIC PL190/PL192 DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt
++F: drivers/irqchip/irq-vic.c
++
++ARM SMC WATCHDOG DRIVER
++M: Julius Werner <jwerner@chromium.org>
++R: Evan Benn <evanbenn@chromium.org>
++S: Maintained
++F: Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml
++F: drivers/watchdog/arm_smc_wdt.c
++
++ARM SMMU DRIVERS
++M: Will Deacon <will@kernel.org>
++R: Robin Murphy <robin.murphy@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/iommu/arm,smmu*
++F: drivers/iommu/arm/
++F: drivers/iommu/io-pgtable-arm*
++
++ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS)
++M: Arnd Bergmann <arnd@arndb.de>
++M: Olof Johansson <olof@lixom.net>
++M: soc@kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
++F: arch/arm/boot/dts/Makefile
++F: arch/arm64/boot/dts/Makefile
++
++ARM SUB-ARCHITECTURES
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
++F: arch/arm/mach-*/
++F: arch/arm/plat-*/
++
++ARM/ACTIONS SEMI ARCHITECTURE
++M: Andreas Färber <afaerber@suse.de>
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-actions@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/actions.yaml
++F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
++F: Documentation/devicetree/bindings/dma/owl-dma.yaml
++F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
++F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
++F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml
++F: Documentation/devicetree/bindings/net/actions,owl-emac.yaml
++F: Documentation/devicetree/bindings/pinctrl/actions,*
++F: Documentation/devicetree/bindings/power/actions,owl-sps.txt
++F: Documentation/devicetree/bindings/timer/actions,owl-timer.txt
++F: arch/arm/boot/dts/owl-*
++F: arch/arm/mach-actions/
++F: arch/arm64/boot/dts/actions/
++F: drivers/clk/actions/
++F: drivers/clocksource/timer-owl*
++F: drivers/dma/owl-dma.c
++F: drivers/i2c/busses/i2c-owl.c
++F: drivers/irqchip/irq-owl-sirq.c
++F: drivers/mmc/host/owl-mmc.c
++F: drivers/net/ethernet/actions/
++F: drivers/pinctrl/actions/*
++F: drivers/soc/actions/
++F: include/dt-bindings/power/owl-*
++F: include/dt-bindings/reset/actions,*
++F: include/linux/soc/actions/
++N: owl
++
++ARM/ADS SPHERE MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/AFEB9260 MACHINE SUPPORT
++M: Sergey Lapin <slapin@ossfans.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/AJECO 1ARM MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/Allwinner SoC Clock Support
++M: Emilio López <emilio@elopez.com.ar>
++S: Maintained
++F: drivers/clk/sunxi/
++
++ARM/Allwinner sunXi SoC support
++M: Maxime Ripard <mripard@kernel.org>
++M: Chen-Yu Tsai <wens@csie.org>
++R: Jernej Skrabec <jernej.skrabec@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
++L: linux-sunxi@lists.linux.dev
++F: arch/arm/mach-sunxi/
++F: arch/arm64/boot/dts/allwinner/
++F: drivers/clk/sunxi-ng/
++F: drivers/pinctrl/sunxi/
++F: drivers/soc/sunxi/
++N: allwinner
++N: sun[x456789]i
++N: sun50i
++
++ARM/Amlogic Meson SoC CLOCK FRAMEWORK
++M: Neil Armstrong <narmstrong@baylibre.com>
++M: Jerome Brunet <jbrunet@baylibre.com>
++L: linux-amlogic@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/clock/amlogic*
++F: drivers/clk/meson/
++F: include/dt-bindings/clock/gxbb*
++F: include/dt-bindings/clock/meson*
++
++ARM/Amlogic Meson SoC Crypto Drivers
++M: Corentin Labbe <clabbe@baylibre.com>
++L: linux-crypto@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/crypto/amlogic*
++F: drivers/crypto/amlogic/
++
++ARM/Amlogic Meson SoC Sound Drivers
++M: Jerome Brunet <jbrunet@baylibre.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/amlogic*
++F: sound/soc/meson/
++
++ARM/Amlogic Meson SoC support
++M: Neil Armstrong <narmstrong@baylibre.com>
++M: Kevin Hilman <khilman@baylibre.com>
++R: Jerome Brunet <jbrunet@baylibre.com>
++R: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-amlogic@lists.infradead.org
++S: Maintained
++W: http://linux-meson.com/
++F: arch/arm/boot/dts/meson*
++F: arch/arm/mach-meson/
++F: arch/arm64/boot/dts/amlogic/
++F: drivers/mmc/host/meson*
++F: drivers/pinctrl/meson/
++F: drivers/rtc/rtc-meson*
++F: drivers/soc/amlogic/
++N: meson
++
++ARM/Annapurna Labs ALPINE ARCHITECTURE
++M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
++M: Antoine Tenart <atenart@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/alpine*
++F: arch/arm/mach-alpine/
++F: arch/arm64/boot/dts/amazon/
++F: drivers/*/*alpine*
++
++ARM/APPLE MACHINE SUPPORT
++M: Hector Martin <marcan@marcan.st>
++M: Sven Peter <sven@svenpeter.dev>
++R: Alyssa Rosenzweig <alyssa@rosenzweig.io>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: https://asahilinux.org
++B: https://github.com/AsahiLinux/linux/issues
++C: irc://irc.oftc.net/asahi-dev
++T: git https://github.com/AsahiLinux/linux.git
++F: Documentation/devicetree/bindings/arm/apple.yaml
++F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
++F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
++F: arch/arm64/boot/dts/apple/
++F: drivers/irqchip/irq-apple-aic.c
++F: include/dt-bindings/interrupt-controller/apple-aic.h
++F: include/dt-bindings/pinctrl/apple.h
++
++ARM/ARTPEC MACHINE SUPPORT
++M: Jesper Nilsson <jesper.nilsson@axis.com>
++M: Lars Persson <lars.persson@axis.com>
++L: linux-arm-kernel@axis.com
++S: Maintained
++F: Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt
++F: arch/arm/boot/dts/artpec6*
++F: arch/arm/mach-artpec
++F: drivers/clk/axis
++F: drivers/crypto/axis
++F: drivers/mmc/host/usdhi6rol0.c
++F: drivers/pinctrl/pinctrl-artpec*
++
++ARM/ASPEED I2C DRIVER
++M: Brendan Higgins <brendanhiggins@google.com>
++R: Benjamin Herrenschmidt <benh@kernel.crashing.org>
++R: Joel Stanley <joel@jms.id.au>
++L: linux-i2c@vger.kernel.org
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++F: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt
++F: drivers/i2c/busses/i2c-aspeed.c
++F: drivers/irqchip/irq-aspeed-i2c-ic.c
++
++ARM/ASPEED MACHINE SUPPORT
++M: Joel Stanley <joel@jms.id.au>
++R: Andrew Jeffery <andrew@aj.id.au>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
++S: Supported
++Q: https://patchwork.ozlabs.org/project/linux-aspeed/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git
++F: arch/arm/boot/dts/aspeed-*
++F: arch/arm/mach-aspeed/
++N: aspeed
++
++ARM/BITMAIN ARCHITECTURE
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/bitmain.yaml
++F: Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.yaml
++F: Documentation/devicetree/bindings/pinctrl/bitmain,bm1880-pinctrl.txt
++F: arch/arm64/boot/dts/bitmain/
++F: drivers/clk/clk-bm1880.c
++F: drivers/pinctrl/pinctrl-bm1880.c
++
++ARM/CALXEDA HIGHBANK ARCHITECTURE
++M: Andre Przywara <andre.przywara@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/ecx-*.dts*
++F: arch/arm/boot/dts/highbank.dts
++F: arch/arm/mach-highbank/
++
++ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
++M: Krzysztof Halasa <khalasa@piap.pl>
++S: Maintained
++F: arch/arm/mach-cns3xxx/
++
++ARM/CAVIUM THUNDER NETWORK DRIVER
++M: Sunil Goutham <sgoutham@marvell.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/net/ethernet/cavium/thunder/
++
++ARM/CIRRUS LOGIC BK3 MACHINE SUPPORT
++M: Lukasz Majewski <lukma@denx.de>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-ep93xx/ts72xx.c
++
++ARM/CIRRUS LOGIC CLPS711X ARM ARCHITECTURE
++M: Alexander Shiyan <shc_work@mail.ru>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Odd Fixes
++N: clps711x
++
++ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
++M: Hartley Sweeten <hsweeten@visionengravers.com>
++M: Alexander Sverdlin <alexander.sverdlin@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-ep93xx/
++F: arch/arm/mach-ep93xx/include/mach/
++
++ARM/CLKDEV SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git clkdev
++F: drivers/clk/clkdev.c
++
++ARM/CONEXANT DIGICOLOR MACHINE SUPPORT
++M: Baruch Siach <baruch@tkos.co.il>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/cx92755*
++N: digicolor
++
++ARM/CONTEC MICRO9 MACHINE SUPPORT
++M: Hubert Feurstein <hubert.feurstein@contec.at>
++S: Maintained
++F: arch/arm/mach-ep93xx/micro9.c
++
++ARM/CORESIGHT FRAMEWORK AND DRIVERS
++M: Mathieu Poirier <mathieu.poirier@linaro.org>
++M: Suzuki K Poulose <suzuki.poulose@arm.com>
++R: Mike Leach <mike.leach@linaro.org>
++R: Leo Yan <leo.yan@linaro.org>
++L: coresight@lists.linaro.org (moderated for non-subscribers)
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git
++F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
++F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
++F: Documentation/devicetree/bindings/arm/coresight-cti.yaml
++F: Documentation/devicetree/bindings/arm/coresight.txt
++F: Documentation/devicetree/bindings/arm/ete.yaml
++F: Documentation/devicetree/bindings/arm/trbe.yaml
++F: Documentation/trace/coresight/*
++F: drivers/hwtracing/coresight/*
++F: include/dt-bindings/arm/coresight-cti-dt.h
++F: include/linux/coresight*
++F: tools/perf/arch/arm/util/auxtrace.c
++F: tools/perf/arch/arm/util/cs-etm.c
++F: tools/perf/arch/arm/util/cs-etm.h
++F: tools/perf/arch/arm/util/pmu.c
++F: tools/perf/util/cs-etm-decoder/*
++F: tools/perf/util/cs-etm.*
++
++ARM/CORGI MACHINE SUPPORT
++M: Richard Purdie <rpurdie@rpsys.net>
++S: Maintained
++
++ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
++M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/ulli-kroll/linux.git
++F: Documentation/devicetree/bindings/arm/gemini.txt
++F: Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
++F: Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt
++F: Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt
++F: arch/arm/boot/dts/gemini*
++F: arch/arm/mach-gemini/
++F: drivers/crypto/gemini/
++F: drivers/net/ethernet/cortina/
++F: drivers/pinctrl/pinctrl-gemini.c
++F: drivers/rtc/rtc-ftrtc010.c
++
++ARM/CZ.NIC TURRIS SUPPORT
++M: Marek Behún <kabel@kernel.org>
++S: Maintained
++W: https://www.turris.cz/
++F: Documentation/ABI/testing/debugfs-moxtet
++F: Documentation/ABI/testing/sysfs-bus-moxtet-devices
++F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
++F: Documentation/devicetree/bindings/bus/moxtet.txt
++F: Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
++F: Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
++F: Documentation/devicetree/bindings/leds/cznic,turris-omnia-leds.yaml
++F: Documentation/devicetree/bindings/watchdog/armada-37xx-wdt.txt
++F: drivers/bus/moxtet.c
++F: drivers/firmware/turris-mox-rwtm.c
++F: drivers/leds/leds-turris-omnia.c
++F: drivers/mailbox/armada-37xx-rwtm-mailbox.c
++F: drivers/gpio/gpio-moxtet.c
++F: drivers/watchdog/armada_37xx_wdt.c
++F: include/dt-bindings/bus/moxtet.h
++F: include/linux/armada-37xx-rwtm-mailbox.h
++F: include/linux/moxtet.h
++
++ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/ezx.c
++
++ARM/FARADAY FA526 PORT
++M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.berlios.de/gemini-board
++F: arch/arm/mm/*-fa*
++
++ARM/FOOTBRIDGE ARCHITECTURE
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.armlinux.org.uk/
++F: arch/arm/include/asm/hardware/dec21285.h
++F: arch/arm/mach-footbridge/
++
++ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
++M: Shawn Guo <shawnguo@kernel.org>
++M: Sascha Hauer <s.hauer@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++R: Fabio Estevam <festevam@gmail.com>
++R: NXP Linux Team <linux-imx@nxp.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
++X: drivers/media/i2c/
++N: imx
++N: mxs
++
++ARM/FREESCALE LAYERSCAPE ARM ARCHITECTURE
++M: Shawn Guo <shawnguo@kernel.org>
++M: Li Yang <leoyang.li@nxp.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
++F: arch/arm/boot/dts/ls1021a*
++F: arch/arm64/boot/dts/freescale/fsl-*
++F: arch/arm64/boot/dts/freescale/qoriq-*
++
++ARM/FREESCALE VYBRID ARM ARCHITECTURE
++M: Shawn Guo <shawnguo@kernel.org>
++M: Sascha Hauer <s.hauer@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++R: Stefan Agner <stefan@agner.ch>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
++F: arch/arm/boot/dts/vf*
++F: arch/arm/mach-imx/*vf610*
++
++ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/GUMSTIX MACHINE SUPPORT
++M: Steve Sakoman <sakoman@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
++M: Philipp Zabel <philipp.zabel@gmail.com>
++M: Paul Parsons <lost.distance@yahoo.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/hx4700.c
++F: arch/arm/mach-pxa/include/mach/hx4700.h
++F: sound/soc/pxa/hx4700.c
++
++ARM/HISILICON SOC SUPPORT
++M: Wei Xu <xuwei5@hisilicon.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++W: http://www.hisilicon.com
++T: git git://github.com/hisilicon/linux-hisi.git
++F: arch/arm/boot/dts/hi3*
++F: arch/arm/boot/dts/hip*
++F: arch/arm/boot/dts/hisi*
++F: arch/arm/mach-hisi/
++F: arch/arm64/boot/dts/hisilicon/
++
++ARM/HP JORNADA 7XX MACHINE SUPPORT
++M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
++S: Maintained
++W: www.jlime.com
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
++F: arch/arm/mach-sa1100/include/mach/jornada720.h
++F: arch/arm/mach-sa1100/jornada720.c
++
++ARM/IGEP MACHINE SUPPORT
++M: Enric Balletbo i Serra <eballetbo@gmail.com>
++M: Javier Martinez Canillas <javier@dowhile0.org>
++L: linux-omap@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/omap3-igep*
++
++ARM/INCOME PXA270 SUPPORT
++M: Marek Vasut <marek.vasut@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/colibri-pxa270-income.c
++
++ARM/INTEL IOP32X ARM ARCHITECTURE
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/INTEL IQ81342EX MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/INTEL IXDP2850 MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/INTEL IXP4XX ARM ARCHITECTURE
++M: Linus Walleij <linusw@kernel.org>
++M: Imre Kaloz <kaloz@openwrt.org>
++M: Krzysztof Halasa <khalasa@piap.pl>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
++F: Documentation/devicetree/bindings/bus/intel,ixp4xx-expansion-bus-controller.yaml
++F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt
++F: Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
++F: Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
++F: arch/arm/mach-ixp4xx/
++F: drivers/bus/intel-ixp4xx-eb.c
++F: drivers/clocksource/timer-ixp4xx.c
++F: drivers/crypto/ixp4xx_crypto.c
++F: drivers/gpio/gpio-ixp4xx.c
++F: drivers/irqchip/irq-ixp4xx.c
++F: include/linux/irqchip/irq-ixp4xx.h
++F: include/linux/platform_data/timer-ixp4xx.h
++
++ARM/INTEL KEEMBAY ARCHITECTURE
++M: Paul J. Murphy <paul.j.murphy@intel.com>
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/arm/intel,keembay.yaml
++F: arch/arm64/boot/dts/intel/keembay-evm.dts
++F: arch/arm64/boot/dts/intel/keembay-soc.dtsi
++
++ARM/INTEL RESEARCH IMOTE/STARGATE 2 MACHINE SUPPORT
++M: Jonathan Cameron <jic23@cam.ac.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/stargate2.c
++F: drivers/pcmcia/pxa2xx_stargate2.c
++
++ARM/INTEL XSC3 (MANZANO) ARM CORE
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/IP FABRICS DOUBLE ESPRESSO MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/LG1K ARCHITECTURE
++M: Chanho Min <chanho.min@lge.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm64/boot/dts/lg/
++
++ARM/LOGICPD PXA270 MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/LPC18XX ARCHITECTURE
++M: Vladimir Zapolskiy <vz@mleia.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt
++F: arch/arm/boot/dts/lpc43*
++F: drivers/i2c/busses/i2c-lpc2k.c
++F: drivers/memory/pl172.c
++F: drivers/mtd/spi-nor/controllers/nxp-spifi.c
++F: drivers/rtc/rtc-lpc24xx.c
++N: lpc18xx
++
++ARM/LPC32XX SOC SUPPORT
++M: Vladimir Zapolskiy <vz@mleia.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/vzapolskiy/linux-lpc32xx.git
++F: Documentation/devicetree/bindings/i2c/i2c-pnx.txt
++F: arch/arm/boot/dts/lpc32*
++F: arch/arm/mach-lpc32xx/
++F: drivers/i2c/busses/i2c-pnx.c
++F: drivers/net/ethernet/nxp/lpc_eth.c
++F: drivers/usb/host/ohci-nxp.c
++F: drivers/watchdog/pnx4008_wdt.c
++N: lpc32xx
++
++ARM/MAGICIAN MACHINE SUPPORT
++M: Philipp Zabel <philipp.zabel@gmail.com>
++S: Maintained
++
++ARM/Marvell Dove/MV78xx0/Orion SOC support
++M: Andrew Lunn <andrew@lunn.ch>
++M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
++M: Gregory Clement <gregory.clement@bootlin.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git
++F: Documentation/devicetree/bindings/soc/dove/
++F: arch/arm/boot/dts/dove*
++F: arch/arm/boot/dts/orion5x*
++F: arch/arm/mach-dove/
++F: arch/arm/mach-mv78xx0/
++F: arch/arm/mach-orion5x/
++F: arch/arm/plat-orion/
++F: drivers/soc/dove/
++
++ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support
++M: Andrew Lunn <andrew@lunn.ch>
++M: Gregory Clement <gregory.clement@bootlin.com>
++M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git
++F: arch/arm/boot/dts/armada*
++F: arch/arm/boot/dts/kirkwood*
++F: arch/arm/configs/mvebu_*_defconfig
++F: arch/arm/mach-mvebu/
++F: arch/arm64/boot/dts/marvell/armada*
++F: arch/arm64/boot/dts/marvell/cn913*
++F: drivers/cpufreq/armada-37xx-cpufreq.c
++F: drivers/cpufreq/armada-8k-cpufreq.c
++F: drivers/cpufreq/mvebu-cpufreq.c
++F: drivers/irqchip/irq-armada-370-xp.c
++F: drivers/irqchip/irq-mvebu-*
++F: drivers/pinctrl/mvebu/
++F: drivers/rtc/rtc-armada38x.c
++
++ARM/Mediatek RTC DRIVER
++M: Eddie Huang <eddie.huang@mediatek.com>
++M: Sean Wang <sean.wang@mediatek.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/rtc/rtc-mt2712.txt
++F: Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
++F: drivers/rtc/rtc-mt2712.c
++F: drivers/rtc/rtc-mt6397.c
++F: drivers/rtc/rtc-mt7622.c
++
++ARM/Mediatek SoC support
++M: Matthias Brugger <matthias.bgg@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: https://mtk.wiki.kernel.org/
++C: irc://chat.freenode.net/linux-mediatek
++F: arch/arm/boot/dts/mt6*
++F: arch/arm/boot/dts/mt7*
++F: arch/arm/boot/dts/mt8*
++F: arch/arm/mach-mediatek/
++F: arch/arm64/boot/dts/mediatek/
++F: drivers/soc/mediatek/
++N: mtk
++N: mt[678]
++K: mediatek
++
++ARM/Mediatek USB3 PHY DRIVER
++M: Chunfeng Yun <chunfeng.yun@mediatek.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/phy/mediatek,*
++F: drivers/phy/mediatek/
++
++ARM/Microchip (AT91) SoC support
++M: Nicolas Ferre <nicolas.ferre@microchip.com>
++M: Alexandre Belloni <alexandre.belloni@bootlin.com>
++M: Ludovic Desroches <ludovic.desroches@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++W: http://www.linux4sam.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git
++F: arch/arm/boot/dts/at91*.dts
++F: arch/arm/boot/dts/at91*.dtsi
++F: arch/arm/boot/dts/sama*.dts
++F: arch/arm/boot/dts/sama*.dtsi
++F: arch/arm/include/debug/at91.S
++F: arch/arm/mach-at91/
++F: drivers/memory/atmel*
++F: drivers/watchdog/sama5d4_wdt.c
++F: include/soc/at91/
++X: drivers/input/touchscreen/atmel_mxt_ts.c
++X: drivers/net/wireless/atmel/
++N: at91
++N: atmel
++
++ARM/Microchip Sparx5 SoC support
++M: Lars Povlsen <lars.povlsen@microchip.com>
++M: Steen Hegelund <Steen.Hegelund@microchip.com>
++M: UNGLinuxDriver@microchip.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++T: git git://github.com/microchip-ung/linux-upstream.git
++F: arch/arm64/boot/dts/microchip/
++F: drivers/pinctrl/pinctrl-microchip-sgpio.c
++N: sparx5
++
++Microchip Timer Counter Block (TCB) Capture Driver
++M: Kamel Bouhara <kamel.bouhara@bootlin.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/counter/microchip-tcb-capture.c
++
++ARM/MIOA701 MACHINE SUPPORT
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/mioa701.c
++
++ARM/MStar/Sigmastar Armv7 SoC support
++M: Daniel Palmer <daniel@thingy.jp>
++M: Romain Perier <romain.perier@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://linux-chenxing.org/
++T: git git://github.com/linux-chenxing/linux.git
++F: Documentation/devicetree/bindings/arm/mstar/*
++F: Documentation/devicetree/bindings/clock/mstar,msc313-mpll.yaml
++F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
++F: arch/arm/boot/dts/mstar-*
++F: arch/arm/mach-mstar/
++F: drivers/clk/mstar/
++F: drivers/gpio/gpio-msc313.c
++F: drivers/watchdog/msc313e_wdt.c
++F: include/dt-bindings/clock/mstar-*
++F: include/dt-bindings/gpio/msc313-gpio.h
++
++ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
++M: Michael Petchkovsky <mkpetch@internode.on.net>
++S: Maintained
++
++ARM/NOMADIK/Ux500 ARCHITECTURES
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
++F: Documentation/devicetree/bindings/arm/ste-*
++F: Documentation/devicetree/bindings/arm/ux500.yaml
++F: Documentation/devicetree/bindings/arm/ux500/
++F: Documentation/devicetree/bindings/i2c/i2c-nomadik.txt
++F: arch/arm/boot/dts/ste-*
++F: arch/arm/mach-nomadik/
++F: arch/arm/mach-ux500/
++F: drivers/clk/clk-nomadik.c
++F: drivers/clocksource/clksrc-dbx500-prcmu.c
++F: drivers/dma/ste_dma40*
++F: drivers/hwspinlock/u8500_hsem.c
++F: drivers/i2c/busses/i2c-nomadik.c
++F: drivers/iio/adc/ab8500-gpadc.c
++F: drivers/mfd/ab8500*
++F: drivers/mfd/abx500*
++F: drivers/mfd/db8500*
++F: drivers/pinctrl/nomadik/
++F: drivers/rtc/rtc-ab8500.c
++F: drivers/rtc/rtc-pl031.c
++F: drivers/soc/ux500/
++
++ARM/NUVOTON NPCM ARCHITECTURE
++M: Avi Fishman <avifishman70@gmail.com>
++M: Tomer Maimon <tmaimon77@gmail.com>
++M: Tali Perry <tali.perry1@gmail.com>
++R: Patrick Venture <venture@google.com>
++R: Nancy Yuen <yuenn@google.com>
++R: Benjamin Fair <benjaminfair@google.com>
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/*/*/*npcm*
++F: Documentation/devicetree/bindings/*/*npcm*
++F: arch/arm/boot/dts/nuvoton-npcm*
++F: arch/arm/mach-npcm/
++F: drivers/*/*npcm*
++F: drivers/*/*/*npcm*
++F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
++
++ARM/NUVOTON WPCM450 ARCHITECTURE
++M: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/*/*wpcm*
++F: arch/arm/boot/dts/nuvoton-wpcm450*
++F: arch/arm/mach-npcm/wpcm450.c
++F: drivers/*/*wpcm*
++
++ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
++L: openmoko-kernel@lists.openmoko.org (subscribers-only)
++S: Orphan
++W: http://wiki.openmoko.org/wiki/Neo_FreeRunner
++F: arch/arm/mach-s3c/gta02.h
++F: arch/arm/mach-s3c/mach-gta02.c
++
++ARM/Orion SoC/Technologic Systems TS-78xx platform support
++M: Alexander Clouter <alex@digriz.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.digriz.org.uk/ts78xx/kernel
++F: arch/arm/mach-orion5x/ts78xx-*
++
++ARM/OXNAS platform support
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-oxnas@groups.io (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/ox8*.dts*
++F: arch/arm/mach-oxnas/
++F: drivers/power/reset/oxnas-restart.c
++N: oxnas
++
++ARM/PALM TREO SUPPORT
++M: Tomas Cech <sleep_walker@suse.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://hackndev.com
++F: arch/arm/mach-pxa/palmtreo.*
++
++ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
++M: Marek Vasut <marek.vasut@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://hackndev.com
++F: arch/arm/mach-pxa/include/mach/palmld.h
++F: arch/arm/mach-pxa/include/mach/palmtc.h
++F: arch/arm/mach-pxa/include/mach/palmtx.h
++F: arch/arm/mach-pxa/palmld.c
++F: arch/arm/mach-pxa/palmt5.*
++F: arch/arm/mach-pxa/palmtc.c
++F: arch/arm/mach-pxa/palmte2.*
++F: arch/arm/mach-pxa/palmtx.c
++
++ARM/PALMZ72 SUPPORT
++M: Sergey Lapin <slapin@ossfans.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://hackndev.com
++F: arch/arm/mach-pxa/palmz72.*
++
++ARM/PLEB SUPPORT
++M: Peter Chubb <pleb@gelato.unsw.edu.au>
++S: Maintained
++W: http://www.disy.cse.unsw.edu.au/Hardware/PLEB
++
++ARM/PT DIGITAL BOARD PORT
++M: Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.armlinux.org.uk/
++
++ARM/QUALCOMM SUPPORT
++M: Andy Gross <agross@kernel.org>
++M: Bjorn Andersson <bjorn.andersson@linaro.org>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
++F: Documentation/devicetree/bindings/*/qcom*
++F: Documentation/devicetree/bindings/soc/qcom/
++F: arch/arm/boot/dts/qcom-*.dts
++F: arch/arm/boot/dts/qcom-*.dtsi
++F: arch/arm/mach-qcom/
++F: arch/arm64/boot/dts/qcom/
++F: drivers/*/*/qcom*
++F: drivers/*/*/qcom/
++F: drivers/*/pm8???-*
++F: drivers/*/qcom*
++F: drivers/*/qcom/
++F: drivers/bluetooth/btqcomsmd.c
++F: drivers/clocksource/timer-qcom.c
++F: drivers/cpuidle/cpuidle-qcom-spm.c
++F: drivers/extcon/extcon-qcom*
++F: drivers/i2c/busses/i2c-qcom-geni.c
++F: drivers/i2c/busses/i2c-qup.c
++F: drivers/iommu/msm*
++F: drivers/mfd/ssbi.c
++F: drivers/mmc/host/mmci_qcom*
++F: drivers/mmc/host/sdhci-msm.c
++F: drivers/pci/controller/dwc/pcie-qcom.c
++F: drivers/phy/qualcomm/
++F: drivers/power/*/msm*
++F: drivers/reset/reset-qcom-*
++F: drivers/scsi/ufs/ufs-qcom*
++F: drivers/spi/spi-geni-qcom.c
++F: drivers/spi/spi-qcom-qspi.c
++F: drivers/spi/spi-qup.c
++F: drivers/tty/serial/msm_serial.c
++F: drivers/usb/dwc3/dwc3-qcom.c
++F: include/dt-bindings/*/qcom*
++F: include/linux/*/qcom*
++F: include/linux/soc/qcom/
++
++ARM/RADISYS ENP2611 MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/RDA MICRO ARCHITECTURE
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-unisoc@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/rda.yaml
++F: Documentation/devicetree/bindings/gpio/gpio-rda.yaml
++F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
++F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
++F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
++F: arch/arm/boot/dts/rda8810pl-*
++F: drivers/clocksource/timer-rda.c
++F: drivers/gpio/gpio-rda.c
++F: drivers/irqchip/irq-rda-intc.c
++F: drivers/tty/serial/rda-uart.c
++
++ARM/REALTEK ARCHITECTURE
++M: Andreas Färber <afaerber@suse.de>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-realtek-soc@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/realtek.yaml
++F: arch/arm/boot/dts/rtd*
++F: arch/arm/mach-realtek/
++F: arch/arm64/boot/dts/realtek/
++
++ARM/RENESAS ARM64 ARCHITECTURE
++M: Geert Uytterhoeven <geert+renesas@glider.be>
++M: Magnus Damm <magnus.damm@gmail.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
++F: Documentation/devicetree/bindings/arm/renesas.yaml
++F: arch/arm64/boot/dts/renesas/
++F: drivers/soc/renesas/
++F: include/linux/soc/renesas/
++
++ARM/RISCPC ARCHITECTURE
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.armlinux.org.uk/
++F: arch/arm/include/asm/hardware/entry-macro-iomd.S
++F: arch/arm/include/asm/hardware/ioc.h
++F: arch/arm/include/asm/hardware/iomd.h
++F: arch/arm/include/asm/hardware/memc.h
++F: arch/arm/mach-rpc/
++F: drivers/net/ethernet/8390/etherh.c
++F: drivers/net/ethernet/i825xx/ether1*
++F: drivers/net/ethernet/seeq/ether3*
++F: drivers/scsi/arm/
++
++ARM/Rockchip SoC support
++M: Heiko Stuebner <heiko@sntech.de>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
++F: Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
++F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
++F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml
++F: arch/arm/boot/dts/rk3*
++F: arch/arm/boot/dts/rv1108*
++F: arch/arm/mach-rockchip/
++F: drivers/*/*/*rockchip*
++F: drivers/*/*rockchip*
++F: drivers/clk/rockchip/
++F: drivers/i2c/busses/i2c-rk3x.c
++F: sound/soc/rockchip/
++N: rockchip
++
++ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
++F: Documentation/arm/samsung/
++F: Documentation/devicetree/bindings/arm/samsung/
++F: Documentation/devicetree/bindings/power/pd-samsung.yaml
++F: arch/arm/boot/dts/exynos*
++F: arch/arm/boot/dts/s3c*
++F: arch/arm/boot/dts/s5p*
++F: arch/arm/mach-exynos*/
++F: arch/arm/mach-s3c/
++F: arch/arm/mach-s5p*/
++F: arch/arm64/boot/dts/exynos/
++F: drivers/*/*/*s3c24*
++F: drivers/*/*s3c24*
++F: drivers/*/*s3c64xx*
++F: drivers/*/*s5pv210*
++F: drivers/clocksource/samsung_pwm_timer.c
++F: drivers/memory/samsung/
++F: drivers/pwm/pwm-samsung.c
++F: drivers/soc/samsung/
++F: drivers/tty/serial/samsung*
++F: include/clocksource/samsung_pwm.h
++F: include/linux/platform_data/*s3c*
++F: include/linux/serial_s3c.h
++F: include/linux/soc/samsung/
++N: exynos
++N: s3c2410
++N: s3c64xx
++N: s5pv210
++
++ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
++M: Andrzej Hajda <a.hajda@samsung.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/s5p-g2d/
++
++ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT
++M: Marek Szyprowski <m.szyprowski@samsung.com>
++L: linux-samsung-soc@vger.kernel.org
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/s5p-cec.txt
++F: drivers/media/cec/platform/s5p/
++
++ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
++M: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
++M: Jacek Anaszewski <jacek.anaszewski@gmail.com>
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/s5p-jpeg/
++
++ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
++M: Andrzej Hajda <a.hajda@samsung.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/s5p-mfc/
++
++ARM/SHMOBILE ARM ARCHITECTURE
++M: Geert Uytterhoeven <geert+renesas@glider.be>
++M: Magnus Damm <magnus.damm@gmail.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
++F: Documentation/devicetree/bindings/arm/renesas.yaml
++F: arch/arm/boot/dts/emev2*
++F: arch/arm/boot/dts/gr-peach*
++F: arch/arm/boot/dts/iwg20d-q7*
++F: arch/arm/boot/dts/r7s*
++F: arch/arm/boot/dts/r8a*
++F: arch/arm/boot/dts/r9a*
++F: arch/arm/boot/dts/sh*
++F: arch/arm/configs/shmobile_defconfig
++F: arch/arm/include/debug/renesas-scif.S
++F: arch/arm/mach-shmobile/
++F: drivers/soc/renesas/
++F: include/linux/soc/renesas/
++
++ARM/SOCFPGA ARCHITECTURE
++M: Dinh Nguyen <dinguyen@kernel.org>
++S: Maintained
++W: http://www.rocketboards.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
++F: arch/arm/boot/dts/socfpga*
++F: arch/arm/configs/socfpga_defconfig
++F: arch/arm/mach-socfpga/
++F: arch/arm64/boot/dts/altera/
++F: arch/arm64/boot/dts/intel/
++
++ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
++M: Dinh Nguyen <dinguyen@kernel.org>
++S: Maintained
++F: drivers/clk/socfpga/
++
++ARM/SOCFPGA EDAC SUPPORT
++M: Dinh Nguyen <dinguyen@kernel.org>
++S: Maintained
++F: drivers/edac/altera_edac.[ch]
++
++ARM/SPREADTRUM SoC SUPPORT
++M: Orson Zhai <orsonzhai@gmail.com>
++M: Baolin Wang <baolin.wang7@gmail.com>
++M: Chunyan Zhang <zhang.lyra@gmail.com>
++S: Maintained
++F: arch/arm64/boot/dts/sprd
++N: sprd
++N: sc27xx
++N: sc2731
++
++ARM/STI ARCHITECTURE
++M: Patrice Chotard <patrice.chotard@foss.st.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.stlinux.com
++F: Documentation/devicetree/bindings/i2c/i2c-st.txt
++F: arch/arm/boot/dts/sti*
++F: arch/arm/mach-sti/
++F: drivers/ata/ahci_st.c
++F: drivers/char/hw_random/st-rng.c
++F: drivers/clocksource/arm_global_timer.c
++F: drivers/clocksource/clksrc_st_lpc.c
++F: drivers/cpufreq/sti-cpufreq.c
++F: drivers/dma/st_fdma*
++F: drivers/i2c/busses/i2c-st.c
++F: drivers/media/platform/sti/c8sectpfe/
++F: drivers/media/rc/st_rc.c
++F: drivers/mmc/host/sdhci-st.c
++F: drivers/phy/st/phy-miphy28lp.c
++F: drivers/phy/st/phy-stih407-usb.c
++F: drivers/pinctrl/pinctrl-st.c
++F: drivers/remoteproc/st_remoteproc.c
++F: drivers/remoteproc/st_slim_rproc.c
++F: drivers/reset/sti/
++F: drivers/rtc/rtc-st-lpc.c
++F: drivers/tty/serial/st-asc.c
++F: drivers/usb/dwc3/dwc3-st.c
++F: drivers/usb/host/ehci-st.c
++F: drivers/usb/host/ohci-st.c
++F: drivers/watchdog/st_lpc_wdt.c
++F: include/linux/remoteproc/st_slim_rproc.h
++
++ARM/STM32 ARCHITECTURE
++M: Maxime Coquelin <mcoquelin.stm32@gmail.com>
++M: Alexandre Torgue <alexandre.torgue@foss.st.com>
++L: linux-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers)
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
++F: arch/arm/boot/dts/stm32*
++F: arch/arm/mach-stm32/
++F: drivers/clocksource/armv7m_systick.c
++N: stm32
++N: stm
++
++ARM/Synaptics SoC support
++M: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
++M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/berlin*
++F: arch/arm/mach-berlin/
++F: arch/arm64/boot/dts/synaptics/
++
++ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-tegra@vger.kernel.org
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/tegra-cec.txt
++F: drivers/media/cec/platform/tegra/
++
++ARM/TETON BGA MACHINE SUPPORT
++M: "Mark F. Brown" <mark.brown314@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/memory/*emif*
++
++ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
++F: arch/arm/boot/dts/keystone-*
++F: arch/arm/mach-keystone/
++
++ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/clk/keystone/
++
++ARM/TEXAS INSTRUMENT KEYSTONE CLOCKSOURCE
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/clocksource/timer-keystone.c
++
++ARM/TEXAS INSTRUMENT KEYSTONE RESET DRIVER
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/power/reset/keystone-reset.c
++
++ARM/TEXAS INSTRUMENTS K3 ARCHITECTURE
++M: Nishanth Menon <nm@ti.com>
++M: Vignesh Raghavendra <vigneshr@ti.com>
++M: Tero Kristo <kristo@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/arm/ti/k3.yaml
++F: arch/arm64/boot/dts/ti/Makefile
++F: arch/arm64/boot/dts/ti/k3-*
++F: include/dt-bindings/pinctrl/k3.h
++
++ARM/THECUS N2100 MACHINE SUPPORT
++M: Lennert Buytenhek <kernel@wantstofly.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++
++ARM/TOSA MACHINE SUPPORT
++M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
++M: Dirk Opfer <dirk@opfer-online.de>
++S: Maintained
++
++ARM/TOSHIBA VISCONTI ARCHITECTURE
++M: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git
++F: Documentation/devicetree/bindings/arm/toshiba.yaml
++F: Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml
++F: Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml
++F: Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
++F: Documentation/devicetree/bindings/pinctrl/toshiba,tmpv7700-pinctrl.yaml
++F: Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml
++F: arch/arm64/boot/dts/toshiba/
++F: drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
++F: drivers/gpio/gpio-visconti.c
++F: drivers/pci/controller/dwc/pcie-visconti.c
++F: drivers/pinctrl/visconti/
++F: drivers/watchdog/visconti_wdt.c
++N: visconti
++
++ARM/UNIPHIER ARCHITECTURE
++M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
++M: Masami Hiramatsu <mhiramat@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
++F: Documentation/devicetree/bindings/gpio/socionext,uniphier-gpio.yaml
++F: Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml
++F: arch/arm/boot/dts/uniphier*
++F: arch/arm/include/asm/hardware/cache-uniphier.h
++F: arch/arm/mach-uniphier/
++F: arch/arm/mm/cache-uniphier.c
++F: arch/arm64/boot/dts/socionext/uniphier*
++F: drivers/bus/uniphier-system-bus.c
++F: drivers/clk/uniphier/
++F: drivers/dma/uniphier-mdmac.c
++F: drivers/gpio/gpio-uniphier.c
++F: drivers/i2c/busses/i2c-uniphier*
++F: drivers/irqchip/irq-uniphier-aidet.c
++F: drivers/mmc/host/uniphier-sd.c
++F: drivers/pinctrl/uniphier/
++F: drivers/reset/reset-uniphier.c
++F: drivers/tty/serial/8250/8250_uniphier.c
++N: uniphier
++
++ARM/VERSATILE EXPRESS PLATFORM
++M: Liviu Dudau <liviu.dudau@arm.com>
++M: Sudeep Holla <sudeep.holla@arm.com>
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: */*/*/vexpress*
++F: */*/vexpress*
++F: arch/arm/boot/dts/vexpress*
++F: arch/arm/mach-vexpress/
++F: arch/arm64/boot/dts/arm/
++F: drivers/clk/versatile/clk-vexpress-osc.c
++F: drivers/clocksource/timer-versatile.c
++N: mps2
++
++ARM/VFP SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.armlinux.org.uk/
++F: arch/arm/vfp/
++
++ARM/VOIPAC PXA270 SUPPORT
++M: Marek Vasut <marek.vasut@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/include/mach/vpac270.h
++F: arch/arm/mach-pxa/vpac270.c
++
++ARM/VT8500 ARM ARCHITECTURE
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Orphan
++F: Documentation/devicetree/bindings/i2c/i2c-wmt.txt
++F: arch/arm/mach-vt8500/
++F: drivers/clocksource/timer-vt8500.c
++F: drivers/i2c/busses/i2c-wmt.c
++F: drivers/mmc/host/wmt-sdmmc.c
++F: drivers/pwm/pwm-vt8500.c
++F: drivers/rtc/rtc-vt8500.c
++F: drivers/tty/serial/vt8500_serial.c
++F: drivers/usb/host/ehci-platform.c
++F: drivers/usb/host/uhci-platform.c
++F: drivers/video/fbdev/vt8500lcdfb.*
++F: drivers/video/fbdev/wm8505fb*
++F: drivers/video/fbdev/wmt_ge_rops.*
++
++ARM/ZIPIT Z2 SUPPORT
++M: Marek Vasut <marek.vasut@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/mach-pxa/include/mach/z2.h
++F: arch/arm/mach-pxa/z2.c
++
++ARM/ZYNQ ARCHITECTURE
++M: Michal Simek <michal.simek@xilinx.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++W: http://wiki.xilinx.com
++T: git https://github.com/Xilinx/linux-xlnx.git
++F: Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml
++F: Documentation/devicetree/bindings/i2c/xlnx,xps-iic-2.00.a.yaml
++F: Documentation/devicetree/bindings/spi/xlnx,zynq-qspi.yaml
++F: arch/arm/mach-zynq/
++F: drivers/clocksource/timer-cadence-ttc.c
++F: drivers/cpuidle/cpuidle-zynq.c
++F: drivers/edac/synopsys_edac.c
++F: drivers/i2c/busses/i2c-cadence.c
++F: drivers/i2c/busses/i2c-xiic.c
++F: drivers/mmc/host/sdhci-of-arasan.c
++N: zynq
++N: xilinx
++
++ARM64 PORT (AARCH64 ARCHITECTURE)
++M: Catalin Marinas <catalin.marinas@arm.com>
++M: Will Deacon <will@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
++F: Documentation/arm64/
++F: arch/arm64/
++F: tools/testing/selftests/arm64/
++X: arch/arm64/boot/dts/
++
++ARROW SPEEDCHIPS XRS7000 SERIES ETHERNET SWITCH DRIVER
++M: George McCollister <george.mccollister@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/arrow,xrs700x.yaml
++F: drivers/net/dsa/xrs700x/*
++F: net/dsa/tag_xrs700x.c
++
++AS3645A LED FLASH CONTROLLER DRIVER
++M: Sakari Ailus <sakari.ailus@iki.fi>
++L: linux-leds@vger.kernel.org
++S: Maintained
++F: drivers/leds/flash/leds-as3645a.c
++
++ASAHI KASEI AK7375 LENS VOICE COIL DRIVER
++M: Tianshu Qiu <tian.shu.qiu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ak7375.txt
++F: drivers/media/i2c/ak7375.c
++
++ASAHI KASEI AK8974 DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://www.akm.com/
++F: drivers/iio/magnetometer/ak8974.c
++
++ASC7621 HARDWARE MONITOR DRIVER
++M: George Joseph <george.joseph@fairview5.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/asc7621.rst
++F: drivers/hwmon/asc7621.c
++
++ASPEED PINCTRL DRIVERS
++M: Andrew Jeffery <andrew@aj.id.au>
++L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pinctrl/aspeed,*
++F: drivers/pinctrl/aspeed/
++
++ASPEED SCU INTERRUPT CONTROLLER DRIVER
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt
++F: drivers/irqchip/irq-aspeed-scu-ic.c
++F: include/dt-bindings/interrupt-controller/aspeed-scu-ic.h
++
++ASPEED SD/MMC DRIVER
++M: Andrew Jeffery <andrew@aj.id.au>
++L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
++F: drivers/mmc/host/sdhci-of-aspeed*
++
++ASPEED VIDEO ENGINE DRIVER
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-media@vger.kernel.org
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/media/aspeed-video.txt
++F: drivers/media/platform/aspeed-video.c
++
++ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
++M: Corentin Chary <corentin.chary@gmail.com>
++L: acpi4asus-user@lists.sourceforge.net
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://acpi4asus.sf.net
++F: drivers/platform/x86/asus*.c
++F: drivers/platform/x86/eeepc*.c
++
++ASUS WIRELESS RADIO CONTROL DRIVER
++M: João Paulo Rechi Vita <jprvita@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/asus-wireless.c
++
++ASYMMETRIC KEYS
++M: David Howells <dhowells@redhat.com>
++L: keyrings@vger.kernel.org
++S: Maintained
++F: Documentation/crypto/asymmetric-keys.rst
++F: crypto/asymmetric_keys/
++F: include/crypto/pkcs7.h
++F: include/crypto/public_key.h
++F: include/linux/verification.h
++
++ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
++R: Dan Williams <dan.j.williams@intel.com>
++S: Odd fixes
++W: http://sourceforge.net/projects/xscaleiop
++F: Documentation/crypto/async-tx-api.rst
++F: crypto/async_tx/
++F: include/linux/async_tx.h
++
++AT24 EEPROM DRIVER
++M: Bartosz Golaszewski <brgl@bgdev.pl>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
++F: Documentation/devicetree/bindings/eeprom/at24.yaml
++F: drivers/misc/eeprom/at24.c
++
++ATA OVER ETHERNET (AOE) DRIVER
++M: "Justin Sanders" <justin@coraid.com>
++S: Supported
++W: http://www.openaoe.org/
++F: Documentation/admin-guide/aoe/
++F: drivers/block/aoe/
++
++ATC260X PMIC MFD DRIVER
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++M: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
++L: linux-actions@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
++F: drivers/input/misc/atc260x-onkey.c
++F: drivers/mfd/atc260*
++F: drivers/power/reset/atc260x-poweroff.c
++F: drivers/regulator/atc260x-regulator.c
++F: include/linux/mfd/atc260x/*
++
++ATHEROS 71XX/9XXX GPIO DRIVER
++M: Alban Bedel <albeu@free.fr>
++S: Maintained
++W: https://github.com/AlbanBedel/linux
++T: git git://github.com/AlbanBedel/linux
++F: Documentation/devicetree/bindings/gpio/gpio-ath79.txt
++F: drivers/gpio/gpio-ath79.c
++
++ATHEROS 71XX/9XXX USB PHY DRIVER
++M: Alban Bedel <albeu@free.fr>
++S: Maintained
++W: https://github.com/AlbanBedel/linux
++T: git git://github.com/AlbanBedel/linux
++F: Documentation/devicetree/bindings/phy/phy-ath79-usb.txt
++F: drivers/phy/qualcomm/phy-ath79-usb.c
++
++ATHEROS ATH GENERIC UTILITIES
++M: Kalle Valo <kvalo@codeaurora.org>
++L: linux-wireless@vger.kernel.org
++S: Supported
++F: drivers/net/wireless/ath/*
++
++ATHEROS ATH5K WIRELESS DRIVER
++M: Jiri Slaby <jirislaby@kernel.org>
++M: Nick Kossifidis <mickflemm@gmail.com>
++M: Luis Chamberlain <mcgrof@kernel.org>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/en/users/Drivers/ath5k
++F: drivers/net/wireless/ath/ath5k/
++
++ATHEROS ATH6KL WIRELESS DRIVER
++M: Kalle Valo <kvalo@codeaurora.org>
++L: linux-wireless@vger.kernel.org
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/Drivers/ath6kl
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
++F: drivers/net/wireless/ath/ath6kl/
++
++ATI_REMOTE2 DRIVER
++M: Ville Syrjala <syrjala@sci.fi>
++S: Maintained
++F: drivers/input/misc/ati_remote2.c
++
++ATK0110 HWMON DRIVER
++M: Luca Tettamanti <kronos.it@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/asus_atk0110.c
++
++ATLX ETHERNET DRIVERS
++M: Chris Snook <chris.snook@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://sourceforge.net/projects/atl1
++W: http://atl1.sourceforge.net
++F: drivers/net/ethernet/atheros/
++
++ATM
++M: Chas Williams <3chas3@gmail.com>
++L: linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://linux-atm.sourceforge.net
++F: drivers/atm/
++F: include/linux/atm*
++F: include/uapi/linux/atm*
++
++ATMEL MACB ETHERNET DRIVER
++M: Nicolas Ferre <nicolas.ferre@microchip.com>
++M: Claudiu Beznea <claudiu.beznea@microchip.com>
++S: Supported
++F: drivers/net/ethernet/cadence/
++
++ATMEL MAXTOUCH DRIVER
++M: Nick Dyer <nick@shmanahar.org>
++S: Maintained
++T: git git://github.com/ndyer/linux.git
++F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
++F: drivers/input/touchscreen/atmel_mxt_ts.c
++
++ATMEL WIRELESS DRIVER
++M: Simon Kelley <simon@thekelleys.org.uk>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: http://www.thekelleys.org.uk/atmel
++W: http://atmelwlandriver.sourceforge.net/
++F: drivers/net/wireless/atmel/atmel*
++
++ATOMIC INFRASTRUCTURE
++M: Will Deacon <will@kernel.org>
++M: Peter Zijlstra <peterz@infradead.org>
++R: Boqun Feng <boqun.feng@gmail.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: arch/*/include/asm/atomic*.h
++F: include/*/atomic*.h
++F: include/linux/refcount.h
++F: Documentation/atomic_*.txt
++F: scripts/atomic/
++
++ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
++M: Bradley Grove <linuxdrivers@attotech.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.attotech.com
++F: drivers/scsi/esas2r
++
++ATUSB IEEE 802.15.4 RADIO DRIVER
++M: Stefan Schmidt <stefan@datenfreihafen.org>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++F: drivers/net/ieee802154/at86rf230.h
++F: drivers/net/ieee802154/atusb.c
++F: drivers/net/ieee802154/atusb.h
++
++AUDIT SUBSYSTEM
++M: Paul Moore <paul@paul-moore.com>
++M: Eric Paris <eparis@redhat.com>
++L: linux-audit@redhat.com (moderated for non-subscribers)
++S: Supported
++W: https://github.com/linux-audit
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
++F: include/asm-generic/audit_*.h
++F: include/linux/audit.h
++F: include/uapi/linux/audit.h
++F: kernel/audit*
++F: lib/*audit.c
++
++AUXILIARY DISPLAY DRIVERS
++M: Miguel Ojeda <ojeda@kernel.org>
++S: Maintained
++F: drivers/auxdisplay/
++F: include/linux/cfag12864b.h
++
++AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER
++M: Andreas Klinger <ak@it-klinger.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
++F: drivers/iio/adc/hx711.c
++
++AX.25 NETWORK LAYER
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://www.linux-ax25.org/
++F: include/net/ax25.h
++F: include/uapi/linux/ax25.h
++F: net/ax25/
++
++AXENTIA ARM DEVICES
++M: Peter Rosin <peda@axentia.se>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/at91-linea.dtsi
++F: arch/arm/boot/dts/at91-natte.dtsi
++F: arch/arm/boot/dts/at91-nattis-2-natte-2.dts
++F: arch/arm/boot/dts/at91-tse850-3.dts
++
++AXENTIA ASOC DRIVERS
++M: Peter Rosin <peda@axentia.se>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/axentia,*
++F: sound/soc/atmel/tse850-pcm5142.c
++
++AXI-FAN-CONTROL HARDWARE MONITOR DRIVER
++M: Nuno Sá <nuno.sa@analog.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
++F: drivers/hwmon/axi-fan-control.c
++
++AXXIA I2C CONTROLLER
++M: Krzysztof Adamski <krzysztof.adamski@nokia.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-axxia.txt
++F: drivers/i2c/busses/i2c-axxia.c
++
++AZ6007 DVB DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/az6007.c
++
++AZTECH FM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-aztech*
++
++B43 WIRELESS DRIVER
++L: linux-wireless@vger.kernel.org
++L: b43-dev@lists.infradead.org
++S: Odd Fixes
++W: https://wireless.wiki.kernel.org/en/users/Drivers/b43
++F: drivers/net/wireless/broadcom/b43/
++
++B43LEGACY WIRELESS DRIVER
++M: Larry Finger <Larry.Finger@lwfinger.net>
++L: linux-wireless@vger.kernel.org
++L: b43-dev@lists.infradead.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/en/users/Drivers/b43
++F: drivers/net/wireless/broadcom/b43legacy/
++
++BACKLIGHT CLASS/SUBSYSTEM
++M: Lee Jones <lee.jones@linaro.org>
++M: Daniel Thompson <daniel.thompson@linaro.org>
++M: Jingoo Han <jingoohan1@gmail.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
++F: Documentation/ABI/stable/sysfs-class-backlight
++F: Documentation/ABI/testing/sysfs-class-backlight
++F: Documentation/devicetree/bindings/leds/backlight
++F: drivers/video/backlight/
++F: include/linux/backlight.h
++F: include/linux/pwm_backlight.h
++
++BATMAN ADVANCED
++M: Marek Lindner <mareklindner@neomailbox.ch>
++M: Simon Wunderlich <sw@simonwunderlich.de>
++M: Antonio Quartulli <a@unstable.cc>
++M: Sven Eckelmann <sven@narfation.org>
++L: b.a.t.m.a.n@lists.open-mesh.org (moderated for non-subscribers)
++S: Maintained
++W: https://www.open-mesh.org/
++Q: https://patchwork.open-mesh.org/project/batman/list/
++B: https://www.open-mesh.org/projects/batman-adv/issues
++C: ircs://irc.hackint.org/batadv
++T: git https://git.open-mesh.org/linux-merge.git
++F: Documentation/networking/batman-adv.rst
++F: include/uapi/linux/batadv_packet.h
++F: include/uapi/linux/batman_adv.h
++F: net/batman-adv/
++
++BAYCOM/HDLCDRV DRIVERS FOR AX.25
++M: Thomas Sailer <t.sailer@alumni.ethz.ch>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://www.baycom.org/~tom/ham/ham.html
++F: drivers/net/hamradio/baycom*
++
++BCACHE (BLOCK LAYER CACHE)
++M: Coly Li <colyli@suse.de>
++M: Kent Overstreet <kent.overstreet@gmail.com>
++L: linux-bcache@vger.kernel.org
++S: Maintained
++W: http://bcache.evilpiepirate.org
++C: irc://irc.oftc.net/bcache
++F: drivers/md/bcache/
++
++BDISP ST MEDIA DRIVER
++M: Fabien Dessenne <fabien.dessenne@foss.st.com>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/platform/sti/bdisp
++
++BECKHOFF CX5020 ETHERCAT MASTER DRIVER
++M: Dariusz Marcinkiewicz <reksio@newterm.pl>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/ec_bhf.c
++
++BEFS FILE SYSTEM
++M: Luis de Bethencourt <luisbg@kernel.org>
++M: Salah Triki <salah.triki@gmail.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/luisbg/linux-befs.git
++F: Documentation/filesystems/befs.rst
++F: fs/befs/
++
++BFQ I/O SCHEDULER
++M: Paolo Valente <paolo.valente@linaro.org>
++M: Jens Axboe <axboe@kernel.dk>
++L: linux-block@vger.kernel.org
++S: Maintained
++F: Documentation/block/bfq-iosched.rst
++F: block/bfq-*
++
++BFS FILE SYSTEM
++M: "Tigran A. Aivazian" <aivazian.tigran@gmail.com>
++S: Maintained
++F: Documentation/filesystems/bfs.rst
++F: fs/bfs/
++F: include/uapi/linux/bfs_fs.h
++
++BITMAP API
++M: Yury Norov <yury.norov@gmail.com>
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
++S: Maintained
++F: include/asm-generic/bitops/find.h
++F: include/linux/bitmap.h
++F: lib/bitmap.c
++F: lib/find_bit.c
++F: lib/find_bit_benchmark.c
++F: lib/test_bitmap.c
++F: tools/include/asm-generic/bitops/find.h
++F: tools/include/linux/bitmap.h
++F: tools/lib/bitmap.c
++F: tools/lib/find_bit.c
++
++BLINKM RGB LED DRIVER
++M: Jan-Simon Moeller <jansimon.moeller@gmx.de>
++S: Maintained
++F: drivers/leds/leds-blinkm.c
++
++BLOCK LAYER
++M: Jens Axboe <axboe@kernel.dk>
++L: linux-block@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
++F: block/
++F: drivers/block/
++F: include/linux/blk*
++F: kernel/trace/blktrace.c
++F: lib/sbitmap.c
++
++BLOCK2MTD DRIVER
++M: Joern Engel <joern@lazybastard.org>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: drivers/mtd/devices/block2mtd.c
++
++BLUETOOTH DRIVERS
++M: Marcel Holtmann <marcel@holtmann.org>
++M: Johan Hedberg <johan.hedberg@gmail.com>
++M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
++L: linux-bluetooth@vger.kernel.org
++S: Supported
++W: http://www.bluez.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
++F: drivers/bluetooth/
++
++BLUETOOTH SUBSYSTEM
++M: Marcel Holtmann <marcel@holtmann.org>
++M: Johan Hedberg <johan.hedberg@gmail.com>
++M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
++L: linux-bluetooth@vger.kernel.org
++S: Supported
++W: http://www.bluez.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
++F: include/net/bluetooth/
++F: net/bluetooth/
++
++BONDING DRIVER
++M: Jay Vosburgh <j.vosburgh@gmail.com>
++M: Veaceslav Falico <vfalico@gmail.com>
++M: Andy Gospodarek <andy@greyhouse.net>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://sourceforge.net/projects/bonding/
++F: drivers/net/bonding/
++F: include/net/bonding.h
++F: include/uapi/linux/if_bonding.h
++
++BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
++M: Dan Robertson <dan@dlrobertson.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
++F: drivers/iio/accel/bma400*
++
++BPF (Safe dynamic programs and tools)
++M: Alexei Starovoitov <ast@kernel.org>
++M: Daniel Borkmann <daniel@iogearbox.net>
++M: Andrii Nakryiko <andrii@kernel.org>
++R: Martin KaFai Lau <kafai@fb.com>
++R: Song Liu <songliubraving@fb.com>
++R: Yonghong Song <yhs@fb.com>
++R: John Fastabend <john.fastabend@gmail.com>
++R: KP Singh <kpsingh@kernel.org>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Supported
++W: https://bpf.io/
++Q: https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
++F: Documentation/bpf/
++F: Documentation/networking/filter.rst
++F: Documentation/userspace-api/ebpf/
++F: arch/*/net/*
++F: include/linux/bpf*
++F: include/linux/btf*
++F: include/linux/filter.h
++F: include/trace/events/xdp.h
++F: include/uapi/linux/bpf*
++F: include/uapi/linux/btf*
++F: include/uapi/linux/filter.h
++F: kernel/bpf/
++F: kernel/trace/bpf_trace.c
++F: lib/test_bpf.c
++F: net/bpf/
++F: net/core/filter.c
++F: net/sched/act_bpf.c
++F: net/sched/cls_bpf.c
++F: samples/bpf/
++F: scripts/bpf_doc.py
++F: tools/bpf/
++F: tools/lib/bpf/
++F: tools/testing/selftests/bpf/
++N: bpf
++K: bpf
++
++BPF JIT for ARM
++M: Shubham Bansal <illusionist.neo@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/arm/net/
++
++BPF JIT for ARM64
++M: Daniel Borkmann <daniel@iogearbox.net>
++M: Alexei Starovoitov <ast@kernel.org>
++M: Zi Shen Lim <zlim.lnx@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Supported
++F: arch/arm64/net/
++
++BPF JIT for MIPS (32-BIT AND 64-BIT)
++M: Paul Burton <paulburton@kernel.org>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/mips/net/
++
++BPF JIT for NFP NICs
++M: Jakub Kicinski <kuba@kernel.org>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/netronome/nfp/bpf/
++
++BPF JIT for POWERPC (32-BIT AND 64-BIT)
++M: Naveen N. Rao <naveen.n.rao@linux.ibm.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/powerpc/net/
++
++BPF JIT for RISC-V (32-bit)
++M: Luke Nelson <luke.r.nels@gmail.com>
++M: Xi Wang <xi.wang@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/riscv/net/
++X: arch/riscv/net/bpf_jit_comp64.c
++
++BPF JIT for RISC-V (64-bit)
++M: Björn Töpel <bjorn@kernel.org>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/riscv/net/
++X: arch/riscv/net/bpf_jit_comp32.c
++
++BPF JIT for S390
++M: Ilya Leoshkevich <iii@linux.ibm.com>
++M: Heiko Carstens <hca@linux.ibm.com>
++M: Vasily Gorbik <gor@linux.ibm.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/s390/net/
++X: arch/s390/net/pnet.c
++
++BPF JIT for SPARC (32-BIT AND 64-BIT)
++M: David S. Miller <davem@davemloft.net>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/sparc/net/
++
++BPF JIT for X86 32-BIT
++M: Wang YanQing <udknight@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: arch/x86/net/bpf_jit_comp32.c
++
++BPF JIT for X86 64-BIT
++M: Alexei Starovoitov <ast@kernel.org>
++M: Daniel Borkmann <daniel@iogearbox.net>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Supported
++F: arch/x86/net/
++X: arch/x86/net/bpf_jit_comp32.c
++
++BPF LSM (Security Audit and Enforcement using BPF)
++M: KP Singh <kpsingh@kernel.org>
++R: Florent Revest <revest@chromium.org>
++R: Brendan Jackman <jackmanb@chromium.org>
++L: bpf@vger.kernel.org
++S: Maintained
++F: Documentation/bpf/bpf_lsm.rst
++F: include/linux/bpf_lsm.h
++F: kernel/bpf/bpf_lsm.c
++F: security/bpf/
++
++BROADCOM B44 10/100 ETHERNET DRIVER
++M: Michael Chan <michael.chan@broadcom.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/b44.*
++
++BROADCOM B53 ETHERNET SWITCH DRIVER
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: netdev@vger.kernel.org
++L: openwrt-devel@lists.openwrt.org (subscribers-only)
++S: Supported
++F: Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml
++F: drivers/net/dsa/b53/*
++F: include/linux/dsa/brcm.h
++F: include/linux/platform_data/b53.h
++
++BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
++M: Nicolas Saenz Julienne <nsaenz@kernel.org>
++L: bcm-kernel-feedback-list@broadcom.com
++L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/nsaenz/linux-rpi.git
++F: Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
++F: drivers/pci/controller/pcie-brcmstb.c
++F: drivers/staging/vc04_services
++N: bcm2711
++N: bcm283*
++
++BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: Ray Jui <rjui@broadcom.com>
++M: Scott Branden <sbranden@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++T: git git://github.com/broadcom/mach-bcm
++F: arch/arm/mach-bcm/
++N: bcm281*
++N: bcm113*
++N: bcm216*
++N: kona
++
++BROADCOM BCM47XX MIPS ARCHITECTURE
++M: Hauke Mehrtens <hauke@hauke-m.de>
++M: Rafał Miłecki <zajec5@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/mips/brcm/
++F: arch/mips/bcm47xx/*
++F: arch/mips/include/asm/mach-bcm47xx/*
++
++BROADCOM BCM4908 ETHERNET DRIVER
++M: Rafał Miłecki <rafal@milecki.pl>
++M: bcm-kernel-feedback-list@broadcom.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
++F: drivers/net/ethernet/broadcom/bcm4908_enet.*
++F: drivers/net/ethernet/broadcom/unimac.h
++
++BROADCOM BCM5301X ARM ARCHITECTURE
++M: Hauke Mehrtens <hauke@hauke-m.de>
++M: Rafał Miłecki <zajec5@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/bcm470*
++F: arch/arm/boot/dts/bcm5301*
++F: arch/arm/boot/dts/bcm953012*
++F: arch/arm/mach-bcm/bcm_5301x.c
++
++BROADCOM BCM53573 ARM ARCHITECTURE
++M: Rafał Miłecki <rafal@milecki.pl>
++L: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/boot/dts/bcm47189*
++F: arch/arm/boot/dts/bcm53573*
++
++BROADCOM BCM63XX ARM ARCHITECTURE
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/broadcom/stblinux.git
++N: bcm63xx
++
++BROADCOM BCM63XX/BCM33XX UDC DRIVER
++M: Kevin Cernekee <cernekee@gmail.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/gadget/udc/bcm63xx_udc.*
++
++BROADCOM BCM7XXX ARM ARCHITECTURE
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/broadcom/stblinux.git
++F: Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
++F: arch/arm/boot/dts/bcm7*.dts*
++F: arch/arm/include/asm/hardware/cache-b15-rac.h
++F: arch/arm/mach-bcm/*brcmstb*
++F: arch/arm/mm/cache-b15-rac.c
++F: drivers/bus/brcmstb_gisb.c
++F: drivers/pci/controller/pcie-brcmstb.c
++N: brcmstb
++
++BROADCOM BDC DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-usb@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: Documentation/devicetree/bindings/usb/brcm,bdc.txt
++F: drivers/usb/gadget/udc/bdc/
++
++BROADCOM BMIPS CPUFREQ DRIVER
++M: Markus Mayer <mmayer@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: drivers/cpufreq/bmips-cpufreq.c
++
++BROADCOM BMIPS MIPS ARCHITECTURE
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: bcm-kernel-feedback-list@broadcom.com
++L: linux-mips@vger.kernel.org
++S: Maintained
++T: git git://github.com/broadcom/stblinux.git
++F: arch/mips/bmips/*
++F: arch/mips/boot/dts/brcm/bcm*.dts*
++F: arch/mips/include/asm/mach-bmips/*
++F: arch/mips/kernel/*bmips*
++F: drivers/soc/bcm/bcm63xx
++F: drivers/irqchip/irq-bcm63*
++F: drivers/irqchip/irq-bcm7*
++F: drivers/irqchip/irq-brcmstb*
++F: include/linux/bcm963xx_nvram.h
++F: include/linux/bcm963xx_tag.h
++
++BROADCOM BNX2 GIGABIT ETHERNET DRIVER
++M: Rasesh Mody <rmody@marvell.com>
++M: GR-Linux-NIC-Dev@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/bnx2.*
++F: drivers/net/ethernet/broadcom/bnx2_*
++
++BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER
++M: Saurav Kashyap <skashyap@marvell.com>
++M: Javed Hasan <jhasan@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/bnx2fc/
++
++BROADCOM BNX2I 1/10 GIGABIT iSCSI DRIVER
++M: Nilesh Javali <njavali@marvell.com>
++M: Manish Rangankar <mrangankar@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/bnx2i/
++
++BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
++M: Ariel Elior <aelior@marvell.com>
++M: Sudarsana Kalluru <skalluru@marvell.com>
++M: GR-everest-linux-l2@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/bnx2x/
++
++BROADCOM BNXT_EN 50 GIGABIT ETHERNET DRIVER
++M: Michael Chan <michael.chan@broadcom.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/bnxt/
++
++BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
++M: Arend van Spriel <aspriel@gmail.com>
++M: Franky Lin <franky.lin@broadcom.com>
++M: Hante Meuleman <hante.meuleman@broadcom.com>
++M: Chi-hsien Lin <chi-hsien.lin@infineon.com>
++M: Wright Feng <wright.feng@infineon.com>
++M: Chung-hsien Hsu <chung-hsien.hsu@infineon.com>
++L: linux-wireless@vger.kernel.org
++L: brcm80211-dev-list.pdl@broadcom.com
++L: SHA-cyfmac-dev-list@infineon.com
++S: Supported
++F: drivers/net/wireless/broadcom/brcm80211/
++
++BROADCOM BRCMSTB GPIO DRIVER
++M: Gregory Fong <gregory.0xf0@gmail.com>
++L: bcm-kernel-feedback-list@broadcom.com
++S: Supported
++F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
++F: drivers/gpio/gpio-brcmstb.c
++
++BROADCOM BRCMSTB I2C DRIVER
++M: Kamal Dasu <kdasu.kdev@gmail.com>
++L: linux-i2c@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Supported
++F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
++F: drivers/i2c/busses/i2c-brcmstb.c
++
++BROADCOM BRCMSTB UART DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-serial@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml
++F: drivers/tty/serial/8250/8250_bcm7271.c
++
++BROADCOM BRCMSTB USB EHCI DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-usb@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
++F: drivers/usb/host/ehci-brcm.*
++
++BROADCOM BRCMSTB USB PIN MAP DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-usb@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml
++F: drivers/usb/misc/brcmstb-usb-pinmap.c
++
++BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-kernel@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: drivers/phy/broadcom/phy-brcm-usb*
++
++BROADCOM ETHERNET PHY DRIVERS
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: bcm-kernel-feedback-list@broadcom.com
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/net/broadcom-bcm87xx.txt
++F: drivers/net/phy/bcm*.[ch]
++F: drivers/net/phy/broadcom.c
++F: include/linux/brcmphy.h
++
++BROADCOM GENET ETHERNET DRIVER
++M: Doug Berger <opendmb@gmail.com>
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: bcm-kernel-feedback-list@broadcom.com
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
++F: Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
++F: drivers/net/ethernet/broadcom/genet/
++F: drivers/net/ethernet/broadcom/unimac.h
++F: drivers/net/mdio/mdio-bcm-unimac.c
++F: include/linux/platform_data/bcmgenet.h
++F: include/linux/platform_data/mdio-bcm-unimac.h
++
++BROADCOM IPROC ARM ARCHITECTURE
++M: Ray Jui <rjui@broadcom.com>
++M: Scott Branden <sbranden@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/broadcom/cygnus-linux.git
++F: arch/arm64/boot/dts/broadcom/northstar2/*
++F: arch/arm64/boot/dts/broadcom/stingray/*
++F: drivers/clk/bcm/clk-ns*
++F: drivers/clk/bcm/clk-sr*
++F: drivers/pinctrl/bcm/pinctrl-ns*
++F: include/dt-bindings/clock/bcm-sr*
++N: iproc
++N: cygnus
++N: bcm[-_]nsp
++N: bcm9113*
++N: bcm9583*
++N: bcm9585*
++N: bcm9586*
++N: bcm988312
++N: bcm113*
++N: bcm583*
++N: bcm585*
++N: bcm586*
++N: bcm88312
++N: hr2
++N: stingray
++
++BROADCOM IPROC GBIT ETHERNET DRIVER
++M: Rafał Miłecki <rafal@milecki.pl>
++M: bcm-kernel-feedback-list@broadcom.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/brcm,amac.txt
++F: drivers/net/ethernet/broadcom/bgmac*
++F: drivers/net/ethernet/broadcom/unimac.h
++
++BROADCOM KONA GPIO DRIVER
++M: Ray Jui <rjui@broadcom.com>
++L: bcm-kernel-feedback-list@broadcom.com
++S: Supported
++F: Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt
++F: drivers/gpio/gpio-bcm-kona.c
++
++BROADCOM MPI3 STORAGE CONTROLLER DRIVER
++M: Sathya Prakash Veerichetty <sathya.prakash@broadcom.com>
++M: Kashyap Desai <kashyap.desai@broadcom.com>
++M: Sumit Saxena <sumit.saxena@broadcom.com>
++M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
++L: mpi3mr-linuxdrv.pdl@broadcom.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: https://www.broadcom.com/support/storage
++F: drivers/scsi/mpi3mr/
++
++BROADCOM NETXTREME-E ROCE DRIVER
++M: Selvin Xavier <selvin.xavier@broadcom.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.broadcom.com
++F: drivers/infiniband/hw/bnxt_re/
++F: include/uapi/rdma/bnxt_re-abi.h
++
++BROADCOM NVRAM DRIVER
++M: Rafał Miłecki <zajec5@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: drivers/firmware/broadcom/*
++
++BROADCOM PMB (POWER MANAGEMENT BUS) DRIVER
++M: Rafał Miłecki <rafal@milecki.pl>
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://github.com/broadcom/stblinux.git
++F: drivers/soc/bcm/bcm63xx/bcm-pmb.c
++F: include/dt-bindings/soc/bcm-pmb.h
++
++BROADCOM SPECIFIC AMBA DRIVER (BCMA)
++M: Rafał Miłecki <zajec5@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/bcma/
++F: include/linux/bcma/
++
++BROADCOM SPI DRIVER
++M: Kamal Dasu <kdasu.kdev@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.yaml
++F: drivers/spi/spi-bcm-qspi.*
++F: drivers/spi/spi-brcmstb-qspi.c
++F: drivers/spi/spi-iproc-qspi.c
++
++BROADCOM STB AVS CPUFREQ DRIVER
++M: Markus Mayer <mmayer@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
++F: drivers/cpufreq/brcmstb*
++
++BROADCOM STB AVS TMON DRIVER
++M: Markus Mayer <mmayer@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
++F: drivers/thermal/broadcom/brcmstb*
++
++BROADCOM STB DPFE DRIVER
++M: Markus Mayer <mmayer@broadcom.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/memory-controllers/brcm,dpfe-cpu.yaml
++F: drivers/memory/brcmstb_dpfe.c
++
++BROADCOM STB NAND FLASH DRIVER
++M: Brian Norris <computersforpeace@gmail.com>
++M: Kamal Dasu <kdasu.kdev@gmail.com>
++L: linux-mtd@lists.infradead.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: drivers/mtd/nand/raw/brcmnand/
++
++BROADCOM STB PCIE DRIVER
++M: Jim Quinlan <jim2101024@gmail.com>
++M: Nicolas Saenz Julienne <nsaenz@kernel.org>
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: bcm-kernel-feedback-list@broadcom.com
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
++F: drivers/pci/controller/pcie-brcmstb.c
++
++BROADCOM SYSTEMPORT ETHERNET DRIVER
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: bcm-kernel-feedback-list@broadcom.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/bcmsysport.*
++F: drivers/net/ethernet/broadcom/unimac.h
++
++BROADCOM TG3 GIGABIT ETHERNET DRIVER
++M: Siva Reddy Kallam <siva.kallam@broadcom.com>
++M: Prashant Sreedharan <prashant@broadcom.com>
++M: Michael Chan <mchan@broadcom.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/broadcom/tg3.*
++
++BROADCOM VK DRIVER
++M: Scott Branden <scott.branden@broadcom.com>
++L: bcm-kernel-feedback-list@broadcom.com
++S: Supported
++F: drivers/misc/bcm-vk/
++F: include/uapi/linux/misc/bcm_vk.h
++
++BROCADE BFA FC SCSI DRIVER
++M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
++M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/bfa/
++
++BROCADE BNA 10 GIGABIT ETHERNET DRIVER
++M: Rasesh Mody <rmody@marvell.com>
++M: Sudarsana Kalluru <skalluru@marvell.com>
++M: GR-Linux-NIC-Dev@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/brocade/bna/
++
++BSG (block layer generic sg v4 driver)
++M: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: block/bsg.c
++F: include/linux/bsg.h
++F: include/uapi/linux/bsg.h
++
++BT87X AUDIO DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: Documentation/sound/cards/bt87x.rst
++F: sound/pci/bt87x.c
++
++BT8XXGPIO DRIVER
++M: Michael Buesch <m@bues.ch>
++S: Maintained
++W: http://bu3sch.de/btgpio.php
++F: drivers/gpio/gpio-bt8xx.c
++
++BTRFS FILE SYSTEM
++M: Chris Mason <clm@fb.com>
++M: Josef Bacik <josef@toxicpanda.com>
++M: David Sterba <dsterba@suse.com>
++L: linux-btrfs@vger.kernel.org
++S: Maintained
++W: http://btrfs.wiki.kernel.org/
++Q: http://patchwork.kernel.org/project/linux-btrfs/list/
++C: irc://irc.libera.chat/btrfs
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
++F: Documentation/filesystems/btrfs.rst
++F: fs/btrfs/
++F: include/linux/btrfs*
++F: include/uapi/linux/btrfs*
++
++BTTV VIDEO4LINUX DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/driver-api/media/drivers/bttv*
++F: drivers/media/pci/bt8xx/bttv*
++
++BUS FREQUENCY DRIVER FOR SAMSUNG EXYNOS
++M: Chanwoo Choi <cw00.choi@samsung.com>
++L: linux-pm@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
++F: Documentation/devicetree/bindings/devfreq/exynos-bus.txt
++F: drivers/devfreq/exynos-bus.c
++
++BUSLOGIC SCSI DRIVER
++M: Khalid Aziz <khalid@gonehiking.org>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/BusLogic.*
++F: drivers/scsi/FlashPoint.*
++
++C-MEDIA CMI8788 DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: sound/pci/oxygen/
++
++C-SKY ARCHITECTURE
++M: Guo Ren <guoren@kernel.org>
++L: linux-csky@vger.kernel.org
++S: Supported
++T: git https://github.com/c-sky/csky-linux.git
++F: Documentation/devicetree/bindings/csky/
++F: Documentation/devicetree/bindings/interrupt-controller/csky,*
++F: Documentation/devicetree/bindings/timer/csky,*
++F: arch/csky/
++F: drivers/clocksource/timer-gx6605s.c
++F: drivers/clocksource/timer-mp-csky.c
++F: drivers/irqchip/irq-csky-*
++N: csky
++K: csky
++
++CA8210 IEEE-802.15.4 RADIO DRIVER
++M: Harry Morris <h.morris@cascoda.com>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++W: https://github.com/Cascoda/ca8210-linux.git
++F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
++F: drivers/net/ieee802154/ca8210.c
++
++CANAAN/KENDRYTE K210 SOC FPIOA DRIVER
++M: Damien Le Moal <damien.lemoal@wdc.com>
++L: linux-riscv@lists.infradead.org
++L: linux-gpio@vger.kernel.org (pinctrl driver)
++F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
++F: drivers/pinctrl/pinctrl-k210.c
++
++CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
++M: Damien Le Moal <damien.lemoal@wdc.com>
++L: linux-kernel@vger.kernel.org
++L: linux-riscv@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
++F: drivers/reset/reset-k210.c
++
++CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
++M: Damien Le Moal <damien.lemoal@wdc.com>
++L: linux-riscv@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
++F: drivers/soc/canaan/
++F: include/soc/canaan/
++
++CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
++M: David Howells <dhowells@redhat.com>
++L: linux-cachefs@redhat.com (moderated for non-subscribers)
++S: Supported
++F: Documentation/filesystems/caching/cachefiles.rst
++F: fs/cachefiles/
++
++CADENCE MIPI-CSI2 BRIDGES
++M: Maxime Ripard <mripard@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/cdns,*.txt
++F: drivers/media/platform/cadence/cdns-csi2*
++
++CADENCE NAND DRIVER
++L: linux-mtd@lists.infradead.org
++S: Orphan
++F: Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
++F: drivers/mtd/nand/raw/cadence-nand-controller.c
++
++CADENCE USB3 DRD IP DRIVER
++M: Peter Chen <peter.chen@kernel.org>
++M: Pawel Laszczak <pawell@cadence.com>
++R: Roger Quadros <rogerq@kernel.org>
++R: Aswath Govindraju <a-govindraju@ti.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
++F: Documentation/devicetree/bindings/usb/cdns,usb3.yaml
++F: drivers/usb/cdns3/
++X: drivers/usb/cdns3/cdnsp*
++
++CADENCE USBSSP DRD IP DRIVER
++M: Pawel Laszczak <pawell@cadence.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
++F: drivers/usb/cdns3/
++X: drivers/usb/cdns3/cdns3*
++
++CADET FM/AM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-cadet*
++
++CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
++L: linux-media@vger.kernel.org
++S: Orphan
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/cafe_ccic*
++F: drivers/media/platform/marvell-ccic/
++
++CAIF NETWORK LAYER
++L: netdev@vger.kernel.org
++S: Orphan
++F: Documentation/networking/caif/
++F: drivers/net/caif/
++F: include/net/caif/
++F: include/uapi/linux/caif/
++F: net/caif/
++
++CAKE QDISC
++M: Toke Høiland-Jørgensen <toke@toke.dk>
++L: cake@lists.bufferbloat.net (moderated for non-subscribers)
++S: Maintained
++F: net/sched/sch_cake.c
++
++CAN NETWORK DRIVERS
++M: Wolfgang Grandegger <wg@grandegger.com>
++M: Marc Kleine-Budde <mkl@pengutronix.de>
++L: linux-can@vger.kernel.org
++S: Maintained
++W: https://github.com/linux-can
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
++F: Documentation/devicetree/bindings/net/can/
++F: Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
++F: drivers/net/can/
++F: drivers/phy/phy-can-transceiver.c
++F: include/linux/can/bittiming.h
++F: include/linux/can/dev.h
++F: include/linux/can/led.h
++F: include/linux/can/length.h
++F: include/linux/can/platform/
++F: include/linux/can/rx-offload.h
++F: include/uapi/linux/can/error.h
++F: include/uapi/linux/can/netlink.h
++F: include/uapi/linux/can/vxcan.h
++
++CAN NETWORK LAYER
++M: Oliver Hartkopp <socketcan@hartkopp.net>
++M: Marc Kleine-Budde <mkl@pengutronix.de>
++L: linux-can@vger.kernel.org
++S: Maintained
++W: https://github.com/linux-can
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
++F: Documentation/networking/can.rst
++F: include/linux/can/can-ml.h
++F: include/linux/can/core.h
++F: include/linux/can/skb.h
++F: include/net/netns/can.h
++F: include/uapi/linux/can.h
++F: include/uapi/linux/can/bcm.h
++F: include/uapi/linux/can/gw.h
++F: include/uapi/linux/can/isotp.h
++F: include/uapi/linux/can/raw.h
++F: net/can/
++
++CAN-J1939 NETWORK LAYER
++M: Robin van der Gracht <robin@protonic.nl>
++M: Oleksij Rempel <o.rempel@pengutronix.de>
++R: kernel@pengutronix.de
++L: linux-can@vger.kernel.org
++S: Maintained
++F: Documentation/networking/j1939.rst
++F: include/uapi/linux/can/j1939.h
++F: net/can/j1939/
++
++CAPABILITIES
++M: Serge Hallyn <serge@hallyn.com>
++L: linux-security-module@vger.kernel.org
++S: Supported
++F: include/linux/capability.h
++F: include/uapi/linux/capability.h
++F: kernel/capability.c
++F: security/commoncap.c
++
++CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER
++M: Kevin Tsai <ktsai@capellamicro.com>
++S: Maintained
++F: drivers/iio/light/cm*
++
++CARL9170 LINUX COMMUNITY WIRELESS DRIVER
++M: Christian Lamparter <chunkeey@googlemail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/en/users/Drivers/carl9170
++F: drivers/net/wireless/ath/carl9170/
++
++CAVIUM I2C DRIVER
++M: Robert Richter <rric@kernel.org>
++S: Odd Fixes
++W: http://www.marvell.com
++F: drivers/i2c/busses/i2c-octeon*
++F: drivers/i2c/busses/i2c-thunderx*
++
++CAVIUM LIQUIDIO NETWORK DRIVER
++M: Derek Chickles <dchickles@marvell.com>
++M: Satanand Burla <sburla@marvell.com>
++M: Felix Manlunas <fmanlunas@marvell.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.marvell.com
++F: drivers/net/ethernet/cavium/liquidio/
++
++CAVIUM MMC DRIVER
++M: Robert Richter <rric@kernel.org>
++S: Odd Fixes
++W: http://www.marvell.com
++F: drivers/mmc/host/cavium*
++
++CAVIUM OCTEON-TX CRYPTO DRIVER
++M: George Cherian <gcherian@marvell.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++W: http://www.marvell.com
++F: drivers/crypto/cavium/cpt/
++
++CAVIUM THUNDERX2 ARM64 SOC
++M: Robert Richter <rric@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Odd Fixes
++F: Documentation/devicetree/bindings/arm/cavium-thunder2.txt
++F: arch/arm64/boot/dts/cavium/thunder2-99xx*
++
++CBS/ETF/TAPRIO QDISCS
++M: Vinicius Costa Gomes <vinicius.gomes@intel.com>
++S: Maintained
++L: netdev@vger.kernel.org
++F: net/sched/sch_cbs.c
++F: net/sched/sch_etf.c
++F: net/sched/sch_taprio.c
++
++CC2520 IEEE-802.15.4 RADIO DRIVER
++M: Varka Bhadram <varkabhadram@gmail.com>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
++F: drivers/net/ieee802154/cc2520.c
++F: include/linux/spi/cc2520.h
++
++CCREE ARM TRUSTZONE CRYPTOCELL REE DRIVER
++M: Gilad Ben-Yossef <gilad@benyossef.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
++F: drivers/crypto/ccree/
++
++CCTRNG ARM TRUSTZONE CRYPTOCELL TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
++M: Hadar Gat <hadar.gat@arm.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++F: drivers/char/hw_random/cctrng.c
++F: drivers/char/hw_random/cctrng.h
++F: Documentation/devicetree/bindings/rng/arm-cctrng.yaml
++W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
++
++CEC FRAMEWORK
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Supported
++W: http://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/ABI/testing/debugfs-cec-error-inj
++F: Documentation/devicetree/bindings/media/cec.txt
++F: Documentation/driver-api/media/cec-core.rst
++F: Documentation/userspace-api/media/cec
++F: drivers/media/cec/
++F: drivers/media/rc/keymaps/rc-cec.c
++F: include/media/cec-notifier.h
++F: include/media/cec.h
++F: include/uapi/linux/cec-funcs.h
++F: include/uapi/linux/cec.h
++
++CEC GPIO DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Supported
++W: http://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/cec-gpio.txt
++F: drivers/media/cec/platform/cec-gpio/
++
++CELL BROADBAND ENGINE ARCHITECTURE
++M: Arnd Bergmann <arnd@arndb.de>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++W: http://www.ibm.com/developerworks/power/cell/
++F: arch/powerpc/include/asm/cell*.h
++F: arch/powerpc/include/asm/spu*.h
++F: arch/powerpc/include/uapi/asm/spu*.h
++F: arch/powerpc/platforms/cell/
++
++CELLWISE CW2015 BATTERY DRIVER
++M: Tobias Schrammm <t.schramm@manjaro.org>
++S: Maintained
++F: Documentation/devicetree/bindings/power/supply/cw2015_battery.yaml
++F: drivers/power/supply/cw2015_battery.c
++
++CEPH COMMON CODE (LIBCEPH)
++M: Ilya Dryomov <idryomov@gmail.com>
++M: Jeff Layton <jlayton@kernel.org>
++L: ceph-devel@vger.kernel.org
++S: Supported
++W: http://ceph.com/
++T: git git://github.com/ceph/ceph-client.git
++F: include/linux/ceph/
++F: include/linux/crush/
++F: net/ceph/
++
++CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
++M: Jeff Layton <jlayton@kernel.org>
++M: Ilya Dryomov <idryomov@gmail.com>
++L: ceph-devel@vger.kernel.org
++S: Supported
++W: http://ceph.com/
++T: git git://github.com/ceph/ceph-client.git
++F: Documentation/filesystems/ceph.rst
++F: fs/ceph/
++
++CERTIFICATE HANDLING
++M: David Howells <dhowells@redhat.com>
++M: David Woodhouse <dwmw2@infradead.org>
++L: keyrings@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/module-signing.rst
++F: certs/
++F: scripts/extract-cert.c
++F: scripts/sign-file.c
++
++CFAG12864B LCD DRIVER
++M: Miguel Ojeda <ojeda@kernel.org>
++S: Maintained
++F: drivers/auxdisplay/cfag12864b.c
++F: include/linux/cfag12864b.h
++
++CFAG12864BFB LCD FRAMEBUFFER DRIVER
++M: Miguel Ojeda <ojeda@kernel.org>
++S: Maintained
++F: drivers/auxdisplay/cfag12864bfb.c
++F: include/linux/cfag12864b.h
++
++CHAR and MISC DRIVERS
++M: Arnd Bergmann <arnd@arndb.de>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
++F: drivers/char/
++F: drivers/misc/
++F: include/linux/miscdevice.h
++X: drivers/char/agp/
++X: drivers/char/hw_random/
++X: drivers/char/ipmi/
++X: drivers/char/random.c
++X: drivers/char/tpm/
++
++CHECKPATCH
++M: Andy Whitcroft <apw@canonical.com>
++M: Joe Perches <joe@perches.com>
++R: Dwaipayan Ray <dwaipayanray1@gmail.com>
++R: Lukas Bulwahn <lukas.bulwahn@gmail.com>
++S: Maintained
++F: scripts/checkpatch.pl
++
++CHECKPATCH DOCUMENTATION
++M: Dwaipayan Ray <dwaipayanray1@gmail.com>
++M: Lukas Bulwahn <lukas.bulwahn@gmail.com>
++R: Joe Perches <joe@perches.com>
++S: Maintained
++F: Documentation/dev-tools/checkpatch.rst
++
++CHINESE DOCUMENTATION
++M: Alex Shi <alexs@kernel.org>
++S: Maintained
++F: Documentation/translations/zh_CN/
++
++CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
++M: Peter Chen <peter.chen@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
++F: drivers/usb/chipidea/
++
++CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
++F: drivers/input/touchscreen/chipone_icn8318.c
++
++CHIPONE ICN8505 I2C TOUCHSCREEN DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/chipone_icn8505.c
++
++CHROME HARDWARE PLATFORM SUPPORT
++M: Benson Leung <bleung@chromium.org>
++M: Enric Balletbo i Serra <enric.balletbo@collabora.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
++F: drivers/platform/chrome/
++
++CHROMEOS EC CODEC DRIVER
++M: Cheng-Yi Chiang <cychiang@chromium.org>
++R: Enric Balletbo i Serra <enric.balletbo@collabora.com>
++R: Guenter Roeck <groeck@chromium.org>
++S: Maintained
++F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
++F: sound/soc/codecs/cros_ec_codec.*
++
++CHROMEOS EC SUBDRIVERS
++M: Benson Leung <bleung@chromium.org>
++M: Enric Balletbo i Serra <enric.balletbo@collabora.com>
++R: Guenter Roeck <groeck@chromium.org>
++S: Maintained
++F: drivers/power/supply/cros_usbpd-charger.c
++N: cros_ec
++N: cros-ec
++
++CHRONTEL CH7322 CEC DRIVER
++M: Jeff Chase <jnchase@google.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml
++F: drivers/media/cec/i2c/ch7322.c
++
++CIRRUS LOGIC AUDIO CODEC DRIVERS
++M: James Schulman <james.schulman@cirrus.com>
++M: David Rhodes <david.rhodes@cirrus.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++L: patches@opensource.cirrus.com
++S: Maintained
++F: sound/soc/codecs/cs*
++
++CIRRUS LOGIC EP93XX ETHERNET DRIVER
++M: Hartley Sweeten <hsweeten@visionengravers.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/cirrus/ep93xx_eth.c
++
++CIRRUS LOGIC LOCHNAGAR DRIVER
++M: Charles Keepax <ckeepax@opensource.cirrus.com>
++M: Richard Fitzgerald <rf@opensource.cirrus.com>
++L: patches@opensource.cirrus.com
++S: Supported
++F: Documentation/devicetree/bindings/clock/cirrus,lochnagar.yaml
++F: Documentation/devicetree/bindings/hwmon/cirrus,lochnagar.yaml
++F: Documentation/devicetree/bindings/mfd/cirrus,lochnagar.yaml
++F: Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml
++F: Documentation/devicetree/bindings/sound/cirrus,lochnagar.yaml
++F: Documentation/hwmon/lochnagar.rst
++F: drivers/clk/clk-lochnagar.c
++F: drivers/hwmon/lochnagar-hwmon.c
++F: drivers/mfd/lochnagar-i2c.c
++F: drivers/pinctrl/cirrus/pinctrl-lochnagar.c
++F: drivers/regulator/lochnagar-regulator.c
++F: include/dt-bindings/clk/lochnagar.h
++F: include/dt-bindings/pinctrl/lochnagar.h
++F: include/linux/mfd/lochnagar*
++F: sound/soc/codecs/lochnagar-sc.c
++
++CIRRUS LOGIC MADERA CODEC DRIVERS
++M: Charles Keepax <ckeepax@opensource.cirrus.com>
++M: Richard Fitzgerald <rf@opensource.cirrus.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++L: patches@opensource.cirrus.com
++S: Supported
++W: https://github.com/CirrusLogic/linux-drivers/wiki
++T: git https://github.com/CirrusLogic/linux-drivers.git
++F: Documentation/devicetree/bindings/mfd/cirrus,madera.yaml
++F: Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml
++F: Documentation/devicetree/bindings/sound/cirrus,madera.yaml
++F: drivers/gpio/gpio-madera*
++F: drivers/irqchip/irq-madera*
++F: drivers/mfd/cs47l*
++F: drivers/mfd/madera*
++F: drivers/pinctrl/cirrus/*
++F: include/dt-bindings/sound/madera*
++F: include/linux/irqchip/irq-madera*
++F: include/linux/mfd/madera/*
++F: include/sound/madera*
++F: sound/soc/codecs/cs47l*
++F: sound/soc/codecs/madera*
++
++CISCO FCOE HBA DRIVER
++M: Satish Kharat <satishkh@cisco.com>
++M: Sesidhar Baddela <sebaddel@cisco.com>
++M: Karan Tilak Kumar <kartilak@cisco.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/fnic/
++
++CISCO SCSI HBA DRIVER
++M: Karan Tilak Kumar <kartilak@cisco.com>
++M: Sesidhar Baddela <sebaddel@cisco.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/snic/
++
++CISCO VIC ETHERNET NIC DRIVER
++M: Christian Benvenuti <benve@cisco.com>
++M: Govindarajulu Varadarajan <_govind@gmx.com>
++S: Supported
++F: drivers/net/ethernet/cisco/enic/
++
++CISCO VIC LOW LATENCY NIC DRIVER
++M: Christian Benvenuti <benve@cisco.com>
++M: Nelson Escobar <neescoba@cisco.com>
++S: Supported
++F: drivers/infiniband/hw/usnic/
++
++CLANG-FORMAT FILE
++M: Miguel Ojeda <ojeda@kernel.org>
++S: Maintained
++F: .clang-format
++
++CLANG/LLVM BUILD SUPPORT
++M: Nathan Chancellor <nathan@kernel.org>
++M: Nick Desaulniers <ndesaulniers@google.com>
++L: llvm@lists.linux.dev
++S: Supported
++W: https://clangbuiltlinux.github.io/
++B: https://github.com/ClangBuiltLinux/linux/issues
++C: irc://irc.libera.chat/clangbuiltlinux
++F: Documentation/kbuild/llvm.rst
++F: include/linux/compiler-clang.h
++F: scripts/Makefile.clang
++F: scripts/clang-tools/
++K: \b(?i:clang|llvm)\b
++
++CLANG CONTROL FLOW INTEGRITY SUPPORT
++M: Sami Tolvanen <samitolvanen@google.com>
++M: Kees Cook <keescook@chromium.org>
++R: Nathan Chancellor <nathan@kernel.org>
++R: Nick Desaulniers <ndesaulniers@google.com>
++L: llvm@lists.linux.dev
++S: Supported
++B: https://github.com/ClangBuiltLinux/linux/issues
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/clang/features
++F: include/linux/cfi.h
++F: kernel/cfi.c
++
++CLEANCACHE API
++M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: include/linux/cleancache.h
++F: mm/cleancache.c
++
++CLK API
++M: Russell King <linux@armlinux.org.uk>
++L: linux-clk@vger.kernel.org
++S: Maintained
++F: include/linux/clk.h
++
++CLOCKSOURCE, CLOCKEVENT DRIVERS
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++M: Thomas Gleixner <tglx@linutronix.de>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
++F: Documentation/devicetree/bindings/timer/
++F: drivers/clocksource/
++
++CMPC ACPI DRIVER
++M: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
++M: Daniel Oliveira Nascimento <don@syst.com.br>
++L: platform-driver-x86@vger.kernel.org
++S: Supported
++F: drivers/platform/x86/classmate-laptop.c
++
++COBALT MEDIA DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/cobalt/
++
++COCCINELLE/Semantic Patches (SmPL)
++M: Julia Lawall <Julia.Lawall@inria.fr>
++M: Gilles Muller <Gilles.Muller@inria.fr>
++M: Nicolas Palix <nicolas.palix@imag.fr>
++M: Michal Marek <michal.lkml@markovi.net>
++L: cocci@systeme.lip6.fr (moderated for non-subscribers)
++S: Supported
++W: http://coccinelle.lip6.fr/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
++F: Documentation/dev-tools/coccinelle.rst
++F: scripts/coccicheck
++F: scripts/coccinelle/
++
++CODA FILE SYSTEM
++M: Jan Harkes <jaharkes@cs.cmu.edu>
++M: coda@cs.cmu.edu
++L: codalist@coda.cs.cmu.edu
++S: Maintained
++W: http://www.coda.cs.cmu.edu/
++F: Documentation/filesystems/coda.rst
++F: fs/coda/
++F: include/linux/coda*.h
++F: include/uapi/linux/coda*.h
++
++CODA V4L2 MEM2MEM DRIVER
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/coda.yaml
++F: drivers/media/platform/coda/
++
++CODE OF CONDUCT
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++S: Supported
++F: Documentation/process/code-of-conduct-interpretation.rst
++F: Documentation/process/code-of-conduct.rst
++
++COMEDI DRIVERS
++M: Ian Abbott <abbotti@mev.co.uk>
++M: H Hartley Sweeten <hsweeten@visionengravers.com>
++S: Odd Fixes
++F: drivers/comedi/
++
++COMMON CLK FRAMEWORK
++M: Michael Turquette <mturquette@baylibre.com>
++M: Stephen Boyd <sboyd@kernel.org>
++L: linux-clk@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-clk/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
++F: Documentation/devicetree/bindings/clock/
++F: drivers/clk/
++F: include/linux/clk-pr*
++F: include/linux/clk/
++F: include/linux/of_clk.h
++X: drivers/clk/clkdev.c
++
++COMMON INTERNET FILE SYSTEM CLIENT (CIFS)
++M: Steve French <sfrench@samba.org>
++L: linux-cifs@vger.kernel.org
++L: samba-technical@lists.samba.org (moderated for non-subscribers)
++S: Supported
++W: http://linux-cifs.samba.org/
++T: git git://git.samba.org/sfrench/cifs-2.6.git
++F: Documentation/admin-guide/cifs/
++F: fs/cifs/
++F: fs/smbfs_common/
++
++COMPACTPCI HOTPLUG CORE
++M: Scott Murray <scott@spiteful.org>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: drivers/pci/hotplug/cpci_hotplug*
++
++COMPACTPCI HOTPLUG GENERIC DRIVER
++M: Scott Murray <scott@spiteful.org>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: drivers/pci/hotplug/cpcihp_generic.c
++
++COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
++M: Scott Murray <scott@spiteful.org>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: drivers/pci/hotplug/cpcihp_zt5550.*
++
++COMPAL LAPTOP SUPPORT
++M: Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/compal-laptop.c
++
++COMPILER ATTRIBUTES
++M: Miguel Ojeda <ojeda@kernel.org>
++R: Nick Desaulniers <ndesaulniers@google.com>
++S: Maintained
++F: include/linux/compiler_attributes.h
++
++COMPUTE EXPRESS LINK (CXL)
++M: Alison Schofield <alison.schofield@intel.com>
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Ira Weiny <ira.weiny@intel.com>
++M: Ben Widawsky <ben.widawsky@intel.com>
++M: Dan Williams <dan.j.williams@intel.com>
++L: linux-cxl@vger.kernel.org
++S: Maintained
++F: drivers/cxl/
++F: include/uapi/linux/cxl_mem.h
++
++CONEXANT ACCESSRUNNER USB DRIVER
++L: accessrunner-general@lists.sourceforge.net
++S: Orphan
++W: http://accessrunner.sourceforge.net/
++F: drivers/usb/atm/cxacru.c
++
++CONFIGFS
++M: Joel Becker <jlbec@evilplan.org>
++M: Christoph Hellwig <hch@lst.de>
++S: Supported
++T: git git://git.infradead.org/users/hch/configfs.git
++F: fs/configfs/
++F: include/linux/configfs.h
++F: samples/configfs/
++
++CONSOLE SUBSYSTEM
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++S: Supported
++F: drivers/video/console/
++F: include/linux/console*
++
++CONTEXT TRACKING
++M: Frederic Weisbecker <frederic@kernel.org>
++S: Maintained
++F: kernel/context_tracking.c
++F: include/linux/context_tracking*
++
++CONTROL GROUP (CGROUP)
++M: Tejun Heo <tj@kernel.org>
++M: Zefan Li <lizefan.x@bytedance.com>
++M: Johannes Weiner <hannes@cmpxchg.org>
++L: cgroups@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
++F: Documentation/admin-guide/cgroup-v1/
++F: Documentation/admin-guide/cgroup-v2.rst
++F: include/linux/cgroup*
++F: kernel/cgroup/
++
++CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
++M: Tejun Heo <tj@kernel.org>
++M: Jens Axboe <axboe@kernel.dk>
++L: cgroups@vger.kernel.org
++L: linux-block@vger.kernel.org
++T: git git://git.kernel.dk/linux-block
++F: Documentation/admin-guide/cgroup-v1/blkio-controller.rst
++F: block/bfq-cgroup.c
++F: block/blk-cgroup.c
++F: block/blk-iolatency.c
++F: block/blk-throttle.c
++F: include/linux/blk-cgroup.h
++
++CONTROL GROUP - CPUSET
++M: Zefan Li <lizefan.x@bytedance.com>
++L: cgroups@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
++F: Documentation/admin-guide/cgroup-v1/cpusets.rst
++F: include/linux/cpuset.h
++F: kernel/cgroup/cpuset.c
++
++CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
++M: Johannes Weiner <hannes@cmpxchg.org>
++M: Michal Hocko <mhocko@kernel.org>
++M: Vladimir Davydov <vdavydov.dev@gmail.com>
++L: cgroups@vger.kernel.org
++L: linux-mm@kvack.org
++S: Maintained
++F: mm/memcontrol.c
++F: mm/swap_cgroup.c
++
++CORETEMP HARDWARE MONITORING DRIVER
++M: Fenghua Yu <fenghua.yu@intel.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/coretemp.rst
++F: drivers/hwmon/coretemp.c
++
++CORSAIR-CPRO HARDWARE MONITOR DRIVER
++M: Marius Zachmann <mail@mariuszachmann.de>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/corsair-cpro.c
++
++CORSAIR-PSU HARDWARE MONITOR DRIVER
++M: Wilken Gottwalt <wilken.gottwalt@posteo.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/corsair-psu.rst
++F: drivers/hwmon/corsair-psu.c
++
++COSA/SRP SYNC SERIAL DRIVER
++M: Jan "Yenya" Kasprzak <kas@fi.muni.cz>
++S: Maintained
++W: http://www.fi.muni.cz/~kas/cosa/
++F: drivers/net/wan/cosa*
++
++COUNTER SUBSYSTEM
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-counter
++F: Documentation/driver-api/generic-counter.rst
++F: drivers/counter/
++F: include/linux/counter.h
++F: include/linux/counter_enum.h
++
++CP2615 I2C DRIVER
++M: Bence Csókás <bence98@sch.bme.hu>
++S: Maintained
++F: drivers/i2c/busses/i2c-cp2615.c
++
++CPMAC ETHERNET DRIVER
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/ti/cpmac.c
++
++CPU FREQUENCY DRIVERS - VEXPRESS SPC ARM BIG LITTLE
++M: Viresh Kumar <viresh.kumar@linaro.org>
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
++F: drivers/cpufreq/vexpress-spc-cpufreq.c
++
++CPU FREQUENCY SCALING FRAMEWORK
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Viresh Kumar <viresh.kumar@linaro.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git (For ARM Updates)
++F: Documentation/admin-guide/pm/cpufreq.rst
++F: Documentation/admin-guide/pm/intel_pstate.rst
++F: Documentation/cpu-freq/
++F: Documentation/devicetree/bindings/cpufreq/
++F: drivers/cpufreq/
++F: include/linux/cpufreq.h
++F: include/linux/sched/cpufreq.h
++F: kernel/sched/cpufreq*.c
++F: tools/testing/selftests/cpufreq/
++
++CPU IDLE TIME MANAGEMENT FRAMEWORK
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
++F: Documentation/admin-guide/pm/cpuidle.rst
++F: Documentation/driver-api/pm/cpuidle.rst
++F: drivers/cpuidle/
++F: include/linux/cpuidle.h
++
++CPU POWER MONITORING SUBSYSTEM
++M: Thomas Renninger <trenn@suse.com>
++M: Shuah Khan <shuah@kernel.org>
++M: Shuah Khan <skhan@linuxfoundation.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: tools/power/cpupower/
++
++CPUID/MSR DRIVER
++M: "H. Peter Anvin" <hpa@zytor.com>
++S: Maintained
++F: arch/x86/kernel/cpuid.c
++F: arch/x86/kernel/msr.c
++
++CPUIDLE DRIVER - ARM BIG LITTLE
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++L: linux-pm@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
++F: drivers/cpuidle/cpuidle-big_little.c
++
++CPUIDLE DRIVER - ARM EXYNOS
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++M: Kukjin Kim <kgene@kernel.org>
++L: linux-pm@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Supported
++F: arch/arm/mach-exynos/pm.c
++F: drivers/cpuidle/cpuidle-exynos.c
++F: include/linux/platform_data/cpuidle-exynos.h
++
++CPUIDLE DRIVER - ARM PSCI
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-pm@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/cpuidle/cpuidle-psci.c
++
++CPUIDLE DRIVER - ARM PSCI PM DOMAIN
++M: Ulf Hansson <ulf.hansson@linaro.org>
++L: linux-pm@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/cpuidle/cpuidle-psci.h
++F: drivers/cpuidle/cpuidle-psci-domain.c
++
++CRAMFS FILESYSTEM
++M: Nicolas Pitre <nico@fluxnic.net>
++S: Maintained
++F: Documentation/filesystems/cramfs.rst
++F: fs/cramfs/
++
++CREATIVE SB0540
++M: Bastien Nocera <hadess@hadess.net>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-creative-sb0540.c
++
++CRYPTO API
++M: Herbert Xu <herbert@gondor.apana.org.au>
++M: "David S. Miller" <davem@davemloft.net>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git
++F: Documentation/crypto/
++F: Documentation/devicetree/bindings/crypto/
++F: arch/*/crypto/
++F: crypto/
++F: drivers/crypto/
++F: include/crypto/
++F: include/linux/crypto*
++F: lib/crypto/
++
++CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
++M: Neil Horman <nhorman@tuxdriver.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: crypto/ansi_cprng.c
++F: crypto/rng.c
++
++CS3308 MEDIA DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: http://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/cs3308.c
++
++CS5535 Audio ALSA driver
++M: Jaya Kumar <jayakumar.alsa@gmail.com>
++S: Maintained
++F: sound/pci/cs5535audio/
++
++CSI DRIVERS FOR ALLWINNER V3s
++M: Yong Deng <yong.deng@magewell.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
++F: drivers/media/platform/sunxi/sun6i-csi/
++
++CW1200 WLAN driver
++M: Solomon Peachy <pizza@shaftnet.org>
++S: Maintained
++F: drivers/net/wireless/st/cw1200/
++
++CX18 VIDEO4LINUX DRIVER
++M: Andy Walls <awalls@md.metrocast.net>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/cx18/
++F: include/uapi/linux/ivtv*
++
++CX2341X MPEG ENCODER HELPER MODULE
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/common/cx2341x*
++F: include/media/drv-intf/cx2341x.h
++
++CX24120 MEDIA DRIVER
++M: Jemma Denson <jdenson@gmail.com>
++M: Patrick Boettcher <patrick.boettcher@posteo.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/cx24120*
++
++CX88 VIDEO4LINUX DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/driver-api/media/drivers/cx88*
++F: drivers/media/pci/cx88/
++
++CXD2820R MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/cxd2820r*
++
++CXGB3 ETHERNET DRIVER (CXGB3)
++M: Raju Rangoju <rajur@chelsio.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/net/ethernet/chelsio/cxgb3/
++
++CXGB3 ISCSI DRIVER (CXGB3I)
++M: Karen Xie <kxie@chelsio.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/scsi/cxgbi/cxgb3i
++
++CXGB4 CRYPTO DRIVER (chcr)
++M: Ayush Sawal <ayush.sawal@chelsio.com>
++M: Vinay Kumar Yadav <vinay.yadav@chelsio.com>
++M: Rohit Maheshwari <rohitm@chelsio.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/crypto/chelsio
++
++CXGB4 INLINE CRYPTO DRIVER
++M: Ayush Sawal <ayush.sawal@chelsio.com>
++M: Vinay Kumar Yadav <vinay.yadav@chelsio.com>
++M: Rohit Maheshwari <rohitm@chelsio.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/net/ethernet/chelsio/inline_crypto/
++
++CXGB4 ETHERNET DRIVER (CXGB4)
++M: Raju Rangoju <rajur@chelsio.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/net/ethernet/chelsio/cxgb4/
++
++CXGB4 ISCSI DRIVER (CXGB4I)
++M: Karen Xie <kxie@chelsio.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/scsi/cxgbi/cxgb4i
++
++CXGB4 IWARP RNIC DRIVER (IW_CXGB4)
++M: Potnuri Bharat Teja <bharat@chelsio.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.openfabrics.org
++F: drivers/infiniband/hw/cxgb4/
++F: include/uapi/rdma/cxgb4-abi.h
++
++CXGB4VF ETHERNET DRIVER (CXGB4VF)
++M: Raju Rangoju <rajur@chelsio.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.chelsio.com
++F: drivers/net/ethernet/chelsio/cxgb4vf/
++
++CXL (IBM Coherent Accelerator Processor Interface CAPI) DRIVER
++M: Frederic Barrat <fbarrat@linux.ibm.com>
++M: Andrew Donnellan <ajd@linux.ibm.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: Documentation/ABI/testing/sysfs-class-cxl
++F: Documentation/powerpc/cxl.rst
++F: arch/powerpc/platforms/powernv/pci-cxl.c
++F: drivers/misc/cxl/
++F: include/misc/cxl*
++F: include/uapi/misc/cxl.h
++
++CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER
++M: Manoj N. Kumar <manoj@linux.ibm.com>
++M: Matthew R. Ochs <mrochs@linux.ibm.com>
++M: Uma Krishnan <ukrishn@linux.ibm.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: Documentation/powerpc/cxlflash.rst
++F: drivers/scsi/cxlflash/
++F: include/uapi/scsi/cxlflash_ioctl.h
++
++CYBERPRO FB DRIVER
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.armlinux.org.uk/
++F: drivers/video/fbdev/cyber2000fb.*
++
++CYCLADES PC300 DRIVER
++S: Orphan
++F: drivers/net/wan/pc300*
++
++CYPRESS_FIRMWARE MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/common/cypress_firmware*
++
++CYPRESS CY8CTMA140 TOUCHSCREEN DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/cy8ctma140.c
++
++CYTTSP TOUCHSCREEN DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/cyttsp*
++
++D-LINK DIR-685 TOUCHKEYS DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-input@vger.kernel.org
++S: Supported
++F: drivers/input/keyboard/dlink-dir685-touchkeys.c
++
++DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK
++M: Joshua Kinard <kumba@gentoo.org>
++S: Maintained
++F: drivers/rtc/rtc-ds1685.c
++F: include/linux/rtc/ds1685.h
++
++DAMA SLAVE for AX.25
++M: Joerg Reuter <jreuter@yaina.de>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://yaina.de/jreuter/
++W: http://www.qsl.net/dl1bke/
++F: net/ax25/af_ax25.c
++F: net/ax25/ax25_dev.c
++F: net/ax25/ax25_ds_*
++F: net/ax25/ax25_in.c
++F: net/ax25/ax25_out.c
++F: net/ax25/ax25_timer.c
++F: net/ax25/sysctl_net_ax25.c
++
++DATA ACCESS MONITOR
++M: SeongJae Park <sjpark@amazon.de>
++L: linux-mm@kvack.org
++S: Maintained
++F: Documentation/admin-guide/mm/damon/
++F: Documentation/vm/damon/
++F: include/linux/damon.h
++F: include/trace/events/damon.h
++F: mm/damon/
++F: tools/testing/selftests/damon/
++
++DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
++L: netdev@vger.kernel.org
++S: Orphan
++F: Documentation/networking/device_drivers/ethernet/dec/dmfe.rst
++F: drivers/net/ethernet/dec/tulip/dmfe.c
++
++DC390/AM53C974 SCSI driver
++M: Hannes Reinecke <hare@suse.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/am53c974.c
++
++DC395x SCSI driver
++M: Oliver Neukum <oliver@neukum.org>
++M: Ali Akcaagac <aliakc@web.de>
++M: Jamie Lenehan <lenehan@twibble.org>
++L: dc395x@twibble.org
++S: Maintained
++W: http://twibble.org/dist/dc395x/
++W: http://lists.twibble.org/mailman/listinfo/dc395x/
++F: Documentation/scsi/dc395x.rst
++F: drivers/scsi/dc395x.*
++
++DCCP PROTOCOL
++L: dccp@vger.kernel.org
++S: Orphan
++W: http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
++F: include/linux/dccp.h
++F: include/linux/tfrc.h
++F: include/uapi/linux/dccp.h
++F: net/dccp/
++
++DECnet NETWORK LAYER
++L: linux-decnet-user@lists.sourceforge.net
++S: Orphan
++W: http://linux-decnet.sourceforge.net
++F: Documentation/networking/decnet.rst
++F: net/decnet/
++
++DECSTATION PLATFORM SUPPORT
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++L: linux-mips@vger.kernel.org
++S: Maintained
++W: http://www.linux-mips.org/wiki/DECstation
++F: arch/mips/dec/
++F: arch/mips/include/asm/dec/
++F: arch/mips/include/asm/mach-dec/
++
++DEFXX FDDI NETWORK DRIVER
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++S: Maintained
++F: drivers/net/fddi/defxx.*
++
++DEFZA FDDI NETWORK DRIVER
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++S: Maintained
++F: drivers/net/fddi/defza.*
++
++DEINTERLACE DRIVERS FOR ALLWINNER H3
++M: Jernej Skrabec <jernej.skrabec@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml
++F: drivers/media/platform/sunxi/sun8i-di/
++
++DELL LAPTOP DRIVER
++M: Matthew Garrett <mjg59@srcf.ucam.org>
++M: Pali Rohár <pali@kernel.org>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell-laptop.c
++
++DELL LAPTOP FREEFALL DRIVER
++M: Pali Rohár <pali@kernel.org>
++S: Maintained
++F: drivers/platform/x86/dell/dell-smo8800.c
++
++DELL LAPTOP RBTN DRIVER
++M: Pali Rohár <pali@kernel.org>
++S: Maintained
++F: drivers/platform/x86/dell/dell-rbtn.*
++
++DELL LAPTOP SMM DRIVER
++M: Pali Rohár <pali@kernel.org>
++S: Maintained
++F: drivers/hwmon/dell-smm-hwmon.c
++F: include/uapi/linux/i8k.h
++
++DELL REMOTE BIOS UPDATE DRIVER
++M: Stuart Hayes <stuart.w.hayes@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell_rbu.c
++
++DELL SMBIOS DRIVER
++M: Pali Rohár <pali@kernel.org>
++L: Dell.Client.Kernel@dell.com
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell-smbios.*
++
++DELL SMBIOS SMM DRIVER
++L: Dell.Client.Kernel@dell.com
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell-smbios-smm.c
++
++DELL SMBIOS WMI DRIVER
++L: Dell.Client.Kernel@dell.com
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell-smbios-wmi.c
++F: tools/wmi/dell-smbios-example.c
++
++DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
++M: Stuart Hayes <stuart.w.hayes@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/driver-api/dcdbas.rst
++F: drivers/platform/x86/dell/dcdbas.*
++
++DELL WMI DESCRIPTOR DRIVER
++L: Dell.Client.Kernel@dell.com
++S: Maintained
++F: drivers/platform/x86/dell/dell-wmi-descriptor.c
++
++DELL WMI SYSMAN DRIVER
++M: Divya Bharathi <divya.bharathi@dell.com>
++M: Prasanth Ksr <prasanth.ksr@dell.com>
++L: Dell.Client.Kernel@dell.com
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-firmware-attributes
++F: drivers/platform/x86/dell/dell-wmi-sysman/
++
++DELL WMI NOTIFICATIONS DRIVER
++M: Matthew Garrett <mjg59@srcf.ucam.org>
++M: Pali Rohár <pali@kernel.org>
++S: Maintained
++F: drivers/platform/x86/dell/dell-wmi-base.c
++
++DELL WMI HARDWARE PRIVACY SUPPORT
++M: Perry Yuan <Perry.Yuan@dell.com>
++L: Dell.Client.Kernel@dell.com
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/dell/dell-wmi-privacy.c
++
++DELTA ST MEDIA DRIVER
++M: Hugues Fruchet <hugues.fruchet@foss.st.com>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/platform/sti/delta
++
++DELTA DPS920AB PSU DRIVER
++M: Robert Marko <robert.marko@sartura.hr>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/dps920ab.rst
++F: drivers/hwmon/pmbus/dps920ab.c
++
++DENALI NAND DRIVER
++L: linux-mtd@lists.infradead.org
++S: Orphan
++F: drivers/mtd/nand/raw/denali*
++
++DESIGNWARE EDMA CORE IP DRIVER
++M: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
++L: dmaengine@vger.kernel.org
++S: Maintained
++F: drivers/dma/dw-edma/
++F: include/linux/dma/edma.h
++
++DESIGNWARE XDATA IP DRIVER
++M: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/misc-devices/dw-xdata-pcie.rst
++F: drivers/misc/dw-xdata-pcie.c
++
++DESIGNWARE USB2 DRD IP DRIVER
++M: Minas Harutyunyan <hminas@synopsys.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
++F: drivers/usb/dwc2/
++
++DESIGNWARE USB3 DRD IP DRIVER
++M: Felipe Balbi <balbi@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
++F: drivers/usb/dwc3/
++
++DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER
++M: Andreas Klinger <ak@it-klinger.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
++F: drivers/iio/proximity/srf*.c
++
++DEVICE COREDUMP (DEV_COREDUMP)
++M: Johannes Berg <johannes@sipsolutions.net>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/base/devcoredump.c
++F: include/linux/devcoredump.h
++
++DEVICE DEPENDENCY HELPER SCRIPT
++M: Saravana Kannan <saravanak@google.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: scripts/dev-needs.sh
++
++DEVICE DIRECT ACCESS (DAX)
++M: Dan Williams <dan.j.williams@intel.com>
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Dave Jiang <dave.jiang@intel.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++F: drivers/dax/
++
++DEVICE FREQUENCY (DEVFREQ)
++M: MyungJoo Ham <myungjoo.ham@samsung.com>
++M: Kyungmin Park <kyungmin.park@samsung.com>
++M: Chanwoo Choi <cw00.choi@samsung.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
++F: Documentation/devicetree/bindings/devfreq/
++F: drivers/devfreq/
++F: include/linux/devfreq.h
++F: include/trace/events/devfreq.h
++
++DEVICE FREQUENCY EVENT (DEVFREQ-EVENT)
++M: Chanwoo Choi <cw00.choi@samsung.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
++F: Documentation/devicetree/bindings/devfreq/event/
++F: drivers/devfreq/devfreq-event.c
++F: drivers/devfreq/event/
++F: include/dt-bindings/pmu/exynos_ppmu.h
++F: include/linux/devfreq-event.h
++
++DEVICE NUMBER REGISTRY
++M: Torben Mathiasen <device@lanana.org>
++S: Maintained
++W: http://lanana.org/docs/device-list/index.html
++
++DEVICE RESOURCE MANAGEMENT HELPERS
++M: Hans de Goede <hdegoede@redhat.com>
++R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
++S: Maintained
++F: include/linux/devm-helpers.h
++
++DEVICE-MAPPER (LVM)
++M: Alasdair Kergon <agk@redhat.com>
++M: Mike Snitzer <snitzer@redhat.com>
++M: dm-devel@redhat.com
++L: dm-devel@redhat.com
++S: Maintained
++W: http://sources.redhat.com/dm
++Q: http://patchwork.kernel.org/project/dm-devel/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git
++T: quilt http://people.redhat.com/agk/patches/linux/editing/
++F: Documentation/admin-guide/device-mapper/
++F: drivers/md/Kconfig
++F: drivers/md/Makefile
++F: drivers/md/dm*
++F: drivers/md/persistent-data/
++F: include/linux/device-mapper.h
++F: include/linux/dm-*.h
++F: include/uapi/linux/dm-*.h
++
++DEVLINK
++M: Jiri Pirko <jiri@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/devlink
++F: include/net/devlink.h
++F: include/uapi/linux/devlink.h
++F: net/core/devlink.c
++
++DH ELECTRONICS IMX6 DHCOM BOARD SUPPORT
++M: Christoph Niedermaier <cniedermaier@dh-electronics.com>
++L: kernel@dh-electronics.com
++S: Maintained
++F: arch/arm/boot/dts/imx6*-dhcom-*
++
++DH ELECTRONICS STM32MP1 DHCOM/DHCOR BOARD SUPPORT
++M: Marek Vasut <marex@denx.de>
++L: kernel@dh-electronics.com
++S: Maintained
++F: arch/arm/boot/dts/stm32mp1*-dhcom-*
++F: arch/arm/boot/dts/stm32mp1*-dhcor-*
++
++DIALOG SEMICONDUCTOR DRIVERS
++M: Support Opensource <support.opensource@diasemi.com>
++S: Supported
++W: http://www.dialog-semiconductor.com/products
++F: Documentation/devicetree/bindings/input/da90??-onkey.txt
++F: Documentation/devicetree/bindings/input/dlg,da72??.txt
++F: Documentation/devicetree/bindings/mfd/da90*.txt
++F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml
++F: Documentation/devicetree/bindings/regulator/da92*.txt
++F: Documentation/devicetree/bindings/regulator/slg51000.txt
++F: Documentation/devicetree/bindings/sound/da[79]*.txt
++F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt
++F: Documentation/devicetree/bindings/watchdog/da90??-wdt.txt
++F: Documentation/hwmon/da90??.rst
++F: drivers/gpio/gpio-da90??.c
++F: drivers/hwmon/da90??-hwmon.c
++F: drivers/iio/adc/da91??-*.c
++F: drivers/input/misc/da72??.[ch]
++F: drivers/input/misc/da90??_onkey.c
++F: drivers/input/touchscreen/da9052_tsi.c
++F: drivers/leds/leds-da90??.c
++F: drivers/mfd/da903x.c
++F: drivers/mfd/da90??-*.c
++F: drivers/mfd/da91??-*.c
++F: drivers/pinctrl/pinctrl-da90??.c
++F: drivers/power/supply/da9052-battery.c
++F: drivers/power/supply/da91??-*.c
++F: drivers/regulator/da9???-regulator.[ch]
++F: drivers/regulator/slg51000-regulator.[ch]
++F: drivers/rtc/rtc-da90??.c
++F: drivers/thermal/da90??-thermal.c
++F: drivers/video/backlight/da90??_bl.c
++F: drivers/watchdog/da90??_wdt.c
++F: include/dt-bindings/regulator/dlg,da9*-regulator.h
++F: include/linux/mfd/da903x.h
++F: include/linux/mfd/da9052/
++F: include/linux/mfd/da9055/
++F: include/linux/mfd/da9062/
++F: include/linux/mfd/da9063/
++F: include/linux/mfd/da9150/
++F: include/linux/regulator/da9211.h
++F: include/sound/da[79]*.h
++F: sound/soc/codecs/da[79]*.[ch]
++
++DIAMOND SYSTEMS GPIO-MM GPIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-gpio-mm.c
++
++DIOLAN U2C-12 I2C DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-diolan-u2c.c
++
++DIRECTORY NOTIFICATION (DNOTIFY)
++M: Jan Kara <jack@suse.cz>
++R: Amir Goldstein <amir73il@gmail.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: Documentation/filesystems/dnotify.rst
++F: fs/notify/dnotify/
++F: include/linux/dnotify.h
++
++DISK GEOMETRY AND PARTITION HANDLING
++M: Andries Brouwer <aeb@cwi.nl>
++S: Maintained
++W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html
++W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
++W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
++
++DISKQUOTA
++M: Jan Kara <jack@suse.com>
++S: Maintained
++F: Documentation/filesystems/quota.rst
++F: fs/quota/
++F: include/linux/quota*.h
++F: include/uapi/linux/quota*.h
++
++DISPLAYLINK USB 2.0 FRAMEBUFFER DRIVER (UDLFB)
++M: Bernie Thompson <bernie@plugable.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++W: http://plugable.com/category/projects/udlfb/
++F: Documentation/fb/udlfb.rst
++F: drivers/video/fbdev/udlfb.c
++F: include/video/udlfb.h
++
++DISTRIBUTED LOCK MANAGER (DLM)
++M: Christine Caulfield <ccaulfie@redhat.com>
++M: David Teigland <teigland@redhat.com>
++L: cluster-devel@redhat.com
++S: Supported
++W: http://sources.redhat.com/cluster/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git
++F: fs/dlm/
++
++DMA BUFFER SHARING FRAMEWORK
++M: Sumit Semwal <sumit.semwal@linaro.org>
++M: Christian König <christian.koenig@amd.com>
++L: linux-media@vger.kernel.org
++L: dri-devel@lists.freedesktop.org
++L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/driver-api/dma-buf.rst
++F: drivers/dma-buf/
++F: include/linux/*fence.h
++F: include/linux/dma-buf*
++F: include/linux/dma-resv.h
++K: \bdma_(?:buf|fence|resv)\b
++
++DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
++M: Vinod Koul <vkoul@kernel.org>
++L: dmaengine@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/linux-dmaengine/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
++F: Documentation/devicetree/bindings/dma/
++F: Documentation/driver-api/dmaengine/
++F: drivers/dma/
++F: include/linux/dma/
++F: include/linux/dmaengine.h
++F: include/linux/of_dma.h
++
++DMA MAPPING HELPERS
++M: Christoph Hellwig <hch@lst.de>
++M: Marek Szyprowski <m.szyprowski@samsung.com>
++R: Robin Murphy <robin.murphy@arm.com>
++L: iommu@lists.linux-foundation.org
++S: Supported
++W: http://git.infradead.org/users/hch/dma-mapping.git
++T: git git://git.infradead.org/users/hch/dma-mapping.git
++F: include/asm-generic/dma-mapping.h
++F: include/linux/dma-direct.h
++F: include/linux/dma-mapping.h
++F: include/linux/dma-map-ops.h
++F: kernel/dma/
++
++DMA MAPPING BENCHMARK
++M: Barry Song <song.bao.hua@hisilicon.com>
++L: iommu@lists.linux-foundation.org
++F: kernel/dma/map_benchmark.c
++F: tools/testing/selftests/dma/
++
++DMA-BUF HEAPS FRAMEWORK
++M: Sumit Semwal <sumit.semwal@linaro.org>
++R: Benjamin Gaignard <benjamin.gaignard@linaro.org>
++R: Liam Mark <lmark@codeaurora.org>
++R: Laura Abbott <labbott@redhat.com>
++R: Brian Starkey <Brian.Starkey@arm.com>
++R: John Stultz <john.stultz@linaro.org>
++L: linux-media@vger.kernel.org
++L: dri-devel@lists.freedesktop.org
++L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/dma-buf/dma-heap.c
++F: drivers/dma-buf/heaps/*
++F: include/linux/dma-heap.h
++F: include/uapi/linux/dma-heap.h
++
++DMC FREQUENCY DRIVER FOR SAMSUNG EXYNOS5422
++M: Lukasz Luba <lukasz.luba@arm.com>
++L: linux-pm@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.yaml
++F: drivers/memory/samsung/exynos5422-dmc.c
++
++DME1737 HARDWARE MONITOR DRIVER
++M: Juerg Haefliger <juergh@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/dme1737.rst
++F: drivers/hwmon/dme1737.c
++
++DMI/SMBIOS SUPPORT
++M: Jean Delvare <jdelvare@suse.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git dmi-for-next
++F: Documentation/ABI/testing/sysfs-firmware-dmi-tables
++F: drivers/firmware/dmi-id.c
++F: drivers/firmware/dmi_scan.c
++F: include/linux/dmi.h
++
++DOCUMENTATION
++M: Jonathan Corbet <corbet@lwn.net>
++L: linux-doc@vger.kernel.org
++S: Maintained
++P: Documentation/doc-guide/maintainer-profile.rst
++T: git git://git.lwn.net/linux.git docs-next
++F: Documentation/
++F: scripts/documentation-file-ref-check
++F: scripts/kernel-doc
++F: scripts/sphinx-pre-install
++X: Documentation/ABI/
++X: Documentation/admin-guide/media/
++X: Documentation/devicetree/
++X: Documentation/driver-api/media/
++X: Documentation/firmware-guide/acpi/
++X: Documentation/i2c/
++X: Documentation/power/
++X: Documentation/spi/
++X: Documentation/userspace-api/media/
++
++DOCUMENTATION REPORTING ISSUES
++M: Thorsten Leemhuis <linux@leemhuis.info>
++L: linux-doc@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/reporting-issues.rst
++
++DOCUMENTATION SCRIPTS
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-doc@vger.kernel.org
++S: Maintained
++F: Documentation/sphinx/parse-headers.pl
++F: scripts/documentation-file-ref-check
++F: scripts/sphinx-pre-install
++
++DOCUMENTATION/ITALIAN
++M: Federico Vaga <federico.vaga@vaga.pv.it>
++L: linux-doc@vger.kernel.org
++S: Maintained
++F: Documentation/translations/it_IT
++
++DONGWOON DW9714 LENS VOICE COIL DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt
++F: drivers/media/i2c/dw9714.c
++
++DONGWOON DW9768 LENS VOICE COIL DRIVER
++M: Dongchun Zhu <dongchun.zhu@mediatek.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml
++F: drivers/media/i2c/dw9768.c
++
++DONGWOON DW9807 LENS VOICE COIL DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.txt
++F: drivers/media/i2c/dw9807-vcm.c
++
++DOUBLETALK DRIVER
++M: "James R. Van Zandt" <jrv@vanzandt.mv.com>
++L: blinux-list@redhat.com
++S: Maintained
++F: drivers/char/dtlk.c
++F: include/linux/dtlk.h
++
++DPAA2 DATAPATH I/O (DPIO) DRIVER
++M: Roy Pledge <Roy.Pledge@nxp.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/soc/fsl/dpio
++
++DPAA2 ETHERNET DRIVER
++M: Ioana Ciornei <ioana.ciornei@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/ethernet-driver.rst
++F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst
++F: drivers/net/ethernet/freescale/dpaa2/Kconfig
++F: drivers/net/ethernet/freescale/dpaa2/Makefile
++F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth*
++F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac*
++F: drivers/net/ethernet/freescale/dpaa2/dpkg.h
++F: drivers/net/ethernet/freescale/dpaa2/dpmac*
++F: drivers/net/ethernet/freescale/dpaa2/dpni*
++
++DPAA2 ETHERNET SWITCH DRIVER
++M: Ioana Ciornei <ioana.ciornei@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/switch-driver.rst
++F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch*
++F: drivers/net/ethernet/freescale/dpaa2/dpsw*
++
++DPT_I2O SCSI RAID DRIVER
++M: Adaptec OEM Raid Solutions <aacraid@microsemi.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++W: http://www.adaptec.com/
++F: drivers/scsi/dpt*
++F: drivers/scsi/dpt/
++
++DRBD DRIVER
++M: Philipp Reisner <philipp.reisner@linbit.com>
++M: Lars Ellenberg <lars.ellenberg@linbit.com>
++L: drbd-dev@lists.linbit.com
++S: Supported
++W: http://www.drbd.org
++T: git git://git.linbit.com/linux-drbd.git
++T: git git://git.linbit.com/drbd-8.4.git
++F: Documentation/admin-guide/blockdev/
++F: drivers/block/drbd/
++F: lib/lru_cache.c
++
++DRIVER COMPONENT FRAMEWORK
++L: dri-devel@lists.freedesktop.org
++F: drivers/base/component.c
++F: include/linux/component.h
++
++DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++R: "Rafael J. Wysocki" <rafael@kernel.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
++F: Documentation/core-api/kobject.rst
++F: drivers/base/
++F: fs/debugfs/
++F: fs/sysfs/
++F: include/linux/debugfs.h
++F: include/linux/kobj*
++F: lib/kobj*
++
++DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS)
++M: Nishanth Menon <nm@ti.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: drivers/soc/ti/smartreflex.c
++F: include/linux/power/smartreflex.h
++
++DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE
++M: Maxime Ripard <mripard@kernel.org>
++M: Chen-Yu Tsai <wens@csie.org>
++R: Jernej Skrabec <jernej.skrabec@gmail.com>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/sun4i/sun8i*
++
++DRM DRIVER FOR ARM PL111 CLCD
++M: Emma Anholt <emma@anholt.net>
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/pl111/
++
++DRM DRIVER FOR ARM VERSATILE TFT PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.yaml
++F: drivers/gpu/drm/panel/panel-arm-versatile.c
++
++DRM DRIVER FOR ASPEED BMC GFX
++M: Joel Stanley <joel@jms.id.au>
++L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/gpu/aspeed-gfx.txt
++F: drivers/gpu/drm/aspeed/
++
++DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
++M: Dave Airlie <airlied@redhat.com>
++R: Thomas Zimmermann <tzimmermann@suse.de>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/ast/
++
++DRM DRIVER FOR BOCHS VIRTUAL GPU
++M: Gerd Hoffmann <kraxel@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/tiny/bochs.c
++
++DRM DRIVER FOR BOE HIMAX8279D PANELS
++M: Jerry Han <hanxu5@huaqin.corp-partner.google.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml
++F: drivers/gpu/drm/panel/panel-boe-himax8279d.c
++
++DRM DRIVER FOR CHIPONE ICN6211 MIPI-DSI to RGB CONVERTER BRIDGE
++M: Jagan Teki <jagan@amarulasolutions.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/bridge/chipone,icn6211.yaml
++F: drivers/gpu/drm/bridge/chipone-icn6211.c
++
++DRM DRIVER FOR FARADAY TVE200 TV ENCODER
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/tve200/
++
++DRM DRIVER FOR FEIXIN K101 IM2BA02 MIPI-DSI LCD PANELS
++M: Icenowy Zheng <icenowy@aosc.io>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml
++F: drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
++
++DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
++M: Jagan Teki <jagan@amarulasolutions.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
++F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
++
++DRM DRIVER FOR GENERIC USB DISPLAY
++M: Noralf Trønnes <noralf@tronnes.org>
++S: Maintained
++W: https://github.com/notro/gud/wiki
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/gud/
++F: include/drm/gud.h
++
++DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
++M: Hans de Goede <hdegoede@redhat.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/tiny/gm12u320.c
++
++DRM DRIVER FOR HX8357D PANELS
++M: Emma Anholt <emma@anholt.net>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/himax,hx8357d.txt
++F: drivers/gpu/drm/tiny/hx8357d.c
++
++DRM DRIVER FOR ILITEK ILI9225 PANELS
++M: David Lechner <david@lechnology.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt
++F: drivers/gpu/drm/tiny/ili9225.c
++
++DRM DRIVER FOR ILITEK ILI9486 PANELS
++M: Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/ilitek,ili9486.yaml
++F: drivers/gpu/drm/tiny/ili9486.c
++
++DRM DRIVER FOR INTEL I810 VIDEO CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/i810/
++F: include/uapi/drm/i810_drm.h
++
++DRM DRIVER FOR LVDS PANELS
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: dri-devel@lists.freedesktop.org
++T: git git://anongit.freedesktop.org/drm/drm-misc
++S: Maintained
++F: drivers/gpu/drm/panel/panel-lvds.c
++F: Documentation/devicetree/bindings/display/panel/lvds.yaml
++
++DRM DRIVER FOR MANTIX MLAF057WE51 PANELS
++M: Guido Günther <agx@sigxcpu.org>
++R: Purism Kernel Team <kernel@puri.sm>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml
++F: drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
++
++DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/mga/
++F: include/uapi/drm/mga_drm.h
++
++DRM DRIVER FOR MGA G200 GRAPHICS CHIPS
++M: Dave Airlie <airlied@redhat.com>
++R: Thomas Zimmermann <tzimmermann@suse.de>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/mgag200/
++
++DRM DRIVER FOR MI0283QT
++M: Noralf Trønnes <noralf@tronnes.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
++F: drivers/gpu/drm/tiny/mi0283qt.c
++
++DRM DRIVER FOR MSM ADRENO GPU
++M: Rob Clark <robdclark@gmail.com>
++M: Sean Paul <sean@poorly.run>
++L: linux-arm-msm@vger.kernel.org
++L: dri-devel@lists.freedesktop.org
++L: freedreno@lists.freedesktop.org
++S: Maintained
++T: git https://gitlab.freedesktop.org/drm/msm.git
++F: Documentation/devicetree/bindings/display/msm/
++F: drivers/gpu/drm/msm/
++F: include/uapi/drm/msm_drm.h
++
++DRM DRIVER FOR NOVATEK NT35510 PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
++F: drivers/gpu/drm/panel/panel-novatek-nt35510.c
++
++DRM DRIVER FOR NOVATEK NT36672A PANELS
++M: Sumit Semwal <sumit.semwal@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/novatek,nt36672a.yaml
++F: drivers/gpu/drm/panel/panel-novatek-nt36672a.c
++
++DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
++M: Ben Skeggs <bskeggs@redhat.com>
++L: dri-devel@lists.freedesktop.org
++L: nouveau@lists.freedesktop.org
++S: Supported
++T: git git://github.com/skeggsb/linux
++F: drivers/gpu/drm/nouveau/
++F: include/uapi/drm/nouveau_drm.h
++
++DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
++M: Stefan Mavrodiev <stefan@olimex.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.yaml
++F: drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
++
++DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
++M: Noralf Trønnes <noralf@tronnes.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/repaper.txt
++F: drivers/gpu/drm/tiny/repaper.c
++
++DRM DRIVER FOR QEMU'S CIRRUS DEVICE
++M: Dave Airlie <airlied@redhat.com>
++M: Gerd Hoffmann <kraxel@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Obsolete
++W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/tiny/cirrus.c
++
++DRM DRIVER FOR QXL VIRTUAL GPU
++M: Dave Airlie <airlied@redhat.com>
++M: Gerd Hoffmann <kraxel@redhat.com>
++L: virtualization@lists.linux-foundation.org
++L: spice-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/qxl/
++F: include/uapi/drm/qxl_drm.h
++
++DRM DRIVER FOR RAGE 128 VIDEO CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/r128/
++F: include/uapi/drm/r128_drm.h
++
++DRM DRIVER FOR RAYDIUM RM67191 PANELS
++M: Robert Chiras <robert.chiras@nxp.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml
++F: drivers/gpu/drm/panel/panel-raydium-rm67191.c
++
++DRM DRIVER FOR SAMSUNG DB7430 PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/samsung,lms397kf04.yaml
++F: drivers/gpu/drm/panel/panel-samsung-db7430.c
++
++DRM DRIVER FOR SITRONIX ST7703 PANELS
++M: Guido Günther <agx@sigxcpu.org>
++R: Purism Kernel Team <kernel@puri.sm>
++R: Ondrej Jirman <megous@megous.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml
++F: drivers/gpu/drm/panel/panel-sitronix-st7703.c
++
++DRM DRIVER FOR SAVAGE VIDEO CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/savage/
++F: include/uapi/drm/savage_drm.h
++
++DRM DRIVER FOR SIMPLE FRAMEBUFFERS
++M: Thomas Zimmermann <tzimmermann@suse.de>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/tiny/simpledrm.c
++
++DRM DRIVER FOR SIS VIDEO CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/sis/
++F: include/uapi/drm/sis_drm.h
++
++DRM DRIVER FOR SITRONIX ST7586 PANELS
++M: David Lechner <david@lechnology.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/sitronix,st7586.txt
++F: drivers/gpu/drm/tiny/st7586.c
++
++DRM DRIVER FOR SITRONIX ST7701 PANELS
++M: Jagan Teki <jagan@amarulasolutions.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml
++F: drivers/gpu/drm/panel/panel-sitronix-st7701.c
++
++DRM DRIVER FOR SITRONIX ST7735R PANELS
++M: David Lechner <david@lechnology.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
++F: drivers/gpu/drm/tiny/st7735r.c
++
++DRM DRIVER FOR SONY ACX424AKP PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/panel/panel-sony-acx424akp.c
++
++DRM DRIVER FOR ST-ERICSSON MCDE
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/ste,mcde.yaml
++F: drivers/gpu/drm/mcde/
++
++DRM DRIVER FOR TDFX VIDEO CARDS
++S: Orphan / Obsolete
++F: drivers/gpu/drm/tdfx/
++
++DRM DRIVER FOR TPO TPG110 PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
++F: drivers/gpu/drm/panel/panel-tpo-tpg110.c
++
++DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
++M: Dave Airlie <airlied@redhat.com>
++R: Sean Paul <sean@poorly.run>
++R: Thomas Zimmermann <tzimmermann@suse.de>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/udl/
++
++DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
++M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
++M: Melissa Wen <melissa.srw@gmail.com>
++R: Haneen Mohammed <hamohammed.sa@gmail.com>
++R: Daniel Vetter <daniel@ffwll.ch>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/gpu/vkms.rst
++F: drivers/gpu/drm/vkms/
++
++DRM DRIVER FOR VIRTUALBOX VIRTUAL GPU
++M: Hans de Goede <hdegoede@redhat.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/vboxvideo/
++
++DRM DRIVER FOR VMWARE VIRTUAL GPU
++M: "VMware Graphics" <linux-graphics-maintainer@vmware.com>
++M: Zack Rusin <zackr@vmware.com>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/vmwgfx/
++F: include/uapi/drm/vmwgfx_drm.h
++
++DRM DRIVER FOR WIDECHIPS WS2401 PANELS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/samsung,lms380kf01.yaml
++F: drivers/gpu/drm/panel/panel-widechips-ws2401.c
++
++DRM DRIVERS
++M: David Airlie <airlied@linux.ie>
++M: Daniel Vetter <daniel@ffwll.ch>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++B: https://gitlab.freedesktop.org/drm
++C: irc://irc.oftc.net/dri-devel
++T: git git://anongit.freedesktop.org/drm/drm
++F: Documentation/devicetree/bindings/display/
++F: Documentation/devicetree/bindings/gpu/
++F: Documentation/gpu/
++F: drivers/gpu/
++F: include/drm/
++F: include/linux/vga*
++F: include/uapi/drm/
++
++DRM DRIVERS AND MISC GPU PATCHES
++M: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
++M: Maxime Ripard <mripard@kernel.org>
++M: Thomas Zimmermann <tzimmermann@suse.de>
++S: Maintained
++W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/gpu/
++F: drivers/gpu/drm/*
++F: drivers/gpu/vga/
++F: include/drm/drm*
++F: include/linux/vga*
++F: include/uapi/drm/drm*
++
++DRM DRIVERS FOR ALLWINNER A10
++M: Maxime Ripard <mripard@kernel.org>
++M: Chen-Yu Tsai <wens@csie.org>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/allwinner*
++F: drivers/gpu/drm/sun4i/
++
++DRM DRIVERS FOR AMLOGIC SOCS
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: dri-devel@lists.freedesktop.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++W: http://linux-meson.com/
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
++F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
++F: Documentation/gpu/meson.rst
++F: drivers/gpu/drm/meson/
++
++DRM DRIVERS FOR ATMEL HLCDC
++M: Sam Ravnborg <sam@ravnborg.org>
++M: Boris Brezillon <bbrezillon@kernel.org>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/atmel/
++F: drivers/gpu/drm/atmel-hlcdc/
++
++DRM DRIVERS FOR BRIDGE CHIPS
++M: Andrzej Hajda <a.hajda@samsung.com>
++M: Neil Armstrong <narmstrong@baylibre.com>
++M: Robert Foss <robert.foss@linaro.org>
++R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
++R: Jonas Karlman <jonas@kwiboo.se>
++R: Jernej Skrabec <jernej.skrabec@gmail.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/bridge/
++
++DRM DRIVERS FOR EXYNOS
++M: Inki Dae <inki.dae@samsung.com>
++M: Joonyoung Shim <jy0922.shim@samsung.com>
++M: Seung-Woo Kim <sw0312.kim@samsung.com>
++M: Kyungmin Park <kyungmin.park@samsung.com>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
++F: Documentation/devicetree/bindings/display/exynos/
++F: drivers/gpu/drm/exynos/
++F: include/uapi/drm/exynos_drm.h
++
++DRM DRIVERS FOR FREESCALE DCU
++M: Stefan Agner <stefan@agner.ch>
++M: Alison Wang <alison.wang@nxp.com>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/fsl,dcu.txt
++F: Documentation/devicetree/bindings/display/fsl,tcon.txt
++F: drivers/gpu/drm/fsl-dcu/
++
++DRM DRIVERS FOR FREESCALE IMX
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: Documentation/devicetree/bindings/display/imx/
++F: drivers/gpu/drm/imx/
++F: drivers/gpu/ipu-v3/
++
++DRM DRIVERS FOR GMA500 (Poulsbo, Moorestown and derivative chipsets)
++M: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://github.com/patjak/drm-gma500
++F: drivers/gpu/drm/gma500/
++
++DRM DRIVERS FOR HISILICON
++M: Xinliang Liu <xinliang.liu@linaro.org>
++M: Tian Tao <tiantao6@hisilicon.com>
++R: John Stultz <john.stultz@linaro.org>
++R: Xinwei Kong <kong.kongxinwei@hisilicon.com>
++R: Chen Feng <puck.chen@hisilicon.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/hisilicon/
++F: drivers/gpu/drm/hisilicon/
++
++DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
++M: Deepak Rawat <drawat.floss@gmail.com>
++L: linux-hyperv@vger.kernel.org
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/hyperv
++
++DRM DRIVERS FOR LIMA
++M: Qiang Yu <yuq825@gmail.com>
++L: dri-devel@lists.freedesktop.org
++L: lima@lists.freedesktop.org (moderated for non-subscribers)
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/lima/
++F: include/uapi/drm/lima_drm.h
++
++DRM DRIVERS FOR MEDIATEK
++M: Chun-Kuang Hu <chunkuang.hu@kernel.org>
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: dri-devel@lists.freedesktop.org
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/display/mediatek/
++F: drivers/gpu/drm/mediatek/
++F: drivers/phy/mediatek/phy-mtk-hdmi*
++F: drivers/phy/mediatek/phy-mtk-mipi*
++
++DRM DRIVERS FOR NVIDIA TEGRA
++M: Thierry Reding <thierry.reding@gmail.com>
++L: dri-devel@lists.freedesktop.org
++L: linux-tegra@vger.kernel.org
++S: Supported
++T: git git://anongit.freedesktop.org/tegra/linux.git
++F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
++F: drivers/gpu/drm/tegra/
++F: drivers/gpu/host1x/
++F: include/linux/host1x.h
++F: include/uapi/drm/tegra_drm.h
++
++DRM DRIVERS FOR RENESAS
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++L: dri-devel@lists.freedesktop.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/pinchartl/media drm/du/next
++F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml
++F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml
++F: Documentation/devicetree/bindings/display/renesas,du.yaml
++F: drivers/gpu/drm/rcar-du/
++F: drivers/gpu/drm/shmobile/
++F: include/linux/platform_data/shmob_drm.h
++
++DRM DRIVERS FOR ROCKCHIP
++M: Sandy Huang <hjc@rock-chips.com>
++M: Heiko Stübner <heiko@sntech.de>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/rockchip/
++F: drivers/gpu/drm/rockchip/
++
++DRM DRIVERS FOR STI
++M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/st,stih4xx.txt
++F: drivers/gpu/drm/sti
++
++DRM DRIVERS FOR STM
++M: Yannick Fertre <yannick.fertre@foss.st.com>
++M: Philippe Cornu <philippe.cornu@foss.st.com>
++M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml
++F: drivers/gpu/drm/stm
++
++DRM DRIVERS FOR TI KEYSTONE
++M: Jyri Sarha <jyri.sarha@iki.fi>
++M: Tomi Valkeinen <tomba@kernel.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
++F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
++F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
++F: drivers/gpu/drm/tidss/
++
++DRM DRIVERS FOR TI LCDC
++M: Jyri Sarha <jyri.sarha@iki.fi>
++R: Tomi Valkeinen <tomba@kernel.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: Documentation/devicetree/bindings/display/tilcdc/
++F: drivers/gpu/drm/tilcdc/
++
++DRM DRIVERS FOR TI OMAP
++M: Tomi Valkeinen <tomba@kernel.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: Documentation/devicetree/bindings/display/ti/
++F: drivers/gpu/drm/omapdrm/
++
++DRM DRIVERS FOR V3D
++M: Emma Anholt <emma@anholt.net>
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
++F: drivers/gpu/drm/v3d/
++F: include/uapi/drm/v3d_drm.h
++
++DRM DRIVERS FOR VC4
++M: Emma Anholt <emma@anholt.net>
++M: Maxime Ripard <mripard@kernel.org>
++S: Supported
++T: git git://github.com/anholt/linux
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
++F: drivers/gpu/drm/vc4/
++F: include/uapi/drm/vc4_drm.h
++
++DRM DRIVERS FOR VIVANTE GPU IP
++M: Lucas Stach <l.stach@pengutronix.de>
++R: Russell King <linux+etnaviv@armlinux.org.uk>
++R: Christian Gmeiner <christian.gmeiner@gmail.com>
++L: etnaviv@lists.freedesktop.org (moderated for non-subscribers)
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: Documentation/devicetree/bindings/gpu/vivante,gc.yaml
++F: drivers/gpu/drm/etnaviv/
++F: include/uapi/drm/etnaviv_drm.h
++
++DRM DRIVERS FOR XEN
++M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
++L: dri-devel@lists.freedesktop.org
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/gpu/xen-front.rst
++F: drivers/gpu/drm/xen/
++
++DRM DRIVERS FOR XILINX
++M: Hyun Kwon <hyun.kwon@xilinx.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/xlnx/
++F: drivers/gpu/drm/xlnx/
++
++DRM PANEL DRIVERS
++M: Thierry Reding <thierry.reding@gmail.com>
++R: Sam Ravnborg <sam@ravnborg.org>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/panel/
++F: drivers/gpu/drm/drm_panel.c
++F: drivers/gpu/drm/panel/
++F: include/drm/drm_panel.h
++
++DRM TTM SUBSYSTEM
++M: Christian Koenig <christian.koenig@amd.com>
++M: Huang Rui <ray.huang@amd.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/ttm/
++F: include/drm/ttm/
++
++DSBR100 USB FM RADIO DRIVER
++M: Alexey Klimov <klimov.linux@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/dsbr100.c
++
++DT3155 MEDIA DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/dt3155/
++
++DVB_USB_AF9015 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/af9015*
++
++DVB_USB_AF9035 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/af9035*
++
++DVB_USB_ANYSEE MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/anysee*
++
++DVB_USB_AU6610 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/au6610*
++
++DVB_USB_CE6230 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/ce6230*
++
++DVB_USB_CXUSB MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/dvb-usb/cxusb*
++
++DVB_USB_EC168 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/ec168*
++
++DVB_USB_GL861 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/gl861*
++
++DVB_USB_MXL111SF MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/mxl111sf.git
++F: drivers/media/usb/dvb-usb-v2/mxl111sf*
++
++DVB_USB_RTL28XXU MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/rtl28xxu*
++
++DVB_USB_V2 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/dvb-usb-v2/dvb_usb*
++F: drivers/media/usb/dvb-usb-v2/usb_urb.c
++
++DYNAMIC DEBUG
++M: Jason Baron <jbaron@akamai.com>
++S: Maintained
++F: include/linux/dynamic_debug.h
++F: lib/dynamic_debug.c
++
++DYNAMIC INTERRUPT MODERATION
++M: Tal Gilboa <talgi@nvidia.com>
++S: Maintained
++F: Documentation/networking/net_dim.rst
++F: include/linux/dim.h
++F: lib/dim/
++
++DZ DECSTATION DZ11 SERIAL DRIVER
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++S: Maintained
++F: drivers/tty/serial/dz.*
++
++E3X0 POWER BUTTON DRIVER
++M: Moritz Fischer <moritz.fischer@ettus.com>
++L: usrp-users@lists.ettus.com
++S: Supported
++W: http://www.ettus.com
++F: Documentation/devicetree/bindings/input/e3x0-button.txt
++F: drivers/input/misc/e3x0-button.c
++
++E4000 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/e4000*
++
++EARTH_PT1 MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/pci/pt1/
++
++EARTH_PT3 MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/pci/pt3/
++
++EC100 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/ec100*
++
++ECRYPT FILE SYSTEM
++M: Tyler Hicks <code@tyhicks.com>
++L: ecryptfs@vger.kernel.org
++S: Odd Fixes
++W: http://ecryptfs.org
++W: https://launchpad.net/ecryptfs
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git
++F: Documentation/filesystems/ecryptfs.rst
++F: fs/ecryptfs/
++
++EDAC-AMD64
++M: Yazen Ghannam <yazen.ghannam@amd.com>
++L: linux-edac@vger.kernel.org
++S: Supported
++F: drivers/edac/amd64_edac*
++F: drivers/edac/mce_amd*
++
++EDAC-ARMADA
++M: Jan Luebbe <jlu@pengutronix.de>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/memory-controllers/marvell,mvebu-sdram-controller.yaml
++F: drivers/edac/armada_xp_*
++
++EDAC-AST2500
++M: Stefan Schaeckeler <sschaeck@cisco.com>
++S: Supported
++F: Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
++F: drivers/edac/aspeed_edac.c
++
++EDAC-BLUEFIELD
++M: Shravan Kumar Ramani <shravankr@nvidia.com>
++S: Supported
++F: drivers/edac/bluefield_edac.c
++
++EDAC-CALXEDA
++M: Andre Przywara <andre.przywara@arm.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/highbank*
++
++EDAC-CAVIUM OCTEON
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-edac@vger.kernel.org
++L: linux-mips@vger.kernel.org
++S: Supported
++F: drivers/edac/octeon_edac*
++
++EDAC-CAVIUM THUNDERX
++M: Robert Richter <rric@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Odd Fixes
++F: drivers/edac/thunderx_edac*
++
++EDAC-CORE
++M: Borislav Petkov <bp@alien8.de>
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++M: Tony Luck <tony.luck@intel.com>
++R: James Morse <james.morse@arm.com>
++R: Robert Richter <rric@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
++F: Documentation/admin-guide/ras.rst
++F: Documentation/driver-api/edac.rst
++F: drivers/edac/
++F: include/linux/edac.h
++
++EDAC-DMC520
++M: Lei Wang <lewan@microsoft.com>
++L: linux-edac@vger.kernel.org
++S: Supported
++F: drivers/edac/dmc520_edac.c
++
++EDAC-E752X
++M: Mark Gross <mark.gross@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/e752x_edac.c
++
++EDAC-E7XXX
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/e7xxx_edac.c
++
++EDAC-FSL_DDR
++M: York Sun <york.sun@nxp.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/fsl_ddr_edac.*
++
++EDAC-GHES
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/ghes_edac.c
++
++EDAC-I10NM
++M: Tony Luck <tony.luck@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i10nm_base.c
++
++EDAC-I3000
++L: linux-edac@vger.kernel.org
++S: Orphan
++F: drivers/edac/i3000_edac.c
++
++EDAC-I5000
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i5000_edac.c
++
++EDAC-I5400
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i5400_edac.c
++
++EDAC-I7300
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i7300_edac.c
++
++EDAC-I7CORE
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i7core_edac.c
++
++EDAC-I82443BXGX
++M: Tim Small <tim@buttersideup.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i82443bxgx_edac.c
++
++EDAC-I82975X
++M: "Arvind R." <arvino55@gmail.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/i82975x_edac.c
++
++EDAC-IE31200
++M: Jason Baron <jbaron@akamai.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/ie31200_edac.c
++
++EDAC-IGEN6
++M: Tony Luck <tony.luck@intel.com>
++R: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/igen6_edac.c
++
++EDAC-MPC85XX
++M: Johannes Thumshirn <morbidrsa@gmail.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/mpc85xx_edac.[ch]
++
++EDAC-PASEMI
++M: Egor Martovetsky <egor@pasemi.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/pasemi_edac.c
++
++EDAC-PND2
++M: Tony Luck <tony.luck@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/pnd2_edac.[ch]
++
++EDAC-QCOM
++M: Channagoud Kadabi <ckadabi@codeaurora.org>
++M: Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
++L: linux-arm-msm@vger.kernel.org
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/qcom_edac.c
++
++EDAC-R82600
++M: Tim Small <tim@buttersideup.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/r82600_edac.c
++
++EDAC-SBRIDGE
++M: Tony Luck <tony.luck@intel.com>
++R: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/sb_edac.c
++
++EDAC-SIFIVE
++M: Yash Shah <yash.shah@sifive.com>
++L: linux-edac@vger.kernel.org
++S: Supported
++F: drivers/edac/sifive_edac.c
++
++EDAC-SKYLAKE
++M: Tony Luck <tony.luck@intel.com>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: drivers/edac/skx_*.[ch]
++
++EDAC-TI
++M: Tero Kristo <kristo@kernel.org>
++L: linux-edac@vger.kernel.org
++S: Odd Fixes
++F: drivers/edac/ti_edac.c
++
++EDIROL UA-101/UA-1000 DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: sound/usb/misc/ua101.c
++
++EFI TEST DRIVER
++M: Ivan Hu <ivan.hu@canonical.com>
++M: Ard Biesheuvel <ardb@kernel.org>
++L: linux-efi@vger.kernel.org
++S: Maintained
++F: drivers/firmware/efi/test/
++
++EFI VARIABLE FILESYSTEM
++M: Matthew Garrett <matthew.garrett@nebula.com>
++M: Jeremy Kerr <jk@ozlabs.org>
++M: Ard Biesheuvel <ardb@kernel.org>
++L: linux-efi@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
++F: fs/efivarfs/
++
++EFIFB FRAMEBUFFER DRIVER
++M: Peter Jones <pjones@redhat.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/efifb.c
++
++EFS FILESYSTEM
++S: Orphan
++W: http://aeschi.ch.eu.org/efs/
++F: fs/efs/
++
++EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
++M: Douglas Miller <dougmill@linux.ibm.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/ibm/ehea/
++
++EM28XX VIDEO4LINUX DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/em28xx*
++F: drivers/media/usb/em28xx/
++
++EMBEDDED LINUX
++M: Matt Mackall <mpm@selenic.com>
++M: David Woodhouse <dwmw2@infradead.org>
++L: linux-embedded@vger.kernel.org
++S: Maintained
++
++EMMC CMDQ HOST CONTROLLER INTERFACE (CQHCI) DRIVER
++M: Adrian Hunter <adrian.hunter@intel.com>
++M: Ritesh Harjani <riteshh@codeaurora.org>
++M: Asutosh Das <asutoshd@codeaurora.org>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/cqhci*
++
++EMULEX 10Gbps iSCSI - OneConnect DRIVER
++M: Subbu Seetharaman <subbu.seetharaman@broadcom.com>
++M: Ketan Mukadam <ketan.mukadam@broadcom.com>
++M: Jitendra Bhivare <jitendra.bhivare@broadcom.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.broadcom.com
++F: drivers/scsi/be2iscsi/
++
++EMULEX 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
++M: Ajit Khaparde <ajit.khaparde@broadcom.com>
++M: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
++M: Somnath Kotur <somnath.kotur@broadcom.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.emulex.com
++F: drivers/net/ethernet/emulex/benet/
++
++EMULEX ONECONNECT ROCE DRIVER
++M: Selvin Xavier <selvin.xavier@broadcom.com>
++L: linux-rdma@vger.kernel.org
++S: Odd Fixes
++W: http://www.broadcom.com
++F: drivers/infiniband/hw/ocrdma/
++F: include/uapi/rdma/ocrdma-abi.h
++
++EMULEX/BROADCOM LPFC FC/FCOE SCSI DRIVER
++M: James Smart <james.smart@broadcom.com>
++M: Dick Kennedy <dick.kennedy@broadcom.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.broadcom.com
++F: drivers/scsi/lpfc/
++
++EMULEX/BROADCOM EFCT FC/FCOE SCSI TARGET DRIVER
++M: James Smart <james.smart@broadcom.com>
++M: Ram Vegesna <ram.vegesna@broadcom.com>
++L: linux-scsi@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++W: http://www.broadcom.com
++F: drivers/scsi/elx/
++
++ENE CB710 FLASH CARD READER DRIVER
++M: Michał Mirosław <mirq-linux@rere.qmqm.pl>
++S: Maintained
++F: drivers/misc/cb710/
++F: drivers/mmc/host/cb710-mmc.*
++F: include/linux/cb710.h
++
++ENE KB2426 (ENE0100/ENE020XX) INFRARED RECEIVER
++M: Maxim Levitsky <maximlevitsky@gmail.com>
++S: Maintained
++F: drivers/media/rc/ene_ir.*
++
++EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER
++M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/tty/ehv_bytechan.c
++
++EPSON S1D13XXX FRAMEBUFFER DRIVER
++M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
++F: drivers/video/fbdev/s1d13xxxfb.c
++F: include/video/s1d13xxxfb.h
++
++EROFS FILE SYSTEM
++M: Gao Xiang <xiang@kernel.org>
++M: Chao Yu <chao@kernel.org>
++L: linux-erofs@lists.ozlabs.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
++F: Documentation/filesystems/erofs.rst
++F: fs/erofs/
++F: include/trace/events/erofs.h
++
++ERRSEQ ERROR TRACKING INFRASTRUCTURE
++M: Jeff Layton <jlayton@kernel.org>
++S: Maintained
++F: include/linux/errseq.h
++F: lib/errseq.c
++
++ET131X NETWORK DRIVER
++M: Mark Einon <mark.einon@gmail.com>
++S: Odd Fixes
++F: drivers/net/ethernet/agere/
++
++ETAS ES58X CAN/USB DRIVER
++M: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
++L: linux-can@vger.kernel.org
++S: Maintained
++F: drivers/net/can/usb/etas_es58x/
++
++ETHERNET BRIDGE
++M: Roopa Prabhu <roopa@nvidia.com>
++M: Nikolay Aleksandrov <nikolay@nvidia.com>
++L: bridge@lists.linux-foundation.org (moderated for non-subscribers)
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.linuxfoundation.org/en/Net:Bridge
++F: include/linux/netfilter_bridge/
++F: net/bridge/
++
++ETHERNET PHY LIBRARY
++M: Andrew Lunn <andrew@lunn.ch>
++M: Heiner Kallweit <hkallweit1@gmail.com>
++R: Russell King <linux@armlinux.org.uk>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-net-phydev
++F: Documentation/devicetree/bindings/net/ethernet-phy.yaml
++F: Documentation/devicetree/bindings/net/mdio*
++F: Documentation/devicetree/bindings/net/qca,ar803x.yaml
++F: Documentation/networking/phy.rst
++F: drivers/net/mdio/
++F: drivers/net/mdio/acpi_mdio.c
++F: drivers/net/mdio/fwnode_mdio.c
++F: drivers/net/mdio/of_mdio.c
++F: drivers/net/pcs/
++F: drivers/net/phy/
++F: drivers/of/of_net.c
++F: include/dt-bindings/net/qca-ar803x.h
++F: include/linux/*mdio*.h
++F: include/linux/mdio/*.h
++F: include/linux/of_net.h
++F: include/linux/phy.h
++F: include/linux/phy_fixed.h
++F: include/linux/platform_data/mdio-bcm-unimac.h
++F: include/linux/platform_data/mdio-gpio.h
++F: include/trace/events/mdio.h
++F: include/uapi/linux/mdio.h
++F: include/uapi/linux/mii.h
++
++EXFAT FILE SYSTEM
++M: Namjae Jeon <linkinjeon@kernel.org>
++M: Sungjong Seo <sj1557.seo@samsung.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/exfat/
++
++EXT2 FILE SYSTEM
++M: Jan Kara <jack@suse.com>
++L: linux-ext4@vger.kernel.org
++S: Maintained
++F: Documentation/filesystems/ext2.rst
++F: fs/ext2/
++F: include/linux/ext2*
++
++EXT4 FILE SYSTEM
++M: "Theodore Ts'o" <tytso@mit.edu>
++M: Andreas Dilger <adilger.kernel@dilger.ca>
++L: linux-ext4@vger.kernel.org
++S: Maintained
++W: http://ext4.wiki.kernel.org
++Q: http://patchwork.ozlabs.org/project/linux-ext4/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
++F: Documentation/filesystems/ext4/
++F: fs/ext4/
++F: include/trace/events/ext4.h
++
++Extended Verification Module (EVM)
++M: Mimi Zohar <zohar@linux.ibm.com>
++L: linux-integrity@vger.kernel.org
++S: Supported
++F: security/integrity/evm/
++
++EXTENSIBLE FIRMWARE INTERFACE (EFI)
++M: Ard Biesheuvel <ardb@kernel.org>
++L: linux-efi@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
++F: Documentation/admin-guide/efi-stub.rst
++F: arch/*/include/asm/efi.h
++F: arch/*/kernel/efi.c
++F: arch/arm/boot/compressed/efi-header.S
++F: arch/arm64/kernel/efi-entry.S
++F: arch/x86/platform/efi/
++F: drivers/firmware/efi/
++F: include/linux/efi*.h
++
++EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
++M: MyungJoo Ham <myungjoo.ham@samsung.com>
++M: Chanwoo Choi <cw00.choi@samsung.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
++F: Documentation/devicetree/bindings/extcon/
++F: Documentation/firmware-guide/acpi/extcon-intel-int3496.rst
++F: drivers/extcon/
++F: include/linux/extcon.h
++F: include/linux/extcon/
++
++EXTRA BOOT CONFIG
++M: Masami Hiramatsu <mhiramat@kernel.org>
++S: Maintained
++F: Documentation/admin-guide/bootconfig.rst
++F: fs/proc/bootconfig.c
++F: include/linux/bootconfig.h
++F: lib/bootconfig.c
++F: tools/bootconfig/*
++F: tools/bootconfig/scripts/*
++
++EXYNOS DP DRIVER
++M: Jingoo Han <jingoohan1@gmail.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: drivers/gpu/drm/exynos/exynos_dp*
++
++EXYNOS SYSMMU (IOMMU) driver
++M: Marek Szyprowski <m.szyprowski@samsung.com>
++L: iommu@lists.linux-foundation.org
++S: Maintained
++F: drivers/iommu/exynos-iommu.c
++
++F2FS FILE SYSTEM
++M: Jaegeuk Kim <jaegeuk@kernel.org>
++M: Chao Yu <chao@kernel.org>
++L: linux-f2fs-devel@lists.sourceforge.net
++S: Maintained
++W: https://f2fs.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
++F: Documentation/ABI/testing/sysfs-fs-f2fs
++F: Documentation/filesystems/f2fs.rst
++F: fs/f2fs/
++F: include/linux/f2fs_fs.h
++F: include/trace/events/f2fs.h
++F: include/uapi/linux/f2fs.h
++
++F71805F HARDWARE MONITORING DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/f71805f.rst
++F: drivers/hwmon/f71805f.c
++
++FADDR2LINE
++M: Josh Poimboeuf <jpoimboe@redhat.com>
++S: Maintained
++F: scripts/faddr2line
++
++FAILOVER MODULE
++M: Sridhar Samudrala <sridhar.samudrala@intel.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/failover.rst
++F: include/net/failover.h
++F: net/core/failover.c
++
++FANOTIFY
++M: Jan Kara <jack@suse.cz>
++R: Amir Goldstein <amir73il@gmail.com>
++R: Matthew Bobrowski <repnop@google.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/notify/fanotify/
++F: include/linux/fanotify.h
++F: include/uapi/linux/fanotify.h
++
++FARSYNC SYNCHRONOUS DRIVER
++M: Kevin Curtis <kevin.curtis@farsite.co.uk>
++S: Supported
++W: http://www.farsite.co.uk/
++F: drivers/net/wan/farsync.*
++
++FAULT INJECTION SUPPORT
++M: Akinobu Mita <akinobu.mita@gmail.com>
++S: Supported
++F: Documentation/fault-injection/
++F: lib/fault-inject.c
++
++FBTFT Framebuffer drivers
++L: dri-devel@lists.freedesktop.org
++L: linux-fbdev@vger.kernel.org
++S: Orphan
++F: drivers/staging/fbtft/
++
++FC0011 TUNER DRIVER
++M: Michael Buesch <m@bues.ch>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/tuners/fc0011.c
++F: drivers/media/tuners/fc0011.h
++
++FC2580 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/fc2580*
++
++FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
++M: Hannes Reinecke <hare@suse.de>
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: www.Open-FCoE.org
++F: drivers/scsi/fcoe/
++F: drivers/scsi/libfc/
++F: include/scsi/fc/
++F: include/scsi/libfc.h
++F: include/scsi/libfcoe.h
++F: include/uapi/scsi/fc/
++
++FILE LOCKING (flock() and fcntl()/lockf())
++M: Jeff Layton <jlayton@kernel.org>
++M: "J. Bruce Fields" <bfields@fieldses.org>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/fcntl.c
++F: fs/locks.c
++F: include/linux/fcntl.h
++F: include/uapi/linux/fcntl.h
++
++FILESYSTEM DIRECT ACCESS (DAX)
++M: Dan Williams <dan.j.williams@intel.com>
++R: Matthew Wilcox <willy@infradead.org>
++R: Jan Kara <jack@suse.cz>
++L: linux-fsdevel@vger.kernel.org
++L: nvdimm@lists.linux.dev
++S: Supported
++F: fs/dax.c
++F: include/linux/dax.h
++F: include/trace/events/fs_dax.h
++
++FILESYSTEMS (VFS and infrastructure)
++M: Alexander Viro <viro@zeniv.linux.org.uk>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/*
++F: include/linux/fs.h
++F: include/linux/fs_types.h
++F: include/uapi/linux/fs.h
++F: include/uapi/linux/openat2.h
++X: fs/io-wq.c
++X: fs/io-wq.h
++X: fs/io_uring.c
++
++FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
++M: Riku Voipio <riku.voipio@iki.fi>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/f75375s.c
++F: include/linux/f75375s.h
++
++FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE
++M: Clemens Ladisch <clemens@ladisch.de>
++M: Takashi Sakamoto <o-takashi@sakamocchi.jp>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: include/uapi/sound/firewire.h
++F: sound/firewire/
++
++FIREWIRE MEDIA DRIVERS (firedtv)
++M: Stefan Richter <stefanr@s5r6.in-berlin.de>
++L: linux-media@vger.kernel.org
++L: linux1394-devel@lists.sourceforge.net
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
++F: drivers/media/firewire/
++
++FIREWIRE SBP-2 TARGET
++M: Chris Boot <bootc@bootc.net>
++L: linux-scsi@vger.kernel.org
++L: target-devel@vger.kernel.org
++L: linux1394-devel@lists.sourceforge.net
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
++F: drivers/target/sbp/
++
++FIREWIRE SUBSYSTEM
++M: Stefan Richter <stefanr@s5r6.in-berlin.de>
++L: linux1394-devel@lists.sourceforge.net
++S: Maintained
++W: http://ieee1394.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git
++F: drivers/firewire/
++F: include/linux/firewire.h
++F: include/uapi/linux/firewire*.h
++F: tools/firewire/
++
++FIRMWARE FRAMEWORK FOR ARMV8-A
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/firmware/arm_ffa/
++F: include/linux/arm_ffa.h
++
++FIRMWARE LOADER (request_firmware)
++M: Luis Chamberlain <mcgrof@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/firmware_class/
++F: drivers/base/firmware_loader/
++F: include/linux/firmware.h
++
++FLASH ADAPTER DRIVER (IBM Flash Adapter 900GB Full Height PCI Flash Card)
++M: Joshua Morris <josh.h.morris@us.ibm.com>
++M: Philip Kelleher <pjk1939@linux.ibm.com>
++S: Maintained
++F: drivers/block/rsxx/
++
++FLEXTIMER FTM-QUADDEC DRIVER
++M: Patrick Havelange <patrick.havelange@essensium.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/counter/ftm-quaddec.txt
++F: drivers/counter/ftm-quaddec.c
++
++FLOPPY DRIVER
++M: Denis Efremov <efremov@linux.com>
++L: linux-block@vger.kernel.org
++S: Odd Fixes
++F: drivers/block/floppy.c
++
++FLYSKY FSIA6B RC RECEIVER
++M: Markus Koch <markus@notsyncing.net>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/joystick/fsia6b.c
++
++FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
++M: Geoffrey D. Bennett <g@b4.vu>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: sound/usb/mixer_scarlett_gen2.c
++
++FORCEDETH GIGABIT ETHERNET DRIVER
++M: Rain River <rain.1986.08.12@gmail.com>
++M: Zhu Yanjun <zyjzyj2000@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/nvidia/*
++
++FPGA DFL DRIVERS
++M: Wu Hao <hao.wu@intel.com>
++R: Tom Rix <trix@redhat.com>
++L: linux-fpga@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-dfl*
++F: Documentation/fpga/dfl.rst
++F: drivers/fpga/dfl*
++F: drivers/uio/uio_dfl.c
++F: include/linux/dfl.h
++F: include/uapi/linux/fpga-dfl.h
++
++FPGA MANAGER FRAMEWORK
++M: Moritz Fischer <mdf@kernel.org>
++M: Wu Hao <hao.wu@intel.com>
++M: Xu Yilun <yilun.xu@intel.com>
++R: Tom Rix <trix@redhat.com>
++L: linux-fpga@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-fpga/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga.git
++F: Documentation/devicetree/bindings/fpga/
++F: Documentation/driver-api/fpga/
++F: Documentation/fpga/
++F: drivers/fpga/
++F: include/linux/fpga/
++
++FPU EMULATOR
++M: Bill Metzenthen <billm@melbpc.org.au>
++S: Maintained
++W: http://floatingpoint.sourceforge.net/emulator/index.html
++F: arch/x86/math-emu/
++
++FRAMEBUFFER LAYER
++L: dri-devel@lists.freedesktop.org
++L: linux-fbdev@vger.kernel.org
++S: Orphan
++Q: http://patchwork.kernel.org/project/linux-fbdev/list/
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/fb/
++F: drivers/video/
++F: include/linux/fb.h
++F: include/uapi/linux/fb.h
++F: include/uapi/video/
++F: include/video/
++
++FREESCALE CAAM (Cryptographic Acceleration and Assurance Module) DRIVER
++M: Horia Geantă <horia.geanta@nxp.com>
++M: Pankaj Gupta <pankaj.gupta@nxp.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/crypto/fsl-sec4.txt
++F: drivers/crypto/caam/
++
++FREESCALE COLDFIRE M5441X MMC DRIVER
++M: Angelo Dureghello <angelo.dureghello@timesys.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci-esdhc-mcf.c
++F: include/linux/platform_data/mmc-esdhc-mcf.h
++
++FREESCALE DIU FRAMEBUFFER DRIVER
++M: Timur Tabi <timur@kernel.org>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/fsl-diu-fb.*
++
++FREESCALE DMA DRIVER
++M: Li Yang <leoyang.li@nxp.com>
++M: Zhang Wei <zw@zh-kernel.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/dma/fsldma.*
++
++FREESCALE DSPI DRIVER
++M: Vladimir Oltean <olteanv@gmail.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
++F: drivers/spi/spi-fsl-dspi.c
++F: include/linux/spi/spi-fsl-dspi.h
++
++FREESCALE ENETC ETHERNET DRIVERS
++M: Claudiu Manoil <claudiu.manoil@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/freescale/enetc/
++
++FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
++M: Claudiu Manoil <claudiu.manoil@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
++F: drivers/net/ethernet/freescale/gianfar*
++
++FREESCALE GPMI NAND DRIVER
++M: Han Xu <han.xu@nxp.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: drivers/mtd/nand/raw/gpmi-nand/*
++
++FREESCALE I2C CPM DRIVER
++M: Jochen Friedrich <jochen@scram.de>
++L: linuxppc-dev@lists.ozlabs.org
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-cpm.c
++
++FREESCALE IMX / MXC FEC DRIVER
++M: Joakim Zhang <qiangqing.zhang@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/fsl,fec.yaml
++F: drivers/net/ethernet/freescale/fec.h
++F: drivers/net/ethernet/freescale/fec_main.c
++F: drivers/net/ethernet/freescale/fec_ptp.c
++
++FREESCALE IMX / MXC FRAMEBUFFER DRIVER
++M: Sascha Hauer <s.hauer@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++L: linux-fbdev@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/video/fbdev/imxfb.c
++F: include/linux/platform_data/video-imxfb.h
++
++FREESCALE IMX DDR PMU DRIVER
++M: Frank Li <Frank.li@nxp.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/admin-guide/perf/imx-ddr.rst
++F: Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml
++F: drivers/perf/fsl_imx8_ddr_perf.c
++
++FREESCALE IMX I2C DRIVER
++M: Oleksij Rempel <o.rempel@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-imx.yaml
++F: drivers/i2c/busses/i2c-imx.c
++
++FREESCALE IMX LPI2C DRIVER
++M: Dong Aisheng <aisheng.dong@nxp.com>
++L: linux-i2c@vger.kernel.org
++L: linux-imx@nxp.com
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml
++F: drivers/i2c/busses/i2c-imx-lpi2c.c
++
++FREESCALE MPC I2C DRIVER
++M: Chris Packham <chris.packham@alliedtelesis.co.nz>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-mpc.yaml
++F: drivers/i2c/busses/i2c-mpc.c
++
++FREESCALE QORIQ DPAA ETHERNET DRIVER
++M: Madalin Bucur <madalin.bucur@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/freescale/dpaa
++
++FREESCALE QORIQ DPAA FMAN DRIVER
++M: Madalin Bucur <madalin.bucur@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/fsl-fman.txt
++F: drivers/net/ethernet/freescale/fman
++
++FREESCALE QORIQ PTP CLOCK DRIVER
++M: Yangbo Lu <yangbo.lu@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
++F: drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp*
++F: drivers/net/ethernet/freescale/dpaa2/dprtc*
++F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c
++F: drivers/ptp/ptp_qoriq.c
++F: drivers/ptp/ptp_qoriq_debugfs.c
++F: include/linux/fsl/ptp_qoriq.h
++
++FREESCALE QUAD SPI DRIVER
++M: Han Xu <han.xu@nxp.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml
++F: drivers/spi/spi-fsl-qspi.c
++
++FREESCALE QUICC ENGINE LIBRARY
++M: Qiang Zhao <qiang.zhao@nxp.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/soc/fsl/qe/
++F: include/soc/fsl/*qe*.h
++F: include/soc/fsl/*ucc*.h
++
++FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
++M: Li Yang <leoyang.li@nxp.com>
++L: netdev@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/net/ethernet/freescale/ucc_geth*
++
++FREESCALE QUICC ENGINE UCC HDLC DRIVER
++M: Zhao Qiang <qiang.zhao@nxp.com>
++L: netdev@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/net/wan/fsl_ucc_hdlc*
++
++FREESCALE QUICC ENGINE UCC UART DRIVER
++M: Timur Tabi <timur@kernel.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/tty/serial/ucc_uart.c
++
++FREESCALE SOC DRIVERS
++M: Li Yang <leoyang.li@nxp.com>
++L: linuxppc-dev@lists.ozlabs.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
++F: Documentation/devicetree/bindings/soc/fsl/
++F: drivers/soc/fsl/
++F: include/linux/fsl/
++
++FREESCALE SOC FS_ENET DRIVER
++M: Pantelis Antoniou <pantelis.antoniou@gmail.com>
++L: linuxppc-dev@lists.ozlabs.org
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/freescale/fs_enet/
++F: include/linux/fs_enet_pd.h
++
++FREESCALE SOC SOUND DRIVERS
++M: Nicolin Chen <nicoleotsuka@gmail.com>
++M: Xiubo Li <Xiubo.Lee@gmail.com>
++R: Fabio Estevam <festevam@gmail.com>
++R: Shengjiu Wang <shengjiu.wang@gmail.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: sound/soc/fsl/fsl*
++F: sound/soc/fsl/imx*
++F: sound/soc/fsl/mpc8610_hpcd.c
++
++FREESCALE USB PERIPHERAL DRIVERS
++M: Li Yang <leoyang.li@nxp.com>
++L: linux-usb@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/usb/gadget/udc/fsl*
++
++FREESCALE USB PHY DRIVER
++M: Ran Wang <ran.wang_1@nxp.com>
++L: linux-usb@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/usb/phy/phy-fsl-usb*
++
++FREEVXFS FILESYSTEM
++M: Christoph Hellwig <hch@infradead.org>
++S: Maintained
++W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
++F: fs/freevxfs/
++
++FREEZER
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Pavel Machek <pavel@ucw.cz>
++L: linux-pm@vger.kernel.org
++S: Supported
++F: Documentation/power/freezing-of-tasks.rst
++F: include/linux/freezer.h
++F: kernel/freezer.c
++
++FRONTSWAP API
++M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: include/linux/frontswap.h
++F: mm/frontswap.c
++
++FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS
++M: David Howells <dhowells@redhat.com>
++L: linux-cachefs@redhat.com (moderated for non-subscribers)
++S: Supported
++F: Documentation/filesystems/caching/
++F: fs/fscache/
++F: include/linux/fscache*.h
++
++FSCRYPT: FILE SYSTEM LEVEL ENCRYPTION SUPPORT
++M: Theodore Y. Ts'o <tytso@mit.edu>
++M: Jaegeuk Kim <jaegeuk@kernel.org>
++M: Eric Biggers <ebiggers@kernel.org>
++L: linux-fscrypt@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-fscrypt/list/
++T: git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git
++F: Documentation/filesystems/fscrypt.rst
++F: fs/crypto/
++F: include/linux/fscrypt*.h
++F: include/uapi/linux/fscrypt.h
++
++FSI SUBSYSTEM
++M: Jeremy Kerr <jk@ozlabs.org>
++M: Joel Stanley <joel@jms.id.au>
++R: Alistar Popple <alistair@popple.id.au>
++R: Eddie James <eajames@linux.ibm.com>
++L: linux-fsi@lists.ozlabs.org
++S: Supported
++Q: http://patchwork.ozlabs.org/project/linux-fsi/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi.git
++F: drivers/fsi/
++F: include/linux/fsi*.h
++F: include/trace/events/fsi*.h
++
++FSI-ATTACHED I2C DRIVER
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-i2c@vger.kernel.org
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-fsi.txt
++F: drivers/i2c/busses/i2c-fsi.c
++
++FSI-ATTACHED SPI DRIVER
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
++F: drivers/spi/spi-fsi.c
++
++FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE
++M: Jan Kara <jack@suse.cz>
++R: Amir Goldstein <amir73il@gmail.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git fsnotify
++F: fs/notify/
++F: include/linux/fsnotify*.h
++
++FSVERITY: READ-ONLY FILE-BASED AUTHENTICITY PROTECTION
++M: Eric Biggers <ebiggers@kernel.org>
++M: Theodore Y. Ts'o <tytso@mit.edu>
++L: linux-fscrypt@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-fscrypt/list/
++T: git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git fsverity
++F: Documentation/filesystems/fsverity.rst
++F: fs/verity/
++F: include/linux/fsverity.h
++F: include/uapi/linux/fsverity.h
++
++FT260 FTDI USB-HID TO I2C BRIDGE DRIVER
++M: Michael Zaidman <michael.zaidman@gmail.com>
++L: linux-i2c@vger.kernel.org
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-ft260.c
++
++FUJITSU LAPTOP EXTRAS
++M: Jonathan Woithe <jwoithe@just42.net>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/fujitsu-laptop.c
++
++FUJITSU M-5MO LS CAMERA ISP DRIVER
++M: Kyungmin Park <kyungmin.park@samsung.com>
++M: Heungjun Kim <riverful.kim@samsung.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/m5mols/
++F: include/media/i2c/m5mols.h
++
++FUJITSU TABLET EXTRAS
++M: Robert Gerlach <khnz@gmx.de>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/fujitsu-tablet.c
++
++FUSE: FILESYSTEM IN USERSPACE
++M: Miklos Szeredi <miklos@szeredi.hu>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++W: https://github.com/libfuse/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git
++F: Documentation/filesystems/fuse.rst
++F: fs/fuse/
++F: include/uapi/linux/fuse.h
++
++FUTEX SUBSYSTEM
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Ingo Molnar <mingo@redhat.com>
++R: Peter Zijlstra <peterz@infradead.org>
++R: Darren Hart <dvhart@infradead.org>
++R: Davidlohr Bueso <dave@stgolabs.net>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
++F: Documentation/locking/*futex*
++F: include/asm-generic/futex.h
++F: include/linux/futex.h
++F: include/uapi/linux/futex.h
++F: kernel/futex.c
++F: tools/perf/bench/futex*
++F: tools/testing/selftests/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>
++L: linux-hardening@vger.kernel.org
++S: Maintained
++F: Documentation/kbuild/gcc-plugins.rst
++F: scripts/Makefile.gcc-plugins
++F: scripts/gcc-plugins/
++
++GCOV BASED KERNEL PROFILING
++M: Peter Oberparleiter <oberpar@linux.ibm.com>
++S: Maintained
++F: Documentation/dev-tools/gcov.rst
++F: kernel/gcov/
++
++GDB KERNEL DEBUGGING HELPER SCRIPTS
++M: Jan Kiszka <jan.kiszka@siemens.com>
++M: Kieran Bingham <kbingham@kernel.org>
++S: Supported
++F: scripts/gdb/
++
++GEMINI CRYPTO DRIVER
++M: Corentin Labbe <clabbe@baylibre.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/gemini/
++
++GEMTEK FM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-gemtek*
++
++GENERIC ARCHITECTURE TOPOLOGY
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/base/arch_topology.c
++F: include/linux/arch_topology.h
++
++GENERIC ENTRY CODE
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Peter Zijlstra <peterz@infradead.org>
++M: Andy Lutomirski <luto@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/entry
++F: include/linux/entry-common.h
++F: include/linux/entry-kvm.h
++F: kernel/entry/
++
++GENERIC GPIO I2C DRIVER
++M: Wolfram Sang <wsa+renesas@sang-engineering.com>
++S: Supported
++F: drivers/i2c/busses/i2c-gpio.c
++F: include/linux/platform_data/i2c-gpio.h
++
++GENERIC GPIO I2C MULTIPLEXER DRIVER
++M: Peter Korsgaard <peter.korsgaard@barco.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++F: Documentation/i2c/muxes/i2c-mux-gpio.rst
++F: drivers/i2c/muxes/i2c-mux-gpio.c
++F: include/linux/platform_data/i2c-mux-gpio.h
++
++GENERIC HDLC (WAN) DRIVERS
++M: Krzysztof Halasa <khc@pm.waw.pl>
++S: Maintained
++W: http://www.kernel.org/pub/linux/utils/net/hdlc/
++F: drivers/net/wan/c101.c
++F: drivers/net/wan/hd6457*
++F: drivers/net/wan/hdlc*
++F: drivers/net/wan/n2.c
++F: drivers/net/wan/pc300too.c
++F: drivers/net/wan/pci200syn.c
++F: drivers/net/wan/wanxl*
++
++GENERIC INCLUDE/ASM HEADER FILES
++M: Arnd Bergmann <arnd@arndb.de>
++L: linux-arch@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
++F: include/asm-generic/
++F: include/uapi/asm-generic/
++
++GENERIC PHY FRAMEWORK
++M: Kishon Vijay Abraham I <kishon@ti.com>
++M: Vinod Koul <vkoul@kernel.org>
++L: linux-phy@lists.infradead.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-phy/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git
++F: Documentation/devicetree/bindings/phy/
++F: drivers/phy/
++F: include/linux/phy/
++
++GENERIC PINCTRL I2C DEMULTIPLEXER DRIVER
++M: Wolfram Sang <wsa+renesas@sang-engineering.com>
++S: Supported
++F: drivers/i2c/muxes/i2c-demux-pinctrl.c
++
++GENERIC PM DOMAINS
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Kevin Hilman <khilman@kernel.org>
++M: Ulf Hansson <ulf.hansson@linaro.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/power/power?domain*
++F: drivers/base/power/domain*.c
++F: include/linux/pm_domain.h
++
++GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
++M: Eugen Hristev <eugen.hristev@microchip.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/resistive-adc-touch.c
++
++GENERIC STRING LIBRARY
++R: Andy Shevchenko <andy@kernel.org>
++S: Maintained
++F: lib/string.c
++F: lib/string_helpers.c
++F: lib/test_string.c
++F: lib/test-string_helpers.c
++
++GENERIC UIO DRIVER FOR PCI DEVICES
++M: "Michael S. Tsirkin" <mst@redhat.com>
++L: kvm@vger.kernel.org
++S: Supported
++F: drivers/uio/uio_pci_generic.c
++
++GENERIC VDSO LIBRARY
++M: Andy Lutomirski <luto@kernel.org>
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Vincenzo Frascino <vincenzo.frascino@arm.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso
++F: include/asm-generic/vdso/vsyscall.h
++F: include/vdso/
++F: kernel/time/vsyscall.c
++F: lib/vdso/
++
++GENWQE (IBM Generic Workqueue Card)
++M: Frank Haverkamp <haver@linux.ibm.com>
++S: Supported
++F: drivers/misc/genwqe/
++
++GET_MAINTAINER SCRIPT
++M: Joe Perches <joe@perches.com>
++S: Maintained
++F: scripts/get_maintainer.pl
++
++GFS2 FILE SYSTEM
++M: Bob Peterson <rpeterso@redhat.com>
++M: Andreas Gruenbacher <agruenba@redhat.com>
++L: cluster-devel@redhat.com
++S: Supported
++B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=gfs2
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
++F: Documentation/filesystems/gfs2*
++F: fs/gfs2/
++F: include/uapi/linux/gfs2_ondisk.h
++
++GIGABYTE WMI DRIVER
++M: Thomas Weißschuh <thomas@weissschuh.net>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/gigabyte-wmi.c
++
++GNSS SUBSYSTEM
++M: Johan Hovold <johan@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git
++F: Documentation/ABI/testing/sysfs-class-gnss
++F: Documentation/devicetree/bindings/gnss/
++F: drivers/gnss/
++F: include/linux/gnss.h
++
++GO7007 MPEG CODEC
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/usb/go7007/
++
++GOODIX TOUCHSCREEN
++M: Bastien Nocera <hadess@hadess.net>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/goodix.c
++
++GOOGLE ETHERNET DRIVERS
++M: Jeroen de Borst <jeroendb@google.com>
++R: Catherine Sullivan <csully@google.com>
++R: David Awogbemila <awogbemila@google.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/ethernet/google/gve.rst
++F: drivers/net/ethernet/google
++
++GPD POCKET FAN DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/gpd-pocket-fan.c
++
++GPIO ACPI SUPPORT
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++L: linux-gpio@vger.kernel.org
++L: linux-acpi@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
++F: Documentation/firmware-guide/acpi/gpio-properties.rst
++F: drivers/gpio/gpiolib-acpi.c
++F: drivers/gpio/gpiolib-acpi.h
++
++GPIO AGGREGATOR
++M: Geert Uytterhoeven <geert+renesas@glider.be>
++L: linux-gpio@vger.kernel.org
++S: Supported
++F: Documentation/admin-guide/gpio/gpio-aggregator.rst
++F: drivers/gpio/gpio-aggregator.c
++
++GPIO IR Transmitter
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/gpio-ir-tx.c
++
++GPIO MOCKUP DRIVER
++M: Bamvor Jian Zhang <bamv2005@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-mockup.c
++F: tools/testing/selftests/gpio/
++
++GPIO REGMAP
++R: Michael Walle <michael@walle.cc>
++S: Maintained
++F: drivers/gpio/gpio-regmap.c
++F: include/linux/gpio/regmap.h
++
++GPIO SUBSYSTEM
++M: Linus Walleij <linus.walleij@linaro.org>
++M: Bartosz Golaszewski <brgl@bgdev.pl>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
++F: Documentation/ABI/obsolete/sysfs-gpio
++F: Documentation/ABI/testing/gpio-cdev
++F: Documentation/admin-guide/gpio/
++F: Documentation/devicetree/bindings/gpio/
++F: Documentation/driver-api/gpio/
++F: drivers/gpio/
++F: include/asm-generic/gpio.h
++F: include/linux/gpio.h
++F: include/linux/gpio/
++F: include/linux/of_gpio.h
++F: include/uapi/linux/gpio.h
++F: tools/gpio/
++
++GRE DEMULTIPLEXER DRIVER
++M: Dmitry Kozlov <xeb@mail.ru>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/net/gre.h
++F: net/ipv4/gre_demux.c
++F: net/ipv4/gre_offload.c
++
++GRETH 10/100/1G Ethernet MAC device driver
++M: Andreas Larsson <andreas@gaisler.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/aeroflex/
++
++GREYBUS AUDIO PROTOCOLS DRIVERS
++M: Vaibhav Agarwal <vaibhav.sr@gmail.com>
++M: Mark Greer <mgreer@animalcreek.com>
++S: Maintained
++F: drivers/staging/greybus/audio_apbridgea.c
++F: drivers/staging/greybus/audio_apbridgea.h
++F: drivers/staging/greybus/audio_codec.c
++F: drivers/staging/greybus/audio_codec.h
++F: drivers/staging/greybus/audio_gb.c
++F: drivers/staging/greybus/audio_manager.c
++F: drivers/staging/greybus/audio_manager.h
++F: drivers/staging/greybus/audio_manager_module.c
++F: drivers/staging/greybus/audio_manager_private.h
++F: drivers/staging/greybus/audio_manager_sysfs.c
++F: drivers/staging/greybus/audio_module.c
++F: drivers/staging/greybus/audio_topology.c
++
++GREYBUS FW/HID/SPI PROTOCOLS DRIVERS
++M: Viresh Kumar <vireshk@kernel.org>
++S: Maintained
++F: drivers/staging/greybus/authentication.c
++F: drivers/staging/greybus/bootrom.c
++F: drivers/staging/greybus/firmware.h
++F: drivers/staging/greybus/fw-core.c
++F: drivers/staging/greybus/fw-download.c
++F: drivers/staging/greybus/fw-management.c
++F: drivers/staging/greybus/greybus_authentication.h
++F: drivers/staging/greybus/greybus_firmware.h
++F: drivers/staging/greybus/hid.c
++F: drivers/staging/greybus/i2c.c
++F: drivers/staging/greybus/spi.c
++F: drivers/staging/greybus/spilib.c
++F: drivers/staging/greybus/spilib.h
++
++GREYBUS LOOPBACK DRIVER
++M: Bryan O'Donoghue <pure.logic@nexus-software.ie>
++S: Maintained
++F: drivers/staging/greybus/loopback.c
++
++GREYBUS PLATFORM DRIVERS
++M: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
++S: Maintained
++F: drivers/staging/greybus/arche-apb-ctrl.c
++F: drivers/staging/greybus/arche-platform.c
++F: drivers/staging/greybus/arche_platform.h
++
++GREYBUS SDIO/GPIO/SPI PROTOCOLS DRIVERS
++M: Rui Miguel Silva <rmfrfs@gmail.com>
++S: Maintained
++F: drivers/staging/greybus/gpio.c
++F: drivers/staging/greybus/light.c
++F: drivers/staging/greybus/power_supply.c
++F: drivers/staging/greybus/sdio.c
++F: drivers/staging/greybus/spi.c
++F: drivers/staging/greybus/spilib.c
++
++GREYBUS SUBSYSTEM
++M: Johan Hovold <johan@kernel.org>
++M: Alex Elder <elder@kernel.org>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: greybus-dev@lists.linaro.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/greybus/
++F: drivers/staging/greybus/
++F: include/linux/greybus.h
++F: include/linux/greybus/
++
++GREYBUS UART PROTOCOLS DRIVERS
++M: David Lin <dtwlin@gmail.com>
++S: Maintained
++F: drivers/staging/greybus/log.c
++F: drivers/staging/greybus/uart.c
++
++GS1662 VIDEO SERIALIZER
++M: Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/spi/gs1662.c
++
++GSPCA FINEPIX SUBDRIVER
++M: Frank Zago <frank@zago.net>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/finepix.c
++
++GSPCA GL860 SUBDRIVER
++M: Olivier Lorin <o.lorin@laposte.net>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/gl860/
++
++GSPCA M5602 SUBDRIVER
++M: Erik Andren <erik.andren@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/m5602/
++
++GSPCA PAC207 SONIXB SUBDRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/pac207.c
++
++GSPCA SN9C20X SUBDRIVER
++M: Brian Johnson <brijohn@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/sn9c20x.c
++
++GSPCA T613 SUBDRIVER
++M: Leandro Costantino <lcostantino@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/t613.c
++
++GSPCA USB WEBCAM DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/gspca/
++
++GTP (GPRS Tunneling Protocol)
++M: Pablo Neira Ayuso <pablo@netfilter.org>
++M: Harald Welte <laforge@gnumonks.org>
++L: osmocom-net-gprs@lists.osmocom.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/gtp.git
++F: drivers/net/gtp.c
++
++GUID PARTITION TABLE (GPT)
++M: Davidlohr Bueso <dave@stgolabs.net>
++L: linux-efi@vger.kernel.org
++S: Maintained
++F: block/partitions/efi.*
++
++H8/300 ARCHITECTURE
++M: Yoshinori Sato <ysato@users.sourceforge.jp>
++L: uclinux-h8-devel@lists.sourceforge.jp (moderated for non-subscribers)
++S: Maintained
++W: http://uclinux-h8.sourceforge.jp
++T: git git://git.sourceforge.jp/gitroot/uclinux-h8/linux.git
++F: arch/h8300/
++F: drivers/clk/h8300/
++F: drivers/clocksource/h8300_*.c
++F: drivers/irqchip/irq-renesas-h8*.c
++
++HABANALABS PCI DRIVER
++M: Oded Gabbay <ogabbay@kernel.org>
++S: Supported
++T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/linux.git
++F: Documentation/ABI/testing/debugfs-driver-habanalabs
++F: Documentation/ABI/testing/sysfs-driver-habanalabs
++F: drivers/misc/habanalabs/
++F: include/uapi/misc/habanalabs.h
++
++HACKRF MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/hackrf/
++
++HANTRO VPU CODEC DRIVER
++M: Ezequiel Garcia <ezequiel@collabora.com>
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: linux-media@vger.kernel.org
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
++F: Documentation/devicetree/bindings/media/rockchip-vpu.yaml
++F: drivers/staging/media/hantro/
++
++HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
++M: Frank Seidel <frank@f-seidel.de>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
++F: drivers/platform/x86/hdaps.c
++
++HARDWARE MONITORING
++M: Jean Delvare <jdelvare@suse.com>
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++W: http://hwmon.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
++F: Documentation/devicetree/bindings/hwmon/
++F: Documentation/hwmon/
++F: drivers/hwmon/
++F: include/linux/hwmon*.h
++F: include/trace/events/hwmon*.h
++K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info)
++
++HARDWARE RANDOM NUMBER GENERATOR CORE
++M: Matt Mackall <mpm@selenic.com>
++M: Herbert Xu <herbert@gondor.apana.org.au>
++L: linux-crypto@vger.kernel.org
++S: Odd fixes
++F: Documentation/admin-guide/hw_random.rst
++F: Documentation/devicetree/bindings/rng/
++F: drivers/char/hw_random/
++F: include/linux/hw_random.h
++
++HARDWARE SPINLOCK CORE
++M: Ohad Ben-Cohen <ohad@wizery.com>
++M: Bjorn Andersson <bjorn.andersson@linaro.org>
++R: Baolin Wang <baolin.wang7@gmail.com>
++L: linux-remoteproc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git hwspinlock-next
++F: Documentation/devicetree/bindings/hwlock/
++F: Documentation/locking/hwspinlock.rst
++F: drivers/hwspinlock/
++F: include/linux/hwspinlock.h
++
++HARDWARE TRACING FACILITIES
++M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
++S: Maintained
++F: drivers/hwtracing/
++
++HARMONY SOUND DRIVER
++L: linux-parisc@vger.kernel.org
++S: Maintained
++F: sound/parisc/harmony.*
++
++HDPVR USB VIDEO ENCODER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/hdpvr/
++
++HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER
++M: Matt Hsiao <matt.hsiao@hpe.com>
++S: Supported
++F: drivers/misc/hpilo.[ch]
++
++HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
++M: Jerry Hoemann <jerry.hoemann@hpe.com>
++S: Supported
++F: Documentation/watchdog/hpwdt.rst
++F: drivers/watchdog/hpwdt.c
++
++HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
++M: Don Brace <don.brace@microchip.com>
++L: storagedev@microchip.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: Documentation/scsi/hpsa.rst
++F: drivers/scsi/hpsa*.[ch]
++F: include/linux/cciss*.h
++F: include/uapi/linux/cciss*.h
++
++HFI1 DRIVER
++M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
++M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/hw/hfi1
++
++HFS FILESYSTEM
++L: linux-fsdevel@vger.kernel.org
++S: Orphan
++F: Documentation/filesystems/hfs.rst
++F: fs/hfs/
++
++HFSPLUS FILESYSTEM
++L: linux-fsdevel@vger.kernel.org
++S: Orphan
++F: Documentation/filesystems/hfsplus.rst
++F: fs/hfsplus/
++
++HGA FRAMEBUFFER DRIVER
++M: Ferenc Bakonyi <fero@drama.obuda.kando.hu>
++L: linux-nvidia@lists.surfsouth.com
++S: Maintained
++W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
++F: drivers/video/fbdev/hgafb.c
++
++HIBERNATION (aka Software Suspend, aka swsusp)
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Pavel Machek <pavel@ucw.cz>
++L: linux-pm@vger.kernel.org
++S: Supported
++B: https://bugzilla.kernel.org
++F: arch/*/include/asm/suspend*.h
++F: arch/x86/power/
++F: drivers/base/power/
++F: include/linux/freezer.h
++F: include/linux/pm.h
++F: include/linux/suspend.h
++F: kernel/power/
++
++HID CORE LAYER
++M: Jiri Kosina <jikos@kernel.org>
++M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
++F: drivers/hid/
++F: include/linux/hid*
++F: include/uapi/linux/hid*
++
++HID PLAYSTATION DRIVER
++M: Roderick Colenbrander <roderick.colenbrander@sony.com>
++L: linux-input@vger.kernel.org
++S: Supported
++F: drivers/hid/hid-playstation.c
++
++HID SENSOR HUB DRIVERS
++M: Jiri Kosina <jikos@kernel.org>
++M: Jonathan Cameron <jic23@kernel.org>
++M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
++L: linux-input@vger.kernel.org
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/hid/hid-sensor*
++F: drivers/hid/hid-sensor-*
++F: drivers/iio/*/hid-*
++F: include/linux/hid-sensor-*
++
++HIGH-RESOLUTION TIMERS, CLOCKEVENTS
++M: Thomas Gleixner <tglx@linutronix.de>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
++F: Documentation/timers/
++F: include/linux/clockchips.h
++F: include/linux/hrtimer.h
++F: kernel/time/clockevents.c
++F: kernel/time/hrtimer.c
++F: kernel/time/timer_*.c
++
++HIGH-SPEED SCC DRIVER FOR AX.25
++L: linux-hams@vger.kernel.org
++S: Orphan
++F: drivers/net/hamradio/dmascc.c
++F: drivers/net/hamradio/scc.c
++
++HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
++M: HighPoint Linux Team <linux@highpoint-tech.com>
++S: Supported
++W: http://www.highpoint-tech.com
++F: Documentation/scsi/hptiop.rst
++F: drivers/scsi/hptiop.c
++
++HIPPI
++M: Jes Sorensen <jes@trained-monkey.org>
++L: linux-hippi@sunsite.dk
++S: Maintained
++F: drivers/net/hippi/
++F: include/linux/hippidevice.h
++F: include/uapi/linux/if_hippi.h
++F: net/802/hippi.c
++
++HIRSCHMANN HELLCREEK ETHERNET SWITCH DRIVER
++M: Kurt Kanzenbach <kurt@linutronix.de>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/hirschmann,hellcreek.yaml
++F: drivers/net/dsa/hirschmann/*
++F: include/linux/platform_data/hirschmann-hellcreek.h
++F: net/dsa/tag_hellcreek.c
++
++HISILICON DMA DRIVER
++M: Zhou Wang <wangzhou1@hisilicon.com>
++L: dmaengine@vger.kernel.org
++S: Maintained
++F: drivers/dma/hisi_dma.c
++
++HISILICON GPIO DRIVER
++M: Luo Jiaxing <luojiaxing@huawei.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-hisi.c
++
++HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
++M: Zaibo Xu <xuzaibo@huawei.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/debugfs-hisi-hpre
++F: drivers/crypto/hisilicon/hpre/hpre.h
++F: drivers/crypto/hisilicon/hpre/hpre_crypto.c
++F: drivers/crypto/hisilicon/hpre/hpre_main.c
++
++HISILICON I2C CONTROLLER DRIVER
++M: Yicong Yang <yangyicong@hisilicon.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++W: https://www.hisilicon.com
++F: drivers/i2c/busses/i2c-hisi.c
++
++HISILICON LPC BUS DRIVER
++M: john.garry@huawei.com
++S: Maintained
++W: http://www.hisilicon.com
++F: Documentation/devicetree/bindings/arm/hisilicon/low-pin-count.yaml
++F: drivers/bus/hisi_lpc.c
++
++HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
++M: Yisen Zhuang <yisen.zhuang@huawei.com>
++M: Salil Mehta <salil.mehta@huawei.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.hisilicon.com
++F: drivers/net/ethernet/hisilicon/hns3/
++
++HISILICON NETWORK SUBSYSTEM DRIVER
++M: Yisen Zhuang <yisen.zhuang@huawei.com>
++M: Salil Mehta <salil.mehta@huawei.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.hisilicon.com
++F: Documentation/devicetree/bindings/net/hisilicon*.txt
++F: drivers/net/ethernet/hisilicon/
++
++HIKEY960 ONBOARD USB GPIO HUB DRIVER
++M: John Stultz <john.stultz@linaro.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/misc/hisi_hikey_usb.c
++F: Documentation/devicetree/bindings/misc/hisilicon-hikey-usb.yaml
++
++HISILICON PMU DRIVER
++M: Shaokun Zhang <zhangshaokun@hisilicon.com>
++S: Supported
++W: http://www.hisilicon.com
++F: Documentation/admin-guide/perf/hisi-pmu.rst
++F: drivers/perf/hisilicon
++
++HISILICON QM AND ZIP Controller DRIVER
++M: Zhou Wang <wangzhou1@hisilicon.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/debugfs-hisi-zip
++F: drivers/crypto/hisilicon/qm.c
++F: drivers/crypto/hisilicon/qm.h
++F: drivers/crypto/hisilicon/sgl.c
++F: drivers/crypto/hisilicon/zip/
++
++HISILICON ROCE DRIVER
++M: Wenpeng Liang <liangwenpeng@huawei.com>
++M: Weihang Li <liweihang@huawei.com>
++L: linux-rdma@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
++F: drivers/infiniband/hw/hns/
++
++HISILICON SAS Controller
++M: John Garry <john.garry@huawei.com>
++S: Supported
++W: http://www.hisilicon.com
++F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
++F: drivers/scsi/hisi_sas/
++
++HISILICON SECURITY ENGINE V2 DRIVER (SEC2)
++M: Zaibo Xu <xuzaibo@huawei.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/debugfs-hisi-sec
++F: drivers/crypto/hisilicon/sec2/sec.h
++F: drivers/crypto/hisilicon/sec2/sec_crypto.c
++F: drivers/crypto/hisilicon/sec2/sec_crypto.h
++F: drivers/crypto/hisilicon/sec2/sec_main.c
++
++HISILICON SPI Controller DRIVER FOR KUNPENG SOCS
++M: Jay Fang <f.fangjian@huawei.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++W: http://www.hisilicon.com
++F: drivers/spi/spi-hisi-kunpeng.c
++
++HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970
++M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
++F: drivers/spmi/hisi-spmi-controller.c
++
++HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
++M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
++F: drivers/mfd/hi6421-spmi-pmic.c
++
++HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
++M: Zaibo Xu <xuzaibo@huawei.com>
++S: Maintained
++F: drivers/crypto/hisilicon/trng/trng.c
++
++HISILICON V3XX SPI NOR FLASH Controller Driver
++M: John Garry <john.garry@huawei.com>
++S: Maintained
++W: http://www.hisilicon.com
++F: drivers/spi/spi-hisi-sfc-v3xx.c
++
++HMM - Heterogeneous Memory Management
++M: Jérôme Glisse <jglisse@redhat.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: Documentation/vm/hmm.rst
++F: include/linux/hmm*
++F: lib/test_hmm*
++F: mm/hmm*
++F: tools/testing/selftests/vm/*hmm*
++
++HOST AP DRIVER
++M: Jouni Malinen <j@w1.fi>
++L: linux-wireless@vger.kernel.org
++S: Obsolete
++W: http://w1.fi/hostap-driver.html
++F: drivers/net/wireless/intersil/hostap/
++
++HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
++L: platform-driver-x86@vger.kernel.org
++S: Orphan
++F: drivers/platform/x86/tc1100-wmi.c
++
++HPET: High Precision Event Timers driver
++M: Clemens Ladisch <clemens@ladisch.de>
++S: Maintained
++F: Documentation/timers/hpet.rst
++F: drivers/char/hpet.c
++F: include/linux/hpet.h
++F: include/uapi/linux/hpet.h
++
++HPET: x86
++S: Orphan
++F: arch/x86/include/asm/hpet.h
++F: arch/x86/kernel/hpet.c
++
++HPFS FILESYSTEM
++M: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
++S: Maintained
++W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
++F: fs/hpfs/
++
++HSI SUBSYSTEM
++M: Sebastian Reichel <sre@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git
++F: Documentation/ABI/testing/sysfs-bus-hsi
++F: Documentation/driver-api/hsi.rst
++F: drivers/hsi/
++F: include/linux/hsi/
++F: include/uapi/linux/hsi/
++
++HSO 3G MODEM DRIVER
++L: linux-usb@vger.kernel.org
++S: Orphan
++F: drivers/net/usb/hso.c
++
++HSR NETWORK PROTOCOL
++L: netdev@vger.kernel.org
++S: Orphan
++F: net/hsr/
++
++HT16K33 LED CONTROLLER DRIVER
++M: Robin van der Gracht <robin@protonic.nl>
++S: Maintained
++F: Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++F: drivers/auxdisplay/ht16k33.c
++
++HTCPEN TOUCHSCREEN DRIVER
++M: Pau Oliva Fora <pof@eslack.org>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/htcpen.c
++
++HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
++M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++W: http://www.st.com/
++F: Documentation/devicetree/bindings/iio/humidity/st,hts221.yaml
++F: drivers/iio/humidity/hts221*
++
++HUAWEI ETHERNET DRIVER
++L: netdev@vger.kernel.org
++S: Orphan
++F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst
++F: drivers/net/ethernet/huawei/hinic/
++
++HUGETLB FILESYSTEM
++M: Mike Kravetz <mike.kravetz@oracle.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-kernel-mm-hugepages
++F: Documentation/admin-guide/mm/hugetlbpage.rst
++F: Documentation/vm/hugetlbfs_reserv.rst
++F: fs/hugetlbfs/
++F: include/linux/hugetlb.h
++F: mm/hugetlb.c
++
++HVA ST MEDIA DRIVER
++M: Jean-Christophe Trotin <jean-christophe.trotin@foss.st.com>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/platform/sti/hva
++
++HWPOISON MEMORY FAILURE HANDLING
++M: Naoya Horiguchi <naoya.horiguchi@nec.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: mm/hwpoison-inject.c
++F: mm/memory-failure.c
++
++HYCON HY46XX TOUCHSCREEN SUPPORT
++M: Giulio Benetti <giulio.benetti@benettiengineering.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/input/touchscreen/hycon,hy46xx.yaml
++F: drivers/input/touchscreen/hycon-hy46xx.c
++
++HYGON PROCESSOR SUPPORT
++M: Pu Wen <puwen@hygon.cn>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: arch/x86/kernel/cpu/hygon.c
++
++HYNIX HI556 SENSOR DRIVER
++M: Shawn Tu <shawnx.tu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/hi556.c
++
++Hyper-V/Azure CORE AND DRIVERS
++M: "K. Y. Srinivasan" <kys@microsoft.com>
++M: Haiyang Zhang <haiyangz@microsoft.com>
++M: Stephen Hemminger <sthemmin@microsoft.com>
++M: Wei Liu <wei.liu@kernel.org>
++M: Dexuan Cui <decui@microsoft.com>
++L: linux-hyperv@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
++F: Documentation/ABI/stable/sysfs-bus-vmbus
++F: Documentation/ABI/testing/debugfs-hyperv
++F: Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst
++F: arch/arm64/hyperv
++F: arch/arm64/include/asm/hyperv-tlfs.h
++F: arch/arm64/include/asm/mshyperv.h
++F: arch/x86/hyperv
++F: arch/x86/include/asm/hyperv-tlfs.h
++F: arch/x86/include/asm/mshyperv.h
++F: arch/x86/include/asm/trace/hyperv.h
++F: arch/x86/kernel/cpu/mshyperv.c
++F: drivers/clocksource/hyperv_timer.c
++F: drivers/hid/hid-hyperv.c
++F: drivers/hv/
++F: drivers/input/serio/hyperv-keyboard.c
++F: drivers/iommu/hyperv-iommu.c
++F: drivers/net/ethernet/microsoft/
++F: drivers/net/hyperv/
++F: drivers/pci/controller/pci-hyperv-intf.c
++F: drivers/pci/controller/pci-hyperv.c
++F: drivers/scsi/storvsc_drv.c
++F: drivers/uio/uio_hv_generic.c
++F: drivers/video/fbdev/hyperv_fb.c
++F: include/asm-generic/hyperv-tlfs.h
++F: include/asm-generic/mshyperv.h
++F: include/clocksource/hyperv_timer.h
++F: include/linux/hyperv.h
++F: include/uapi/linux/hyperv.h
++F: net/vmw_vsock/hyperv_transport.c
++F: tools/hv/
++
++HYPERBUS SUPPORT
++M: Vignesh Raghavendra <vigneshr@ti.com>
++L: linux-mtd@lists.infradead.org
++S: Supported
++Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
++C: irc://irc.oftc.net/mtd
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git cfi/next
++F: Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt
++F: Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt
++F: drivers/mtd/hyperbus/
++F: include/linux/mtd/hyperbus.h
++
++HYPERVISOR VIRTUAL CONSOLE DRIVER
++L: linuxppc-dev@lists.ozlabs.org
++S: Odd Fixes
++F: drivers/tty/hvc/
++
++I2C ACPI SUPPORT
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++L: linux-i2c@vger.kernel.org
++L: linux-acpi@vger.kernel.org
++S: Maintained
++F: drivers/i2c/i2c-core-acpi.c
++
++I2C CONTROLLER DRIVER FOR NVIDIA GPU
++M: Ajay Gupta <ajayg@nvidia.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/i2c/busses/i2c-nvidia-gpu.rst
++F: drivers/i2c/busses/i2c-nvidia-gpu.c
++
++I2C MUXES
++M: Peter Rosin <peda@axentia.se>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-arb*
++F: Documentation/devicetree/bindings/i2c/i2c-gate*
++F: Documentation/devicetree/bindings/i2c/i2c-mux*
++F: Documentation/i2c/i2c-topology.rst
++F: Documentation/i2c/muxes/
++F: drivers/i2c/i2c-mux.c
++F: drivers/i2c/muxes/
++F: include/linux/i2c-mux.h
++
++I2C MV64XXX MARVELL AND ALLWINNER DRIVER
++M: Gregory CLEMENT <gregory.clement@bootlin.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
++F: drivers/i2c/busses/i2c-mv64xxx.c
++
++I2C OVER PARALLEL PORT
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/i2c/busses/i2c-parport.rst
++F: drivers/i2c/busses/i2c-parport.c
++
++I2C SUBSYSTEM
++M: Wolfram Sang <wsa@kernel.org>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++W: https://i2c.wiki.kernel.org/
++Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
++F: Documentation/devicetree/bindings/i2c/i2c.txt
++F: Documentation/i2c/
++F: drivers/i2c/*
++F: include/linux/i2c-dev.h
++F: include/linux/i2c-smbus.h
++F: include/linux/i2c.h
++F: include/uapi/linux/i2c-*.h
++F: include/uapi/linux/i2c.h
++
++I2C SUBSYSTEM HOST DRIVERS
++L: linux-i2c@vger.kernel.org
++S: Odd Fixes
++W: https://i2c.wiki.kernel.org/
++Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
++F: Documentation/devicetree/bindings/i2c/
++F: drivers/i2c/algos/
++F: drivers/i2c/busses/
++
++I2C-TAOS-EVM DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/i2c/busses/i2c-taos-evm.rst
++F: drivers/i2c/busses/i2c-taos-evm.c
++
++I2C-TINY-USB DRIVER
++M: Till Harbaum <till@harbaum.org>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++W: http://www.harbaum.org/till/i2c_tiny_usb
++F: drivers/i2c/busses/i2c-tiny-usb.c
++
++I2C/SMBUS CONTROLLER DRIVERS FOR PC
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/i2c/busses/i2c-ali1535.rst
++F: Documentation/i2c/busses/i2c-ali1563.rst
++F: Documentation/i2c/busses/i2c-ali15x3.rst
++F: Documentation/i2c/busses/i2c-amd756.rst
++F: Documentation/i2c/busses/i2c-amd8111.rst
++F: Documentation/i2c/busses/i2c-i801.rst
++F: Documentation/i2c/busses/i2c-nforce2.rst
++F: Documentation/i2c/busses/i2c-piix4.rst
++F: Documentation/i2c/busses/i2c-sis5595.rst
++F: Documentation/i2c/busses/i2c-sis630.rst
++F: Documentation/i2c/busses/i2c-sis96x.rst
++F: Documentation/i2c/busses/i2c-via.rst
++F: Documentation/i2c/busses/i2c-viapro.rst
++F: drivers/i2c/busses/i2c-ali1535.c
++F: drivers/i2c/busses/i2c-ali1563.c
++F: drivers/i2c/busses/i2c-ali15x3.c
++F: drivers/i2c/busses/i2c-amd756-s4882.c
++F: drivers/i2c/busses/i2c-amd756.c
++F: drivers/i2c/busses/i2c-amd8111.c
++F: drivers/i2c/busses/i2c-i801.c
++F: drivers/i2c/busses/i2c-isch.c
++F: drivers/i2c/busses/i2c-nforce2-s4985.c
++F: drivers/i2c/busses/i2c-nforce2.c
++F: drivers/i2c/busses/i2c-piix4.c
++F: drivers/i2c/busses/i2c-sis5595.c
++F: drivers/i2c/busses/i2c-sis630.c
++F: drivers/i2c/busses/i2c-sis96x.c
++F: drivers/i2c/busses/i2c-via.c
++F: drivers/i2c/busses/i2c-viapro.c
++
++I2C/SMBUS INTEL CHT WHISKEY COVE PMIC DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-cht-wc.c
++
++I2C/SMBUS ISMT DRIVER
++M: Seth Heasley <seth.heasley@intel.com>
++M: Neil Horman <nhorman@tuxdriver.com>
++L: linux-i2c@vger.kernel.org
++F: Documentation/i2c/busses/i2c-ismt.rst
++F: drivers/i2c/busses/i2c-ismt.c
++
++I2C/SMBUS STUB DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/i2c-stub.c
++
++I3C DRIVER FOR CADENCE I3C MASTER IP
++M: Przemysław Gaj <pgaj@cadence.com>
++S: Maintained
++F: Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt
++F: drivers/i3c/master/i3c-master-cdns.c
++
++I3C DRIVER FOR SYNOPSYS DESIGNWARE
++M: Vitor Soares <vitor.soares@synopsys.com>
++S: Maintained
++F: Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt
++F: drivers/i3c/master/dw*
++
++I3C SUBSYSTEM
++M: Alexandre Belloni <alexandre.belloni@bootlin.com>
++L: linux-i3c@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++C: irc://chat.freenode.net/linux-i3c
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
++F: Documentation/ABI/testing/sysfs-bus-i3c
++F: Documentation/devicetree/bindings/i3c/
++F: Documentation/driver-api/i3c
++F: drivers/i3c/
++F: include/linux/i3c/
++
++IA64 (Itanium) PLATFORM
++L: linux-ia64@vger.kernel.org
++S: Orphan
++F: Documentation/ia64/
++F: arch/ia64/
++
++IBM Power 842 compression accelerator
++M: Haren Myneni <haren@us.ibm.com>
++S: Supported
++F: crypto/842.c
++F: drivers/crypto/nx/Kconfig
++F: drivers/crypto/nx/Makefile
++F: drivers/crypto/nx/nx-842*
++F: include/linux/sw842.h
++F: lib/842/
++
++IBM Power in-Nest Crypto Acceleration
++M: Breno Leitão <leitao@debian.org>
++M: Nayna Jain <nayna@linux.ibm.com>
++M: Paulo Flabiano Smorigo <pfsmorigo@gmail.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++F: drivers/crypto/nx/Kconfig
++F: drivers/crypto/nx/Makefile
++F: drivers/crypto/nx/nx-aes*
++F: drivers/crypto/nx/nx-sha*
++F: drivers/crypto/nx/nx.*
++F: drivers/crypto/nx/nx_csbcpb.h
++F: drivers/crypto/nx/nx_debugfs.c
++
++IBM Power IO DLPAR Driver for RPA-compliant PPC64 platform
++M: Tyrel Datwyler <tyreld@linux.ibm.com>
++L: linux-pci@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: drivers/pci/hotplug/rpadlpar*
++
++IBM Power Linux RAID adapter
++M: Brian King <brking@us.ibm.com>
++S: Supported
++F: drivers/scsi/ipr.*
++
++IBM Power PCI Hotplug Driver for RPA-compliant PPC64 platform
++M: Tyrel Datwyler <tyreld@linux.ibm.com>
++L: linux-pci@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: drivers/pci/hotplug/rpaphp*
++
++IBM Power SRIOV Virtual NIC Device Driver
++M: Dany Madden <drt@linux.ibm.com>
++M: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
++R: Thomas Falcon <tlfalcon@linux.ibm.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/ibm/ibmvnic.*
++
++IBM Power Virtual Accelerator Switchboard
++M: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: arch/powerpc/include/asm/vas.h
++F: arch/powerpc/platforms/powernv/copy-paste.h
++F: arch/powerpc/platforms/powernv/vas*
++
++IBM Power Virtual Ethernet Device Driver
++M: Cristobal Forno <cforno12@linux.ibm.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/ibm/ibmveth.*
++
++IBM Power Virtual FC Device Drivers
++M: Tyrel Datwyler <tyreld@linux.ibm.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/ibmvscsi/ibmvfc*
++
++IBM Power Virtual Management Channel Driver
++M: Brad Warrum <bwarrum@linux.ibm.com>
++M: Ritu Agarwal <rituagar@linux.ibm.com>
++S: Supported
++F: drivers/misc/ibmvmc.*
++
++IBM Power Virtual SCSI Device Drivers
++M: Tyrel Datwyler <tyreld@linux.ibm.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/ibmvscsi/ibmvscsi*
++F: include/scsi/viosrp.h
++
++IBM Power Virtual SCSI Device Target Driver
++M: Michael Cyr <mikecyr@linux.ibm.com>
++L: linux-scsi@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++F: drivers/scsi/ibmvscsi_tgt/
++
++IBM Power VMX Cryptographic instructions
++M: Breno Leitão <leitao@debian.org>
++M: Nayna Jain <nayna@linux.ibm.com>
++M: Paulo Flabiano Smorigo <pfsmorigo@gmail.com>
++L: linux-crypto@vger.kernel.org
++S: Supported
++F: drivers/crypto/vmx/Kconfig
++F: drivers/crypto/vmx/Makefile
++F: drivers/crypto/vmx/aes*
++F: drivers/crypto/vmx/ghash*
++F: drivers/crypto/vmx/ppc-xlate.pl
++F: drivers/crypto/vmx/vmx.c
++
++IBM ServeRAID RAID DRIVER
++S: Orphan
++F: drivers/scsi/ips.*
++
++ICH LPC AND GPIO DRIVER
++M: Peter Tyser <ptyser@xes-inc.com>
++S: Maintained
++F: drivers/gpio/gpio-ich.c
++F: drivers/mfd/lpc_ich.c
++
++ICY I2C DRIVER
++M: Max Staudt <max@enpas.org>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-icy.c
++
++IDEAPAD LAPTOP EXTRAS DRIVER
++M: Ike Panhc <ike.pan@canonical.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://launchpad.net/ideapad-laptop
++F: drivers/platform/x86/ideapad-laptop.c
++
++IDEAPAD LAPTOP SLIDEBAR DRIVER
++M: Andrey Moiseev <o2g.org.ru@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++W: https://github.com/o2genum/ideapad-slidebar
++F: drivers/input/misc/ideapad_slidebar.c
++
++IDT VersaClock 5 CLOCK DRIVER
++M: Luca Ceresoli <luca@lucaceresoli.net>
++S: Maintained
++F: Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
++F: drivers/clk/clk-versaclock5.c
++
++IEEE 802.15.4 SUBSYSTEM
++M: Alexander Aring <alex.aring@gmail.com>
++M: Stefan Schmidt <stefan@datenfreihafen.org>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++W: https://linux-wpan.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan-next.git
++F: Documentation/networking/ieee802154.rst
++F: drivers/net/ieee802154/
++F: include/linux/ieee802154.h
++F: include/linux/nl802154.h
++F: include/net/af_ieee802154.h
++F: include/net/cfg802154.h
++F: include/net/ieee802154_netdev.h
++F: include/net/mac802154.h
++F: include/net/nl802154.h
++F: net/ieee802154/
++F: net/mac802154/
++
++IFE PROTOCOL
++M: Yotam Gigi <yotam.gi@gmail.com>
++M: Jamal Hadi Salim <jhs@mojatatu.com>
++F: include/net/ife.h
++F: include/uapi/linux/ife.h
++F: net/ife
++
++IGORPLUG-USB IR RECEIVER
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/igorplugusb.c
++
++IGUANAWORKS USB IR TRANSCEIVER
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/iguanair.c
++
++IIO DIGITAL POTENTIOMETER DAC
++M: Peter Rosin <peda@axentia.se>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-iio-dac-dpot-dac
++F: Documentation/devicetree/bindings/iio/dac/dpot-dac.yaml
++F: drivers/iio/dac/dpot-dac.c
++
++IIO ENVELOPE DETECTOR
++M: Peter Rosin <peda@axentia.se>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
++F: Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml
++F: drivers/iio/adc/envelope-detector.c
++
++IIO MULTIPLEXER
++M: Peter Rosin <peda@axentia.se>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.yaml
++F: drivers/iio/multiplexer/iio-mux.c
++
++IIO SCMI BASED DRIVER
++M: Jyoti Bhayana <jbhayana@google.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/iio/common/scmi_sensors/scmi_iio.c
++
++IIO SUBSYSTEM AND DRIVERS
++M: Jonathan Cameron <jic23@kernel.org>
++R: Lars-Peter Clausen <lars@metafoo.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
++F: Documentation/ABI/testing/configfs-iio*
++F: Documentation/ABI/testing/sysfs-bus-iio*
++F: Documentation/devicetree/bindings/iio/
++F: drivers/iio/
++F: drivers/staging/iio/
++F: include/linux/iio/
++F: tools/iio/
++
++IIO UNIT CONVERTER
++M: Peter Rosin <peda@axentia.se>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.yaml
++F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.yaml
++F: Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml
++F: drivers/iio/afe/iio-rescale.c
++
++IKANOS/ADI EAGLE ADSL USB DRIVER
++M: Matthieu Castet <castet.matthieu@free.fr>
++M: Stanislaw Gruszka <stf_xl@wp.pl>
++S: Maintained
++F: drivers/usb/atm/ueagle-atm.c
++
++IMGTEC ASCII LCD DRIVER
++M: Paul Burton <paulburton@kernel.org>
++S: Maintained
++F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml
++F: drivers/auxdisplay/img-ascii-lcd.c
++
++IMGTEC IR DECODER DRIVER
++S: Orphan
++F: drivers/media/rc/img-ir/
++
++IMON SOUNDGRAPH USB IR RECEIVER
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/imon.c
++F: drivers/media/rc/imon_raw.c
++
++IMS TWINTURBO FRAMEBUFFER DRIVER
++L: linux-fbdev@vger.kernel.org
++S: Orphan
++F: drivers/video/fbdev/imsttfb.c
++
++INA209 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
++F: Documentation/hwmon/ina209.rst
++F: drivers/hwmon/ina209.c
++
++INA2XX HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/ina2xx.rst
++F: drivers/hwmon/ina2xx.c
++F: include/linux/platform_data/ina2xx.h
++
++INDUSTRY PACK SUBSYSTEM (IPACK)
++M: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
++M: Jens Taprogge <jens.taprogge@taprogge.org>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: industrypack-devel@lists.sourceforge.net
++S: Maintained
++W: http://industrypack.sourceforge.net
++F: drivers/ipack/
++
++INFINEON DPS310 Driver
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/iio/pressure/dps310.c
++
++INFINIBAND SUBSYSTEM
++M: Doug Ledford <dledford@redhat.com>
++M: Jason Gunthorpe <jgg@nvidia.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: https://github.com/linux-rdma/rdma-core
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git
++F: Documentation/devicetree/bindings/infiniband/
++F: Documentation/infiniband/
++F: drivers/infiniband/
++F: include/rdma/
++F: include/trace/events/ib_mad.h
++F: include/trace/events/ib_umad.h
++F: include/uapi/linux/if_infiniband.h
++F: include/uapi/rdma/
++F: samples/bpf/ibumad_kern.c
++F: samples/bpf/ibumad_user.c
++
++INGENIC JZ4780 NAND DRIVER
++M: Harvey Hunt <harveyhuntnexus@gmail.com>
++L: linux-mtd@lists.infradead.org
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: drivers/mtd/nand/raw/ingenic/
++
++INGENIC JZ47xx SoCs
++M: Paul Cercueil <paul@crapouillou.net>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/boot/dts/ingenic/
++F: arch/mips/generic/board-ingenic.c
++F: arch/mips/include/asm/mach-ingenic/
++F: arch/mips/ingenic/Kconfig
++F: drivers/clk/ingenic/
++F: drivers/dma/dma-jz4780.c
++F: drivers/gpu/drm/ingenic/
++F: drivers/i2c/busses/i2c-jz4780.c
++F: drivers/iio/adc/ingenic-adc.c
++F: drivers/irqchip/irq-ingenic.c
++F: drivers/memory/jz4780-nemc.c
++F: drivers/mmc/host/jz4740_mmc.c
++F: drivers/mtd/nand/raw/ingenic/
++F: drivers/pinctrl/pinctrl-ingenic.c
++F: drivers/power/supply/ingenic-battery.c
++F: drivers/pwm/pwm-jz4740.c
++F: drivers/remoteproc/ingenic_rproc.c
++F: drivers/rtc/rtc-jz4740.c
++F: drivers/tty/serial/8250/8250_ingenic.c
++F: drivers/usb/musb/jz4740.c
++F: drivers/watchdog/jz4740_wdt.c
++F: include/dt-bindings/iio/adc/ingenic,adc.h
++F: include/linux/mfd/ingenic-tcu.h
++F: sound/soc/codecs/jz47*
++F: sound/soc/jz4740/
++
++INOTIFY
++M: Jan Kara <jack@suse.cz>
++R: Amir Goldstein <amir73il@gmail.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: Documentation/filesystems/inotify.rst
++F: fs/notify/inotify/
++F: include/linux/inotify.h
++F: include/uapi/linux/inotify.h
++
++INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
++M: Dmitry Torokhov <dmitry.torokhov@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-input/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
++F: Documentation/devicetree/bindings/input/
++F: Documentation/devicetree/bindings/serio/
++F: Documentation/input/
++F: drivers/input/
++F: include/linux/input.h
++F: include/linux/input/
++F: include/uapi/linux/input-event-codes.h
++F: include/uapi/linux/input.h
++
++INPUT MULTITOUCH (MT) PROTOCOL
++M: Henrik Rydberg <rydberg@bitmath.org>
++L: linux-input@vger.kernel.org
++S: Odd fixes
++F: Documentation/input/multi-touch-protocol.rst
++F: drivers/input/input-mt.c
++K: \b(ABS|SYN)_MT_
++
++INSIDE SECURE CRYPTO DRIVER
++M: Antoine Tenart <atenart@kernel.org>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/inside-secure/
++
++INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
++M: Mimi Zohar <zohar@linux.ibm.com>
++M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
++L: linux-integrity@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
++F: security/integrity/ima/
++
++INTEL 810/815 FRAMEBUFFER DRIVER
++M: Antonino Daplas <adaplas@gmail.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/i810/
++
++INTEL ASoC DRIVERS
++M: Cezary Rojewski <cezary.rojewski@intel.com>
++M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
++M: Liam Girdwood <liam.r.girdwood@linux.intel.com>
++M: Jie Yang <yang.jie@linux.intel.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++F: sound/soc/intel/
++
++INTEL ATOMISP2 DUMMY / POWER-MANAGEMENT DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/atomisp2/pm.c
++
++INTEL ATOMISP2 LED DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/atomisp2/led.c
++
++INTEL BIOS SAR INT1092 DRIVER
++M: Shravan Sudhakar <s.shravan@intel.com>
++M: Intel Corporation <linuxwwan@intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/int1092/
++
++INTEL BROXTON PMC DRIVER
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++M: Zha Qipeng <qipeng.zha@intel.com>
++S: Maintained
++F: drivers/mfd/intel_pmc_bxt.c
++F: include/linux/mfd/intel_pmc_bxt.h
++
++INTEL C600 SERIES SAS CONTROLLER DRIVER
++M: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++T: git git://git.code.sf.net/p/intel-sas/isci
++F: drivers/scsi/isci/
++
++INTEL CPU family model numbers
++M: Tony Luck <tony.luck@intel.com>
++M: x86@kernel.org
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: arch/x86/include/asm/intel-family.h
++
++INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
++M: Jani Nikula <jani.nikula@linux.intel.com>
++M: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
++M: Rodrigo Vivi <rodrigo.vivi@intel.com>
++L: intel-gfx@lists.freedesktop.org
++S: Supported
++W: https://01.org/linuxgraphics/
++Q: http://patchwork.freedesktop.org/project/intel-gfx/
++B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
++C: irc://irc.oftc.net/intel-gfx
++T: git git://anongit.freedesktop.org/drm-intel
++F: Documentation/gpu/i915.rst
++F: drivers/gpu/drm/i915/
++F: include/drm/i915*
++F: include/uapi/drm/i915_drm.h
++
++INTEL ETHERNET DRIVERS
++M: Jesse Brandeburg <jesse.brandeburg@intel.com>
++M: Tony Nguyen <anthony.l.nguyen@intel.com>
++L: intel-wired-lan@lists.osuosl.org (moderated for non-subscribers)
++S: Supported
++W: http://www.intel.com/support/feedback.htm
++W: http://e1000.sourceforge.net/
++Q: http://patchwork.ozlabs.org/project/intel-wired-lan/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git
++F: Documentation/networking/device_drivers/ethernet/intel/
++F: drivers/net/ethernet/intel/
++F: drivers/net/ethernet/intel/*/
++F: include/linux/avf/virtchnl.h
++F: include/linux/net/intel/iidc.h
++
++INTEL ETHERNET PROTOCOL DRIVER FOR RDMA
++M: Mustafa Ismail <mustafa.ismail@intel.com>
++M: Shiraz Saleem <shiraz.saleem@intel.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/hw/irdma/
++F: include/uapi/rdma/irdma-abi.h
++
++INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
++M: Maik Broemme <mbroemme@libmpq.org>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: Documentation/fb/intelfb.rst
++F: drivers/video/fbdev/intelfb/
++
++INTEL GPIO DRIVERS
++M: Andy Shevchenko <andy@kernel.org>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
++F: drivers/gpio/gpio-ich.c
++F: drivers/gpio/gpio-merrifield.c
++F: drivers/gpio/gpio-ml-ioh.c
++F: drivers/gpio/gpio-pch.c
++F: drivers/gpio/gpio-sch.c
++F: drivers/gpio/gpio-sodaville.c
++
++INTEL GVT-g DRIVERS (Intel GPU Virtualization)
++M: Zhenyu Wang <zhenyuw@linux.intel.com>
++M: Zhi Wang <zhi.a.wang@intel.com>
++L: intel-gvt-dev@lists.freedesktop.org
++L: intel-gfx@lists.freedesktop.org
++S: Supported
++W: https://01.org/igvt-g
++T: git https://github.com/intel/gvt-linux.git
++F: drivers/gpu/drm/i915/gvt/
++
++INTEL HID EVENT DRIVER
++M: Alex Hung <alex.hung@canonical.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/hid.c
++
++INTEL I/OAT DMA DRIVER
++M: Dave Jiang <dave.jiang@intel.com>
++R: Dan Williams <dan.j.williams@intel.com>
++L: dmaengine@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-dmaengine/list/
++F: drivers/dma/ioat*
++
++INTEL IADX DRIVER
++M: Dave Jiang <dave.jiang@intel.com>
++L: dmaengine@vger.kernel.org
++S: Supported
++F: drivers/dma/idxd/*
++F: include/uapi/linux/idxd.h
++
++INTEL IDLE DRIVER
++M: Jacob Pan <jacob.jun.pan@linux.intel.com>
++M: Len Brown <lenb@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
++F: drivers/idle/intel_idle.c
++
++INTEL INTEGRATED SENSOR HUB DRIVER
++M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
++M: Jiri Kosina <jikos@kernel.org>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/intel-ish-hid/
++
++INTEL IOMMU (VT-d)
++M: David Woodhouse <dwmw2@infradead.org>
++M: Lu Baolu <baolu.lu@linux.intel.com>
++L: iommu@lists.linux-foundation.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
++F: drivers/iommu/intel/
++F: include/linux/intel-iommu.h
++F: include/linux/intel-svm.h
++
++INTEL IOP-ADMA DMA DRIVER
++R: Dan Williams <dan.j.williams@intel.com>
++S: Odd fixes
++F: drivers/dma/iop-adma.c
++
++INTEL IPU3 CSI-2 CIO2 DRIVER
++M: Yong Zhi <yong.zhi@intel.com>
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++M: Bingbu Cao <bingbu.cao@intel.com>
++M: Dan Scally <djrscally@gmail.com>
++R: Tianshu Qiu <tian.shu.qiu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/userspace-api/media/v4l/pixfmt-srggb10-ipu3.rst
++F: drivers/media/pci/intel/ipu3/
++
++INTEL IPU3 CSI-2 IMGU DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++R: Bingbu Cao <bingbu.cao@intel.com>
++R: Tianshu Qiu <tian.shu.qiu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/media/ipu3.rst
++F: Documentation/admin-guide/media/ipu3_rcb.svg
++F: Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst
++F: drivers/staging/media/ipu3/
++
++INTEL IXP4XX CRYPTO SUPPORT
++M: Corentin Labbe <clabbe@baylibre.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/ixp4xx_crypto.c
++
++INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
++M: Krzysztof Halasa <khalasa@piap.pl>
++S: Maintained
++F: drivers/net/ethernet/xscale/ixp4xx_eth.c
++F: drivers/net/wan/ixp4xx_hss.c
++F: drivers/soc/ixp4xx/ixp4xx-npe.c
++F: drivers/soc/ixp4xx/ixp4xx-qmgr.c
++F: include/linux/soc/ixp4xx/npe.h
++F: include/linux/soc/ixp4xx/qmgr.h
++
++INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
++M: Deepak Saxena <dsaxena@plexity.net>
++S: Maintained
++F: Documentation/devicetree/bindings/display/intel,ixp46x-rng.yaml
++F: drivers/char/hw_random/ixp4xx-rng.c
++
++INTEL KEEM BAY DRM DRIVER
++M: Anitha Chrisanthus <anitha.chrisanthus@intel.com>
++M: Edmund Dea <edmund.j.dea@intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/intel,kmb_display.yaml
++F: drivers/gpu/drm/kmb/
++
++INTEL KEEM BAY OCS AES/SM4 CRYPTO DRIVER
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/crypto/intel,keembay-ocs-aes.yaml
++F: drivers/crypto/keembay/Kconfig
++F: drivers/crypto/keembay/Makefile
++F: drivers/crypto/keembay/keembay-ocs-aes-core.c
++F: drivers/crypto/keembay/ocs-aes.c
++F: drivers/crypto/keembay/ocs-aes.h
++
++INTEL KEEM BAY OCS HCU CRYPTO DRIVER
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++M: Declan Murphy <declan.murphy@intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/crypto/intel,keembay-ocs-hcu.yaml
++F: drivers/crypto/keembay/Kconfig
++F: drivers/crypto/keembay/Makefile
++F: drivers/crypto/keembay/keembay-ocs-hcu-core.c
++F: drivers/crypto/keembay/ocs-hcu.c
++F: drivers/crypto/keembay/ocs-hcu.h
++
++INTEL MANAGEMENT ENGINE (mei)
++M: Tomas Winkler <tomas.winkler@intel.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/driver-api/mei/*
++F: drivers/misc/mei/
++F: drivers/watchdog/mei_wdt.c
++F: include/linux/mei_cl_bus.h
++F: include/uapi/linux/mei.h
++F: samples/mei/*
++
++INTEL MAX 10 BMC MFD DRIVER
++M: Xu Yilun <yilun.xu@intel.com>
++R: Tom Rix <trix@redhat.com>
++S: Maintained
++F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
++F: Documentation/hwmon/intel-m10-bmc-hwmon.rst
++F: drivers/hwmon/intel-m10-bmc-hwmon.c
++F: drivers/mfd/intel-m10-bmc.c
++F: include/linux/mfd/intel-m10-bmc.h
++
++INTEL MENLOW THERMAL DRIVER
++M: Sujith Thomas <sujith.thomas@intel.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++W: https://01.org/linux-acpi
++F: drivers/thermal/intel/intel_menlow.c
++
++INTEL P-Unit IPC DRIVER
++M: Zha Qipeng <qipeng.zha@intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: arch/x86/include/asm/intel_punit_ipc.h
++F: drivers/platform/x86/intel/punit_ipc.c
++
++INTEL PMC CORE DRIVER
++M: Rajneesh Bhardwaj <irenic.rajneesh@gmail.com>
++M: David E Box <david.e.box@intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-platform-intel-pmc
++F: drivers/platform/x86/intel/pmc/
++
++INTEL PMIC GPIO DRIVERS
++M: Andy Shevchenko <andy@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
++F: drivers/gpio/gpio-*cove.c
++
++INTEL PMIC MULTIFUNCTION DEVICE DRIVERS
++M: Andy Shevchenko <andy@kernel.org>
++S: Maintained
++F: drivers/mfd/intel_soc_pmic*
++F: include/linux/mfd/intel_soc_pmic*
++
++INTEL PMT DRIVER
++M: "David E. Box" <david.e.box@linux.intel.com>
++S: Maintained
++F: drivers/mfd/intel_pmt.c
++F: drivers/platform/x86/intel/pmt/
++
++INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
++M: Stanislav Yakovlev <stas.yakovlev@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
++F: Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
++F: drivers/net/wireless/intel/ipw2x00/
++
++INTEL PSTATE DRIVER
++M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
++M: Len Brown <lenb@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++F: drivers/cpufreq/intel_pstate.c
++
++INTEL QUADRATURE ENCODER PERIPHERAL DRIVER
++M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
++L: linux-iio@vger.kernel.org
++F: drivers/counter/intel-qep.c
++
++INTEL SCU DRIVERS
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++S: Maintained
++F: arch/x86/include/asm/intel_scu_ipc.h
++F: drivers/platform/x86/intel_scu_*
++
++INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
++M: Daniel Scally <djrscally@gmail.com>
++S: Maintained
++F: drivers/platform/x86/intel/int3472/
++
++INTEL SPEED SELECT TECHNOLOGY
++M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/speed_select_if/
++F: include/uapi/linux/isst_if.h
++F: tools/power/x86/intel-speed-select/
++
++INTEL STRATIX10 FIRMWARE DRIVERS
++M: Dinh Nguyen <dinguyen@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu
++F: Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt
++F: drivers/firmware/stratix10-rsu.c
++F: drivers/firmware/stratix10-svc.c
++F: include/linux/firmware/intel/stratix10-smc.h
++F: include/linux/firmware/intel/stratix10-svc-client.h
++
++INTEL TELEMETRY DRIVER
++M: Rajneesh Bhardwaj <irenic.rajneesh@gmail.com>
++M: "David E. Box" <david.e.box@linux.intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: arch/x86/include/asm/intel_telemetry.h
++F: drivers/platform/x86/intel/telemetry/
++
++INTEL UNCORE FREQUENCY CONTROL
++M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/uncore-frequency.c
++
++INTEL VIRTUAL BUTTON DRIVER
++M: AceLan Kao <acelan.kao@canonical.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/intel/vbtn.c
++
++INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
++M: Stanislaw Gruszka <stf_xl@wp.pl>
++L: linux-wireless@vger.kernel.org
++S: Supported
++F: drivers/net/wireless/intel/iwlegacy/
++
++INTEL WIRELESS WIFI LINK (iwlwifi)
++M: Luca Coelho <luciano.coelho@intel.com>
++L: linux-wireless@vger.kernel.org
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
++F: drivers/net/wireless/intel/iwlwifi/
++
++INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
++M: Jithu Joseph <jithu.joseph@intel.com>
++R: Maurice Ma <maurice.ma@intel.com>
++S: Maintained
++W: https://slimbootloader.github.io/security/firmware-update.html
++F: drivers/platform/x86/intel/wmi/sbl-fw-update.c
++
++INTEL WMI THUNDERBOLT FORCE POWER DRIVER
++L: Dell.Client.Kernel@dell.com
++S: Maintained
++F: drivers/platform/x86/intel/wmi/thunderbolt.c
++
++INTEL WWAN IOSM DRIVER
++M: M Chetan Kumar <m.chetan.kumar@intel.com>
++M: Intel Corporation <linuxwwan@intel.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/wwan/iosm/
++
++INTEL(R) TRACE HUB
++M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
++S: Supported
++F: Documentation/trace/intel_th.rst
++F: drivers/hwtracing/intel_th/
++F: include/linux/intel_th.h
++
++INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
++M: Ning Sun <ning.sun@intel.com>
++L: tboot-devel@lists.sourceforge.net
++S: Supported
++W: http://tboot.sourceforge.net
++T: hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
++F: Documentation/x86/intel_txt.rst
++F: arch/x86/kernel/tboot.c
++F: include/linux/tboot.h
++
++INTEL SGX
++M: Jarkko Sakkinen <jarkko@kernel.org>
++R: Dave Hansen <dave.hansen@linux.intel.com>
++L: linux-sgx@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/intel-sgx/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx
++F: Documentation/x86/sgx.rst
++F: arch/x86/entry/vdso/vsgx.S
++F: arch/x86/include/asm/sgx.h
++F: arch/x86/include/uapi/asm/sgx.h
++F: arch/x86/kernel/cpu/sgx/*
++F: tools/testing/selftests/sgx/*
++K: \bSGX_
++
++INTERCONNECT API
++M: Georgi Djakov <djakov@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git
++F: Documentation/devicetree/bindings/interconnect/
++F: Documentation/driver-api/interconnect.rst
++F: drivers/interconnect/
++F: include/dt-bindings/interconnect/
++F: include/linux/interconnect-provider.h
++F: include/linux/interconnect.h
++
++INTERRUPT COUNTER DRIVER
++M: Oleksij Rempel <o.rempel@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++L: linux-iio@vger.kernel.org
++F: Documentation/devicetree/bindings/counter/interrupt-counter.yaml
++F: drivers/counter/interrupt-cnt.c
++
++INVENSENSE ICM-426xx IMU DRIVER
++M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++W: https://invensense.tdk.com/
++F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
++F: drivers/iio/imu/inv_icm42600/
++
++INVENSENSE MPU-3050 GYROSCOPE DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.yaml
++F: drivers/iio/gyro/mpu3050*
++
++IOC3 ETHERNET DRIVER
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/sgi/ioc3-eth.c
++
++IOMAP FILESYSTEM LIBRARY
++M: Christoph Hellwig <hch@infradead.org>
++M: Darrick J. Wong <djwong@kernel.org>
++M: linux-xfs@vger.kernel.org
++M: linux-fsdevel@vger.kernel.org
++L: linux-xfs@vger.kernel.org
++L: linux-fsdevel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
++F: fs/iomap/
++F: include/linux/iomap.h
++
++IOMMU DRIVERS
++M: Joerg Roedel <joro@8bytes.org>
++M: Will Deacon <will@kernel.org>
++L: iommu@lists.linux-foundation.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
++F: Documentation/devicetree/bindings/iommu/
++F: Documentation/userspace-api/iommu.rst
++F: drivers/iommu/
++F: include/linux/iommu.h
++F: include/linux/iova.h
++F: include/linux/of_iommu.h
++F: include/uapi/linux/iommu.h
++
++IO_URING
++M: Jens Axboe <axboe@kernel.dk>
++R: Pavel Begunkov <asml.silence@gmail.com>
++L: io-uring@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.dk/linux-block
++T: git git://git.kernel.dk/liburing
++F: fs/io-wq.c
++F: fs/io-wq.h
++F: fs/io_uring.c
++F: include/linux/io_uring.h
++F: include/uapi/linux/io_uring.h
++F: tools/io_uring/
++
++IPMI SUBSYSTEM
++M: Corey Minyard <minyard@acm.org>
++L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
++S: Supported
++W: http://openipmi.sourceforge.net/
++F: Documentation/driver-api/ipmi.rst
++F: Documentation/devicetree/bindings/ipmi/
++F: drivers/char/ipmi/
++F: include/linux/ipmi*
++F: include/uapi/linux/ipmi*
++
++IPS SCSI RAID DRIVER
++M: Adaptec OEM Raid Solutions <aacraid@microsemi.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++W: http://www.adaptec.com/
++F: drivers/scsi/ips*
++
++IPVS
++M: Simon Horman <horms@verge.net.au>
++M: Julian Anastasov <ja@ssi.bg>
++L: netdev@vger.kernel.org
++L: lvs-devel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git
++F: Documentation/networking/ipvs-sysctl.rst
++F: include/net/ip_vs.h
++F: include/uapi/linux/ip_vs.h
++F: net/netfilter/ipvs/
++
++IPWIRELESS DRIVER
++M: Jiri Kosina <jikos@kernel.org>
++M: David Sterba <dsterba@suse.com>
++S: Odd Fixes
++F: drivers/tty/ipwireless/
++
++IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
++M: Marc Zyngier <maz@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
++F: Documentation/core-api/irq/irq-domain.rst
++F: include/linux/irqdomain.h
++F: kernel/irq/irqdomain.c
++F: kernel/irq/msi.c
++
++IRQ SUBSYSTEM
++M: Thomas Gleixner <tglx@linutronix.de>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
++F: kernel/irq/
++
++IRQCHIP DRIVERS
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Marc Zyngier <maz@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
++F: Documentation/devicetree/bindings/interrupt-controller/
++F: drivers/irqchip/
++
++ISA
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++S: Maintained
++F: Documentation/driver-api/isa.rst
++F: drivers/base/isa.c
++F: include/linux/isa.h
++
++ISA RADIO MODULE
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-isa*
++
++ISAPNP
++M: Jaroslav Kysela <perex@perex.cz>
++S: Maintained
++F: Documentation/driver-api/isapnp.rst
++F: drivers/pnp/isapnp/
++F: include/linux/isapnp.h
++
++ISCSI
++M: Lee Duncan <lduncan@suse.com>
++M: Chris Leech <cleech@redhat.com>
++L: open-iscsi@googlegroups.com
++L: linux-scsi@vger.kernel.org
++S: Maintained
++W: www.open-iscsi.com
++F: drivers/scsi/*iscsi*
++F: include/scsi/*iscsi*
++
++iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
++M: Peter Jones <pjones@redhat.com>
++M: Konrad Rzeszutek Wilk <konrad@kernel.org>
++S: Maintained
++F: drivers/firmware/iscsi_ibft*
++
++ISCSI EXTENSIONS FOR RDMA (ISER) INITIATOR
++M: Sagi Grimberg <sagi@grimberg.me>
++M: Max Gurtovoy <mgurtovoy@nvidia.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.openfabrics.org
++W: www.open-iscsi.org
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/ulp/iser/
++
++ISCSI EXTENSIONS FOR RDMA (ISER) TARGET
++M: Sagi Grimberg <sagi@grimberg.me>
++L: linux-rdma@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++W: http://www.linux-iscsi.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
++F: drivers/infiniband/ulp/isert
++
++ISDN/CMTP OVER BLUETOOTH
++M: Karsten Keil <isdn@linux-pingi.de>
++L: isdn4linux@listserv.isdn4linux.de (subscribers-only)
++L: netdev@vger.kernel.org
++S: Odd Fixes
++W: http://www.isdn4linux.de
++F: Documentation/isdn/
++F: drivers/isdn/capi/
++F: include/linux/isdn/
++F: include/uapi/linux/isdn/
++F: net/bluetooth/cmtp/
++
++ISDN/mISDN SUBSYSTEM
++M: Karsten Keil <isdn@linux-pingi.de>
++L: isdn4linux@listserv.isdn4linux.de (subscribers-only)
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.isdn4linux.de
++F: drivers/isdn/Kconfig
++F: drivers/isdn/Makefile
++F: drivers/isdn/hardware/
++F: drivers/isdn/mISDN/
++
++IT87 HARDWARE MONITORING DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/it87.rst
++F: drivers/hwmon/it87.c
++
++IT913X MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/it913x*
++
++ITE IT66121 HDMI BRIDGE DRIVER
++M: Phong LE <ple@baylibre.com>
++M: Neil Armstrong <narmstrong@baylibre.com>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml
++F: drivers/gpu/drm/bridge/ite-it66121.c
++
++IVTV VIDEO4LINUX DRIVER
++M: Andy Walls <awalls@md.metrocast.net>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/ivtv*
++F: drivers/media/pci/ivtv/
++F: include/uapi/linux/ivtv*
++
++IX2505V MEDIA DRIVER
++M: Malcolm Priestley <tvboxspy@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/ix2505v*
++
++JAILHOUSE HYPERVISOR INTERFACE
++M: Jan Kiszka <jan.kiszka@siemens.com>
++L: jailhouse-dev@googlegroups.com
++S: Maintained
++F: arch/x86/include/asm/jailhouse_para.h
++F: arch/x86/kernel/jailhouse.c
++
++JC42.4 TEMPERATURE SENSOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/jc42.rst
++F: drivers/hwmon/jc42.c
++
++JFS FILESYSTEM
++M: Dave Kleikamp <shaggy@kernel.org>
++L: jfs-discussion@lists.sourceforge.net
++S: Maintained
++W: http://jfs.sourceforge.net/
++T: git git://github.com/kleikamp/linux-shaggy.git
++F: Documentation/admin-guide/jfs.rst
++F: fs/jfs/
++
++JME NETWORK DRIVER
++M: Guo-Fu Tseng <cooldavid@cooldavid.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/jme.*
++
++JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
++M: David Woodhouse <dwmw2@infradead.org>
++M: Richard Weinberger <richard@nod.at>
++L: linux-mtd@lists.infradead.org
++S: Odd Fixes
++W: http://www.linux-mtd.infradead.org/doc/jffs2.html
++T: git git://git.infradead.org/ubifs-2.6.git
++F: fs/jffs2/
++F: include/uapi/linux/jffs2.h
++
++JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
++M: "Theodore Ts'o" <tytso@mit.edu>
++M: Jan Kara <jack@suse.com>
++L: linux-ext4@vger.kernel.org
++S: Maintained
++F: fs/jbd2/
++F: include/linux/jbd2.h
++
++JPU V4L2 MEM2MEM DRIVER FOR RENESAS
++M: Mikhail Ulyanov <mikhail.ulyanov@cogentembedded.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/rcar_jpu.c
++
++JSM Neo PCI based serial card
++L: linux-serial@vger.kernel.org
++S: Orphan
++F: drivers/tty/serial/jsm/
++
++K10TEMP HARDWARE MONITORING DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/k10temp.rst
++F: drivers/hwmon/k10temp.c
++
++K8TEMP HARDWARE MONITORING DRIVER
++M: Rudolf Marek <r.marek@assembler.cz>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/k8temp.rst
++F: drivers/hwmon/k8temp.c
++
++KASAN
++M: Andrey Ryabinin <ryabinin.a.a@gmail.com>
++R: Alexander Potapenko <glider@google.com>
++R: Andrey Konovalov <andreyknvl@gmail.com>
++R: Dmitry Vyukov <dvyukov@google.com>
++L: kasan-dev@googlegroups.com
++S: Maintained
++F: Documentation/dev-tools/kasan.rst
++F: arch/*/include/asm/*kasan.h
++F: arch/*/mm/kasan_init*
++F: include/linux/kasan*.h
++F: lib/Kconfig.kasan
++F: lib/test_kasan*.c
++F: mm/kasan/
++F: scripts/Makefile.kasan
++
++KCONFIG
++M: Masahiro Yamada <masahiroy@kernel.org>
++L: linux-kbuild@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
++F: Documentation/kbuild/kconfig*
++F: scripts/Kconfig.include
++F: scripts/kconfig/
++
++KCOV
++R: Dmitry Vyukov <dvyukov@google.com>
++R: Andrey Konovalov <andreyknvl@gmail.com>
++L: kasan-dev@googlegroups.com
++S: Maintained
++F: Documentation/dev-tools/kcov.rst
++F: include/linux/kcov.h
++F: include/uapi/linux/kcov.h
++F: kernel/kcov.c
++F: scripts/Makefile.kcov
++
++KCSAN
++M: Marco Elver <elver@google.com>
++R: Dmitry Vyukov <dvyukov@google.com>
++L: kasan-dev@googlegroups.com
++S: Maintained
++F: Documentation/dev-tools/kcsan.rst
++F: include/linux/kcsan*.h
++F: kernel/kcsan/
++F: lib/Kconfig.kcsan
++F: scripts/Makefile.kcsan
++
++KDUMP
++M: Dave Young <dyoung@redhat.com>
++M: Baoquan He <bhe@redhat.com>
++R: Vivek Goyal <vgoyal@redhat.com>
++L: kexec@lists.infradead.org
++S: Maintained
++W: http://lse.sourceforge.net/kdump/
++F: Documentation/admin-guide/kdump/
++F: fs/proc/vmcore.c
++F: include/linux/crash_core.h
++F: include/linux/crash_dump.h
++F: include/uapi/linux/vmcore.h
++F: kernel/crash_*.c
++
++KEENE FM RADIO TRANSMITTER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-keene*
++
++KERNEL AUTOMOUNTER
++M: Ian Kent <raven@themaw.net>
++L: autofs@vger.kernel.org
++S: Maintained
++F: fs/autofs/
++
++KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
++M: Masahiro Yamada <masahiroy@kernel.org>
++M: Michal Marek <michal.lkml@markovi.net>
++R: Nick Desaulniers <ndesaulniers@google.com>
++L: linux-kbuild@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
++F: Documentation/kbuild/
++F: Makefile
++F: scripts/*vmlinux*
++F: scripts/Kbuild*
++F: scripts/Makefile*
++F: scripts/basic/
++F: scripts/dummy-tools/
++F: scripts/mk*
++F: scripts/mod/
++F: scripts/package/
++
++KERNEL JANITORS
++L: kernel-janitors@vger.kernel.org
++S: Odd Fixes
++W: http://kernelnewbies.org/KernelJanitors
++
++KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
++M: "J. Bruce Fields" <bfields@fieldses.org>
++M: Chuck Lever <chuck.lever@oracle.com>
++L: linux-nfs@vger.kernel.org
++S: Supported
++W: http://nfs.sourceforge.net/
++T: git git://linux-nfs.org/~bfields/linux.git
++F: fs/lockd/
++F: fs/nfs_common/
++F: fs/nfsd/
++F: include/linux/lockd/
++F: include/linux/sunrpc/
++F: include/uapi/linux/nfsd/
++F: include/uapi/linux/sunrpc/
++F: net/sunrpc/
++F: Documentation/filesystems/nfs/
++
++KERNEL REGRESSIONS
++M: Thorsten Leemhuis <linux@leemhuis.info>
++L: regressions@lists.linux.dev
++S: Supported
++
++KERNEL SELFTEST FRAMEWORK
++M: Shuah Khan <shuah@kernel.org>
++M: Shuah Khan <skhan@linuxfoundation.org>
++L: linux-kselftest@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/linux-kselftest/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git
++F: Documentation/dev-tools/kselftest*
++F: tools/testing/selftests/
++
++KERNEL SMB3 SERVER (KSMBD)
++M: Namjae Jeon <linkinjeon@kernel.org>
++M: Sergey Senozhatsky <senozhatsky@chromium.org>
++M: Steve French <sfrench@samba.org>
++M: Hyunchul Lee <hyc.lee@gmail.com>
++L: linux-cifs@vger.kernel.org
++S: Maintained
++T: git git://git.samba.org/ksmbd.git
++F: fs/ksmbd/
++F: fs/smbfs_common/
++
++KERNEL UNIT TESTING FRAMEWORK (KUnit)
++M: Brendan Higgins <brendanhiggins@google.com>
++L: linux-kselftest@vger.kernel.org
++L: kunit-dev@googlegroups.com
++S: Maintained
++W: https://google.github.io/kunit-docs/third_party/kernel/docs/
++F: Documentation/dev-tools/kunit/
++F: include/kunit/
++F: lib/kunit/
++F: tools/testing/kunit/
++
++KERNEL USERMODE HELPER
++M: Luis Chamberlain <mcgrof@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: include/linux/umh.h
++F: kernel/umh.c
++
++KERNEL VIRTUAL MACHINE (KVM)
++M: Paolo Bonzini <pbonzini@redhat.com>
++L: kvm@vger.kernel.org
++S: Supported
++W: http://www.linux-kvm.org
++T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
++F: Documentation/virt/kvm/
++F: include/asm-generic/kvm*
++F: include/kvm/iodev.h
++F: include/linux/kvm*
++F: include/trace/events/kvm.h
++F: include/uapi/asm-generic/kvm*
++F: include/uapi/linux/kvm*
++F: tools/kvm/
++F: tools/testing/selftests/kvm/
++F: virt/kvm/*
++
++KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
++M: Marc Zyngier <maz@kernel.org>
++R: James Morse <james.morse@arm.com>
++R: Alexandru Elisei <alexandru.elisei@arm.com>
++R: Suzuki K Poulose <suzuki.poulose@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: kvmarm@lists.cs.columbia.edu (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
++F: arch/arm64/include/asm/kvm*
++F: arch/arm64/include/uapi/asm/kvm*
++F: arch/arm64/kvm/
++F: include/kvm/arm_*
++F: tools/testing/selftests/kvm/*/aarch64/
++F: tools/testing/selftests/kvm/aarch64/
++
++KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
++M: Huacai Chen <chenhuacai@kernel.org>
++M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
++L: linux-mips@vger.kernel.org
++L: kvm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
++F: arch/mips/include/asm/kvm*
++F: arch/mips/include/uapi/asm/kvm*
++F: arch/mips/kvm/
++
++KERNEL VIRTUAL MACHINE FOR POWERPC (KVM/powerpc)
++M: Paul Mackerras <paulus@ozlabs.org>
++L: kvm-ppc@vger.kernel.org
++S: Supported
++W: http://www.linux-kvm.org/
++T: git git://github.com/agraf/linux-2.6.git
++F: arch/powerpc/include/asm/kvm*
++F: arch/powerpc/include/uapi/asm/kvm*
++F: arch/powerpc/kernel/kvm*
++F: arch/powerpc/kvm/
++
++KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
++M: Christian Borntraeger <borntraeger@de.ibm.com>
++M: Janosch Frank <frankja@linux.ibm.com>
++R: David Hildenbrand <david@redhat.com>
++R: Claudio Imbrenda <imbrenda@linux.ibm.com>
++L: kvm@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
++F: Documentation/virt/kvm/s390*
++F: arch/s390/include/asm/gmap.h
++F: arch/s390/include/asm/kvm*
++F: arch/s390/include/uapi/asm/kvm*
++F: arch/s390/kernel/uv.c
++F: arch/s390/kvm/
++F: arch/s390/mm/gmap.c
++F: tools/testing/selftests/kvm/*/s390x/
++F: tools/testing/selftests/kvm/s390x/
++
++KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
++M: Paolo Bonzini <pbonzini@redhat.com>
++R: Sean Christopherson <seanjc@google.com>
++R: Vitaly Kuznetsov <vkuznets@redhat.com>
++R: Wanpeng Li <wanpengli@tencent.com>
++R: Jim Mattson <jmattson@google.com>
++R: Joerg Roedel <joro@8bytes.org>
++L: kvm@vger.kernel.org
++S: Supported
++W: http://www.linux-kvm.org
++T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
++F: arch/x86/include/asm/kvm*
++F: arch/x86/include/asm/pvclock-abi.h
++F: arch/x86/include/asm/svm.h
++F: arch/x86/include/asm/vmx*.h
++F: arch/x86/include/uapi/asm/kvm*
++F: arch/x86/include/uapi/asm/svm.h
++F: arch/x86/include/uapi/asm/vmx.h
++F: arch/x86/kernel/kvm.c
++F: arch/x86/kernel/kvmclock.c
++F: arch/x86/kvm/
++F: arch/x86/kvm/*/
++
++KERNFS
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++M: Tejun Heo <tj@kernel.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
++F: fs/kernfs/
++F: include/linux/kernfs.h
++
++KEXEC
++M: Eric Biederman <ebiederm@xmission.com>
++L: kexec@lists.infradead.org
++S: Maintained
++W: http://kernel.org/pub/linux/utils/kernel/kexec/
++F: include/linux/kexec.h
++F: include/uapi/linux/kexec.h
++F: kernel/kexec*
++
++KEYS-ENCRYPTED
++M: Mimi Zohar <zohar@linux.ibm.com>
++L: linux-integrity@vger.kernel.org
++L: keyrings@vger.kernel.org
++S: Supported
++F: Documentation/security/keys/trusted-encrypted.rst
++F: include/keys/encrypted-type.h
++F: security/keys/encrypted-keys/
++
++KEYS-TRUSTED
++M: James Bottomley <jejb@linux.ibm.com>
++M: Jarkko Sakkinen <jarkko@kernel.org>
++M: Mimi Zohar <zohar@linux.ibm.com>
++L: linux-integrity@vger.kernel.org
++L: keyrings@vger.kernel.org
++S: Supported
++F: Documentation/security/keys/trusted-encrypted.rst
++F: include/keys/trusted-type.h
++F: include/keys/trusted_tpm.h
++F: security/keys/trusted-keys/
++
++KEYS-TRUSTED-TEE
++M: Sumit Garg <sumit.garg@linaro.org>
++L: linux-integrity@vger.kernel.org
++L: keyrings@vger.kernel.org
++S: Supported
++F: include/keys/trusted_tee.h
++F: security/keys/trusted-keys/trusted_tee.c
++
++KEYS/KEYRINGS
++M: David Howells <dhowells@redhat.com>
++M: Jarkko Sakkinen <jarkko@kernel.org>
++L: keyrings@vger.kernel.org
++S: Maintained
++F: Documentation/security/keys/core.rst
++F: include/keys/
++F: include/linux/key-type.h
++F: include/linux/key.h
++F: include/linux/keyctl.h
++F: include/uapi/linux/keyctl.h
++F: security/keys/
++
++KFENCE
++M: Alexander Potapenko <glider@google.com>
++M: Marco Elver <elver@google.com>
++R: Dmitry Vyukov <dvyukov@google.com>
++L: kasan-dev@googlegroups.com
++S: Maintained
++F: Documentation/dev-tools/kfence.rst
++F: arch/*/include/asm/kfence.h
++F: include/linux/kfence.h
++F: lib/Kconfig.kfence
++F: mm/kfence/
++
++KFIFO
++M: Stefani Seibold <stefani@seibold.net>
++S: Maintained
++F: include/linux/kfifo.h
++F: lib/kfifo.c
++F: samples/kfifo/
++
++KGDB / KDB /debug_core
++M: Jason Wessel <jason.wessel@windriver.com>
++M: Daniel Thompson <daniel.thompson@linaro.org>
++R: Douglas Anderson <dianders@chromium.org>
++L: kgdb-bugreport@lists.sourceforge.net
++S: Maintained
++W: http://kgdb.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git
++F: Documentation/dev-tools/kgdb.rst
++F: drivers/misc/kgdbts.c
++F: drivers/tty/serial/kgdboc.c
++F: include/linux/kdb.h
++F: include/linux/kgdb.h
++F: kernel/debug/
++
++KHADAS MCU MFD DRIVER
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: linux-amlogic@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
++F: drivers/mfd/khadas-mcu.c
++F: include/linux/mfd/khadas-mcu.h
++F: drivers/thermal/khadas_mcu_fan.c
++
++KMEMLEAK
++M: Catalin Marinas <catalin.marinas@arm.com>
++S: Maintained
++F: Documentation/dev-tools/kmemleak.rst
++F: include/linux/kmemleak.h
++F: mm/kmemleak.c
++F: samples/kmemleak/kmemleak-test.c
++
++KMOD KERNEL MODULE LOADER - USERMODE HELPER
++M: Luis Chamberlain <mcgrof@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: include/linux/kmod.h
++F: kernel/kmod.c
++F: lib/test_kmod.c
++F: tools/testing/selftests/kmod/
++
++KPROBES
++M: Naveen N. Rao <naveen.n.rao@linux.ibm.com>
++M: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
++M: "David S. Miller" <davem@davemloft.net>
++M: Masami Hiramatsu <mhiramat@kernel.org>
++S: Maintained
++F: Documentation/trace/kprobes.rst
++F: include/asm-generic/kprobes.h
++F: include/linux/kprobes.h
++F: kernel/kprobes.c
++
++KS0108 LCD CONTROLLER DRIVER
++M: Miguel Ojeda <ojeda@kernel.org>
++S: Maintained
++F: Documentation/admin-guide/auxdisplay/ks0108.rst
++F: drivers/auxdisplay/ks0108.c
++F: include/linux/ks0108.h
++
++KTD253 BACKLIGHT DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktd253.yaml
++F: drivers/video/backlight/ktd253-backlight.c
++
++KTEST
++M: Steven Rostedt <rostedt@goodmis.org>
++M: John Hawley <warthog9@eaglescrag.net>
++S: Maintained
++F: tools/testing/ktest
++
++L3MDEV
++M: David Ahern <dsahern@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/net/l3mdev.h
++F: net/l3mdev
++
++L7 BPF FRAMEWORK
++M: John Fastabend <john.fastabend@gmail.com>
++M: Daniel Borkmann <daniel@iogearbox.net>
++M: Jakub Sitnicki <jakub@cloudflare.com>
++M: Lorenz Bauer <lmb@cloudflare.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: include/linux/skmsg.h
++F: net/core/skmsg.c
++F: net/core/sock_map.c
++F: net/ipv4/tcp_bpf.c
++F: net/ipv4/udp_bpf.c
++F: net/unix/unix_bpf.c
++
++LANDLOCK SECURITY MODULE
++M: Mickaël Salaün <mic@digikod.net>
++L: linux-security-module@vger.kernel.org
++S: Supported
++W: https://landlock.io
++T: git https://github.com/landlock-lsm/linux.git
++F: Documentation/security/landlock.rst
++F: Documentation/userspace-api/landlock.rst
++F: include/uapi/linux/landlock.h
++F: samples/landlock/
++F: security/landlock/
++F: tools/testing/selftests/landlock/
++K: landlock
++K: LANDLOCK
++
++LANTIQ / INTEL Ethernet drivers
++M: Hauke Mehrtens <hauke@hauke-m.de>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/dsa/lantiq_gswip.c
++F: drivers/net/dsa/lantiq_pce.h
++F: drivers/net/ethernet/lantiq_xrx200.c
++F: net/dsa/tag_gswip.c
++
++LANTIQ MIPS ARCHITECTURE
++M: John Crispin <john@phrozen.org>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/lantiq
++F: drivers/soc/lantiq
++
++LASI 53c700 driver for PARISC
++M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: Documentation/scsi/53c700.rst
++F: drivers/scsi/53c700*
++
++LEAKING_ADDRESSES
++M: Tobin C. Harding <me@tobin.cc>
++M: Tycho Andersen <tycho@tycho.pizza>
++L: linux-hardening@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tobin/leaks.git
++F: scripts/leaking_addresses.pl
++
++LED SUBSYSTEM
++M: Pavel Machek <pavel@ucw.cz>
++L: linux-leds@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
++F: Documentation/devicetree/bindings/leds/
++F: drivers/leds/
++F: include/linux/leds.h
++
++LEGACY EEPROM DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++S: Maintained
++F: Documentation/misc-devices/eeprom.rst
++F: drivers/misc/eeprom/eeprom.c
++
++LEGO MINDSTORMS EV3
++R: David Lechner <david@lechnology.com>
++S: Maintained
++F: Documentation/devicetree/bindings/power/supply/lego,ev3-battery.yaml
++F: arch/arm/boot/dts/da850-lego-ev3.dts
++F: drivers/power/supply/lego_ev3_battery.c
++
++LEGO USB Tower driver
++M: Juergen Stuber <starblue@users.sourceforge.net>
++L: legousb-devel@lists.sourceforge.net
++S: Maintained
++W: http://legousb.sourceforge.net/
++F: drivers/usb/misc/legousbtower.c
++
++LG LAPTOP EXTRAS
++M: Matan Ziv-Av <matan@svgalib.org>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-platform-lg-laptop
++F: Documentation/admin-guide/laptops/lg-laptop.rst
++F: drivers/platform/x86/lg-laptop.c
++
++LG2160 MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/dvb-frontends/lg2160.*
++
++LGDT3305 MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/dvb-frontends/lgdt3305.*
++
++LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
++M: Viresh Kumar <vireshk@kernel.org>
++L: linux-ide@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
++F: drivers/ata/pata_arasan_cf.c
++F: include/linux/pata_arasan_cf_data.h
++
++LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-ide@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
++F: drivers/ata/pata_ftide010.c
++F: drivers/ata/sata_gemini.c
++F: drivers/ata/sata_gemini.h
++
++LIBATA SATA AHCI PLATFORM devices support
++M: Hans de Goede <hdegoede@redhat.com>
++M: Jens Axboe <axboe@kernel.dk>
++L: linux-ide@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
++F: drivers/ata/ahci_platform.c
++F: drivers/ata/libahci_platform.c
++F: include/linux/ahci_platform.h
++
++LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
++M: Mikael Pettersson <mikpelinux@gmail.com>
++L: linux-ide@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
++F: drivers/ata/sata_promise.*
++
++LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
++M: Damien Le Moal <damien.lemoal@opensource.wdc.com>
++L: linux-ide@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git
++F: Documentation/devicetree/bindings/ata/
++F: drivers/ata/
++F: include/linux/ata.h
++F: include/linux/libata.h
++
++LIBLOCKDEP
++M: Sasha Levin <alexander.levin@microsoft.com>
++S: Maintained
++F: tools/lib/lockdep/
++
++LIBNVDIMM BLK: MMIO-APERTURE DRIVER
++M: Dan Williams <dan.j.williams@intel.com>
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Dave Jiang <dave.jiang@intel.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
++P: Documentation/nvdimm/maintainer-entry-profile.rst
++F: drivers/nvdimm/blk.c
++F: drivers/nvdimm/region_devs.c
++
++LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Dan Williams <dan.j.williams@intel.com>
++M: Dave Jiang <dave.jiang@intel.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
++P: Documentation/nvdimm/maintainer-entry-profile.rst
++F: drivers/nvdimm/btt*
++
++LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER
++M: Dan Williams <dan.j.williams@intel.com>
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Dave Jiang <dave.jiang@intel.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
++P: Documentation/nvdimm/maintainer-entry-profile.rst
++F: drivers/nvdimm/pmem*
++
++LIBNVDIMM: DEVICETREE BINDINGS
++M: Oliver O'Halloran <oohall@gmail.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
++F: Documentation/devicetree/bindings/pmem/pmem-region.txt
++F: drivers/nvdimm/of_pmem.c
++
++LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
++M: Dan Williams <dan.j.williams@intel.com>
++M: Vishal Verma <vishal.l.verma@intel.com>
++M: Dave Jiang <dave.jiang@intel.com>
++M: Ira Weiny <ira.weiny@intel.com>
++L: nvdimm@lists.linux.dev
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
++P: Documentation/nvdimm/maintainer-entry-profile.rst
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
++F: drivers/acpi/nfit/*
++F: drivers/nvdimm/*
++F: include/linux/libnvdimm.h
++F: include/linux/nd.h
++F: include/uapi/linux/ndctl.h
++F: tools/testing/nvdimm/
++
++LICENSES and SPDX stuff
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-spdx@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/spdx.git
++F: COPYING
++F: Documentation/process/license-rules.rst
++F: LICENSES/
++F: scripts/spdxcheck-test.sh
++F: scripts/spdxcheck.py
++
++LINEAR RANGES HELPERS
++M: Mark Brown <broonie@kernel.org>
++R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
++F: lib/linear_ranges.c
++F: lib/test_linear_ranges.c
++F: include/linux/linear_range.h
++
++LINUX FOR POWER MACINTOSH
++M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Odd Fixes
++F: arch/powerpc/platforms/powermac/
++F: drivers/macintosh/
++
++LINUX FOR POWERPC (32-BIT AND 64-BIT)
++M: Michael Ellerman <mpe@ellerman.id.au>
++R: Benjamin Herrenschmidt <benh@kernel.crashing.org>
++R: Paul Mackerras <paulus@samba.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++W: https://github.com/linuxppc/wiki/wiki
++Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
++F: Documentation/ABI/stable/sysfs-firmware-opal-*
++F: Documentation/devicetree/bindings/i2c/i2c-opal.txt
++F: Documentation/devicetree/bindings/powerpc/
++F: Documentation/devicetree/bindings/rtc/rtc-opal.txt
++F: Documentation/powerpc/
++F: arch/powerpc/
++F: drivers/*/*/*pasemi*
++F: drivers/*/*pasemi*
++F: drivers/char/tpm/tpm_ibmvtpm*
++F: drivers/crypto/nx/
++F: drivers/crypto/vmx/
++F: drivers/i2c/busses/i2c-opal.c
++F: drivers/net/ethernet/ibm/ibmveth.*
++F: drivers/net/ethernet/ibm/ibmvnic.*
++F: drivers/pci/hotplug/pnv_php.c
++F: drivers/pci/hotplug/rpa*
++F: drivers/rtc/rtc-opal.c
++F: drivers/scsi/ibmvscsi/
++F: drivers/tty/hvc/hvc_opal.c
++F: drivers/watchdog/wdrtas.c
++F: tools/testing/selftests/powerpc
++N: /pmac
++N: powermac
++N: powernv
++N: [^a-z0-9]ps3
++N: pseries
++
++LINUX FOR POWERPC EMBEDDED MPC5XXX
++M: Anatolij Gustschin <agust@denx.de>
++L: linuxppc-dev@lists.ozlabs.org
++S: Odd Fixes
++F: arch/powerpc/platforms/512x/
++F: arch/powerpc/platforms/52xx/
++
++LINUX FOR POWERPC EMBEDDED PPC4XX
++L: linuxppc-dev@lists.ozlabs.org
++S: Orphan
++F: arch/powerpc/platforms/40x/
++F: arch/powerpc/platforms/44x/
++
++LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
++M: Scott Wood <oss@buserror.net>
++L: linuxppc-dev@lists.ozlabs.org
++S: Odd fixes
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git
++F: Documentation/devicetree/bindings/powerpc/fsl/
++F: arch/powerpc/platforms/83xx/
++F: arch/powerpc/platforms/85xx/
++
++LINUX FOR POWERPC EMBEDDED PPC8XX
++M: Christophe Leroy <christophe.leroy@csgroup.eu>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: arch/powerpc/platforms/8xx/
++
++LINUX KERNEL DUMP TEST MODULE (LKDTM)
++M: Kees Cook <keescook@chromium.org>
++S: Maintained
++F: drivers/misc/lkdtm/*
++F: tools/testing/selftests/lkdtm/*
++
++LINUX KERNEL MEMORY CONSISTENCY MODEL (LKMM)
++M: Alan Stern <stern@rowland.harvard.edu>
++M: Andrea Parri <parri.andrea@gmail.com>
++M: Will Deacon <will@kernel.org>
++M: Peter Zijlstra <peterz@infradead.org>
++M: Boqun Feng <boqun.feng@gmail.com>
++M: Nicholas Piggin <npiggin@gmail.com>
++M: David Howells <dhowells@redhat.com>
++M: Jade Alglave <j.alglave@ucl.ac.uk>
++M: Luc Maranget <luc.maranget@inria.fr>
++M: "Paul E. McKenney" <paulmck@kernel.org>
++R: Akira Yokosawa <akiyks@gmail.com>
++R: Daniel Lustig <dlustig@nvidia.com>
++R: Joel Fernandes <joel@joelfernandes.org>
++L: linux-kernel@vger.kernel.org
++L: linux-arch@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
++F: Documentation/atomic_bitops.txt
++F: Documentation/atomic_t.txt
++F: Documentation/core-api/refcount-vs-atomic.rst
++F: Documentation/litmus-tests/
++F: Documentation/memory-barriers.txt
++F: tools/memory-model/
++
++LIS3LV02D ACCELEROMETER DRIVER
++M: Eric Piel <eric.piel@tremplin-utc.net>
++S: Maintained
++F: Documentation/misc-devices/lis3lv02d.rst
++F: drivers/misc/lis3lv02d/
++F: drivers/platform/x86/hp_accel.c
++
++LIST KUNIT TEST
++M: David Gow <davidgow@google.com>
++L: linux-kselftest@vger.kernel.org
++L: kunit-dev@googlegroups.com
++S: Maintained
++F: lib/list-test.c
++
++LITEX PLATFORM
++M: Karol Gugala <kgugala@antmicro.com>
++M: Mateusz Holenko <mholenko@antmicro.com>
++S: Maintained
++F: Documentation/devicetree/bindings/*/litex,*.yaml
++F: arch/openrisc/boot/dts/or1klitex.dts
++F: drivers/soc/litex/litex_soc_ctrl.c
++F: drivers/tty/serial/liteuart.c
++F: include/linux/litex.h
++
++LIVE PATCHING
++M: Josh Poimboeuf <jpoimboe@redhat.com>
++M: Jiri Kosina <jikos@kernel.org>
++M: Miroslav Benes <mbenes@suse.cz>
++M: Petr Mladek <pmladek@suse.com>
++R: Joe Lawrence <joe.lawrence@redhat.com>
++L: live-patching@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git
++F: Documentation/ABI/testing/sysfs-kernel-livepatch
++F: Documentation/livepatch/
++F: arch/powerpc/include/asm/livepatch.h
++F: arch/s390/include/asm/livepatch.h
++F: arch/x86/include/asm/livepatch.h
++F: include/linux/livepatch.h
++F: kernel/livepatch/
++F: lib/livepatch/
++F: samples/livepatch/
++F: tools/testing/selftests/livepatch/
++
++LLC (802.2)
++L: netdev@vger.kernel.org
++S: Odd fixes
++F: include/linux/llc.h
++F: include/net/llc*
++F: include/uapi/linux/llc.h
++F: net/llc/
++
++LM73 HARDWARE MONITOR DRIVER
++M: Guillaume Ligneul <guillaume.ligneul@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/lm73.c
++
++LM78 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/lm78.rst
++F: drivers/hwmon/lm78.c
++
++LM83 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/lm83.rst
++F: drivers/hwmon/lm83.c
++
++LM90 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/hwmon/lm90.txt
++F: Documentation/hwmon/lm90.rst
++F: drivers/hwmon/lm90.c
++F: include/dt-bindings/thermal/lm90.h
++
++LM95234 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/lm95234.rst
++F: drivers/hwmon/lm95234.c
++
++LME2510 MEDIA DRIVER
++M: Malcolm Priestley <tvboxspy@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/usb/dvb-usb-v2/lmedm04*
++
++LOADPIN SECURITY MODULE
++M: Kees Cook <keescook@chromium.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
++F: Documentation/admin-guide/LSM/LoadPin.rst
++F: security/loadpin/
++
++LOCKING PRIMITIVES
++M: Peter Zijlstra <peterz@infradead.org>
++M: Ingo Molnar <mingo@redhat.com>
++M: Will Deacon <will@kernel.org>
++R: Waiman Long <longman@redhat.com>
++R: Boqun Feng <boqun.feng@gmail.com> (LOCKDEP)
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
++F: Documentation/locking/
++F: arch/*/include/asm/spinlock*.h
++F: include/linux/lockdep.h
++F: include/linux/mutex*.h
++F: include/linux/rwlock*.h
++F: include/linux/rwsem*.h
++F: include/linux/seqlock.h
++F: include/linux/spinlock*.h
++F: kernel/locking/
++F: lib/locking*.[ch]
++X: kernel/locking/locktorture.c
++
++LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
++M: "Richard Russon (FlatCap)" <ldm@flatcap.org>
++L: linux-ntfs-dev@lists.sourceforge.net
++S: Maintained
++W: http://www.linux-ntfs.org/content/view/19/37/
++F: Documentation/admin-guide/ldm.rst
++F: block/partitions/ldm.*
++
++LOGITECH HID GAMING KEYBOARDS
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
++F: drivers/hid/hid-lg-g15.c
++
++LONTIUM LT8912B MIPI TO HDMI BRIDGE
++M: Adrien Grassein <adrien.grassein@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml
++F: drivers/gpu/drm/bridge/lontium-lt8912b.c
++
++LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
++M: Sathya Prakash <sathya.prakash@broadcom.com>
++M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
++M: Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
++L: MPT-FusionLinux.pdl@broadcom.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++W: http://www.avagotech.com/support/
++F: drivers/message/fusion/
++F: drivers/scsi/mpt3sas/
++
++LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers
++M: Matthew Wilcox <willy@infradead.org>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/sym53c8xx_2/
++
++LTC1660 DAC DRIVER
++M: Marcus Folkesson <marcus.folkesson@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
++F: drivers/iio/dac/ltc1660.c
++
++LTC2947 HARDWARE MONITOR DRIVER
++M: Nuno Sá <nuno.sa@analog.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
++F: drivers/hwmon/ltc2947-core.c
++F: drivers/hwmon/ltc2947-i2c.c
++F: drivers/hwmon/ltc2947-spi.c
++F: drivers/hwmon/ltc2947.h
++
++LTC2983 IIO TEMPERATURE DRIVER
++M: Nuno Sá <nuno.sa@analog.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
++F: drivers/iio/temperature/ltc2983.c
++
++LTC4261 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/ltc4261.rst
++F: drivers/hwmon/ltc4261.c
++
++LTC4306 I2C MULTIPLEXER DRIVER
++M: Michael Hennerich <michael.hennerich@analog.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++W: http://ez.analog.com/community/linux-device-drivers
++F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
++F: drivers/i2c/muxes/i2c-mux-ltc4306.c
++
++LTP (Linux Test Project)
++M: Mike Frysinger <vapier@gentoo.org>
++M: Cyril Hrubis <chrubis@suse.cz>
++M: Wanlong Gao <wanlong.gao@gmail.com>
++M: Jan Stancek <jstancek@redhat.com>
++M: Stanislav Kholmanskikh <stanislav.kholmanskikh@oracle.com>
++M: Alexey Kodanev <alexey.kodanev@oracle.com>
++L: ltp@lists.linux.it (subscribers-only)
++S: Maintained
++W: http://linux-test-project.github.io/
++T: git git://github.com/linux-test-project/ltp.git
++
++LYNX PCS MODULE
++M: Ioana Ciornei <ioana.ciornei@nxp.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/pcs/pcs-lynx.c
++F: include/linux/pcs-lynx.h
++
++M68K ARCHITECTURE
++M: Geert Uytterhoeven <geert@linux-m68k.org>
++L: linux-m68k@lists.linux-m68k.org
++S: Maintained
++W: http://www.linux-m68k.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
++F: arch/m68k/
++F: drivers/zorro/
++
++M68K ON APPLE MACINTOSH
++M: Joshua Thompson <funaho@jurai.org>
++L: linux-m68k@lists.linux-m68k.org
++S: Maintained
++W: http://www.mac.linux-m68k.org/
++F: arch/m68k/mac/
++F: drivers/macintosh/adb-iop.c
++F: drivers/macintosh/via-macii.c
++
++M68K ON HP9000/300
++M: Philip Blundell <philb@gnu.org>
++S: Maintained
++W: http://www.tazenda.demon.co.uk/phil/linux-hp
++F: arch/m68k/hp300/
++
++M88DS3103 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/m88ds3103*
++
++M88RS2000 MEDIA DRIVER
++M: Malcolm Priestley <tvboxspy@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/m88rs2000*
++
++MA901 MASTERKIT USB FM RADIO DRIVER
++M: Alexey Klimov <klimov.linux@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-ma901.c
++
++MAC80211
++M: Johannes Berg <johannes@sipsolutions.net>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
++F: Documentation/networking/mac80211-injection.rst
++F: Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
++F: drivers/net/wireless/mac80211_hwsim.[ch]
++F: include/net/mac80211.h
++F: net/mac80211/
++
++MAILBOX API
++M: Jassi Brar <jassisinghbrar@gmail.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/mailbox/
++F: include/linux/mailbox_client.h
++F: include/linux/mailbox_controller.h
++F: include/dt-bindings/mailbox/
++F: Documentation/devicetree/bindings/mailbox/
++
++MAILBOX ARM MHUv2
++M: Viresh Kumar <viresh.kumar@linaro.org>
++M: Tushar Khandelwal <Tushar.Khandelwal@arm.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/mailbox/arm_mhuv2.c
++F: include/linux/mailbox/arm_mhuv2_message.h
++F: Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
++
++MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP)
++M: Jeremy Kerr <jk@codeconstruct.com.au>
++M: Matt Johnston <matt@codeconstruct.com.au>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/networking/mctp.rst
++F: drivers/net/mctp/
++F: include/net/mctp.h
++F: include/net/mctpdevice.h
++F: include/net/netns/mctp.h
++F: net/mctp/
++
++MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
++M: Michael Kerrisk <mtk.manpages@gmail.com>
++L: linux-man@vger.kernel.org
++S: Maintained
++W: http://www.kernel.org/doc/man-pages
++
++MARDUK (CREATOR CI40) DEVICE TREE SUPPORT
++M: Rahul Bedarkar <rahulbedarkar89@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/boot/dts/img/pistachio*
++
++MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
++M: Andrew Lunn <andrew@lunn.ch>
++M: Vivien Didelot <vivien.didelot@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/marvell.txt
++F: Documentation/networking/devlink/mv88e6xxx.rst
++F: drivers/net/dsa/mv88e6xxx/
++F: include/linux/dsa/mv88e6xxx.h
++F: include/linux/platform_data/mv88e6xxx.h
++
++MARVELL ARMADA 3700 PHY DRIVERS
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++S: Maintained
++F: Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt
++F: Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml
++F: drivers/phy/marvell/phy-mvebu-a3700-comphy.c
++F: drivers/phy/marvell/phy-mvebu-a3700-utmi.c
++
++MARVELL ARMADA DRM SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++S: Maintained
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-devel
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-fixes
++F: Documentation/devicetree/bindings/display/armada/
++F: drivers/gpu/drm/armada/
++F: include/uapi/drm/armada_drm.h
++
++MARVELL CRYPTO DRIVER
++M: Boris Brezillon <bbrezillon@kernel.org>
++M: Arnaud Ebalard <arno@natisbad.org>
++M: Srujana Challa <schalla@marvell.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/marvell/
++F: include/linux/soc/marvell/octeontx2/
++
++MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
++M: Mirko Lindner <mlindner@marvell.com>
++M: Stephen Hemminger <stephen@networkplumber.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/marvell/sk*
++
++MARVELL LIBERTAS WIRELESS DRIVER
++L: libertas-dev@lists.infradead.org
++S: Orphan
++F: drivers/net/wireless/marvell/libertas/
++
++MARVELL MACCHIATOBIN SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
++
++MARVELL MV643XX ETHERNET DRIVER
++M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/marvell/mv643xx_eth.*
++F: include/linux/mv643xx.h
++
++MARVELL MV88X3310 PHY DRIVER
++M: Russell King <linux@armlinux.org.uk>
++M: Marek Behún <kabel@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/phy/marvell10g.c
++
++MARVELL MVEBU THERMAL DRIVER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++S: Maintained
++F: drivers/thermal/armada_thermal.c
++
++MARVELL MVNETA ETHERNET DRIVER
++M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/marvell/mvneta.*
++
++MARVELL MVPP2 ETHERNET DRIVER
++M: Marcin Wojtas <mw@semihalf.com>
++M: Russell King <linux@armlinux.org.uk>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/marvell-pp2.txt
++F: drivers/net/ethernet/marvell/mvpp2/
++
++MARVELL MWIFIEX WIRELESS DRIVER
++M: Amitkumar Karwar <amitkarwar@gmail.com>
++M: Ganapathi Bhat <ganapathi017@gmail.com>
++M: Sharvari Harisangam <sharvari.harisangam@nxp.com>
++M: Xinming Hu <huxinming820@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/marvell/mwifiex/
++
++MARVELL MWL8K WIRELESS DRIVER
++M: Lennert Buytenhek <buytenh@wantstofly.org>
++L: linux-wireless@vger.kernel.org
++S: Odd Fixes
++F: drivers/net/wireless/marvell/mwl8k.c
++
++MARVELL NAND CONTROLLER DRIVER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mtd/marvell-nand.txt
++F: drivers/mtd/nand/raw/marvell_nand.c
++
++MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
++M: Sunil Goutham <sgoutham@marvell.com>
++M: Geetha sowjanya <gakula@marvell.com>
++M: Subbaraya Sundeep <sbhatta@marvell.com>
++M: hariprasad <hkelam@marvell.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/marvell/octeontx2/nic/
++F: include/linux/soc/marvell/octeontx2/
++
++MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
++M: Sunil Goutham <sgoutham@marvell.com>
++M: Linu Cherian <lcherian@marvell.com>
++M: Geetha sowjanya <gakula@marvell.com>
++M: Jerin Jacob <jerinj@marvell.com>
++M: hariprasad <hkelam@marvell.com>
++M: Subbaraya Sundeep <sbhatta@marvell.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
++F: drivers/net/ethernet/marvell/octeontx2/af/
++
++MARVELL PRESTERA ETHERNET SWITCH DRIVER
++M: Taras Chornyi <tchornyi@marvell.com>
++S: Supported
++W: https://github.com/Marvell-switching/switchdev-prestera
++F: drivers/net/ethernet/marvell/prestera/
++
++MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
++M: Nicolas Pitre <nico@fluxnic.net>
++S: Odd Fixes
++F: drivers/mmc/host/mvsdio.*
++
++MARVELL USB MDIO CONTROLLER DRIVER
++M: Tobias Waldekranz <tobias@waldekranz.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/marvell,mvusb.yaml
++F: drivers/net/mdio/mdio-mvusb.c
++
++MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
++M: Hu Ziji <huziji@marvell.com>
++L: linux-mmc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
++F: drivers/mmc/host/sdhci-xenon*
++
++MATROX FRAMEBUFFER DRIVER
++L: linux-fbdev@vger.kernel.org
++S: Orphan
++F: drivers/video/fbdev/matrox/matroxfb_*
++F: include/uapi/linux/matroxfb.h
++
++MAX15301 DRIVER
++M: Daniel Nilsson <daniel.nilsson@flex.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/max15301.rst
++F: drivers/hwmon/pmbus/max15301.c
++
++MAX16065 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/max16065.rst
++F: drivers/hwmon/max16065.c
++
++MAX2175 SDR TUNER DRIVER
++M: Ramesh Shanmugasundaram <rashanmu@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/max2175.txt
++F: Documentation/userspace-api/media/drivers/max2175.rst
++F: drivers/media/i2c/max2175*
++F: include/uapi/linux/max2175.h
++
++MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
++L: linux-hwmon@vger.kernel.org
++S: Orphan
++F: Documentation/hwmon/max6650.rst
++F: drivers/hwmon/max6650.c
++
++MAX6697 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/hwmon/max6697.txt
++F: Documentation/hwmon/max6697.rst
++F: drivers/hwmon/max6697.c
++F: include/linux/platform_data/max6697.h
++
++MAX9286 QUAD GMSL DESERIALIZER DRIVER
++M: Jacopo Mondi <jacopo+renesas@jmondi.org>
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
++M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
++F: drivers/media/i2c/max9286.c
++
++MAX9860 MONO AUDIO VOICE CODEC DRIVER
++M: Peter Rosin <peda@axentia.se>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/max9860.txt
++F: sound/soc/codecs/max9860.*
++
++MAXBOTIX ULTRASONIC RANGER IIO DRIVER
++M: Andreas Klinger <ak@it-klinger.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.yaml
++F: drivers/iio/proximity/mb1232.c
++
++MAXIM MAX77650 PMIC MFD DRIVER
++M: Bartosz Golaszewski <brgl@bgdev.pl>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/*/*max77650.yaml
++F: Documentation/devicetree/bindings/*/max77650*.yaml
++F: drivers/gpio/gpio-max77650.c
++F: drivers/input/misc/max77650-onkey.c
++F: drivers/leds/leds-max77650.c
++F: drivers/mfd/max77650.c
++F: drivers/power/supply/max77650-charger.c
++F: drivers/regulator/max77650-regulator.c
++F: include/linux/mfd/max77650.h
++
++MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
++M: Javier Martinez Canillas <javier@dowhile0.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/*/*max77802.txt
++F: drivers/regulator/max77802-regulator.c
++F: include/dt-bindings/*/*max77802.h
++
++MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++F: drivers/power/supply/max14577_charger.c
++F: drivers/power/supply/max77693_charger.c
++
++MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
++M: Chanwoo Choi <cw00.choi@samsung.com>
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/*/max77686.txt
++F: Documentation/devicetree/bindings/clock/maxim,max77686.txt
++F: Documentation/devicetree/bindings/mfd/max14577.txt
++F: Documentation/devicetree/bindings/mfd/max77693.txt
++F: drivers/*/max14577*.c
++F: drivers/*/max77686*.c
++F: drivers/*/max77693*.c
++F: drivers/clk/clk-max77686.c
++F: drivers/extcon/extcon-max14577.c
++F: drivers/extcon/extcon-max77693.c
++F: drivers/rtc/rtc-max77686.c
++F: include/linux/mfd/max14577*.h
++F: include/linux/mfd/max77686*.h
++F: include/linux/mfd/max77693*.h
++
++MAXIRADIO FM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-maxiradio*
++
++MAXLINEAR ETHERNET PHY DRIVER
++M: Xu Liang <lxu@maxlinear.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/phy/mxl-gpy.c
++
++MCBA MICROCHIP CAN BUS ANALYZER TOOL DRIVER
++R: Yasushi SHOJI <yashi@spacecubics.com>
++L: linux-can@vger.kernel.org
++S: Maintained
++F: drivers/net/can/usb/mcba_usb.c
++
++MCAN MMIO DEVICE DRIVER
++M: Chandrasekar Ramakrishnan <rcsekar@samsung.com>
++L: linux-can@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml
++F: drivers/net/can/m_can/m_can.c
++F: drivers/net/can/m_can/m_can.h
++F: drivers/net/can/m_can/m_can_platform.c
++
++MCP2221A MICROCHIP USB-HID TO I2C BRIDGE DRIVER
++M: Rishi Gupta <gupt21@gmail.com>
++L: linux-i2c@vger.kernel.org
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-mcp2221.c
++
++MCP251XFD SPI-CAN NETWORK DRIVER
++M: Marc Kleine-Budde <mkl@pengutronix.de>
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++R: Thomas Kopp <thomas.kopp@microchip.com>
++L: linux-can@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/can/microchip,mcp251xfd.yaml
++F: drivers/net/can/spi/mcp251xfd/
++
++MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
++M: Peter Rosin <peda@axentia.se>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531
++F: drivers/iio/potentiometer/mcp4018.c
++F: drivers/iio/potentiometer/mcp4531.c
++
++MCR20A IEEE-802.15.4 RADIO DRIVER
++M: Xue Liu <liuxuenetmail@gmail.com>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++W: https://github.com/xueliu/mcr20a-linux
++F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
++F: drivers/net/ieee802154/mcr20a.c
++F: drivers/net/ieee802154/mcr20a.h
++
++MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: drivers/iio/dac/cio-dac.c
++
++MEDIA CONTROLLER FRAMEWORK
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://www.linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/mc/
++F: include/media/media-*.h
++F: include/uapi/linux/media.h
++
++MEDIA DRIVER FOR FREESCALE IMX PXP
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/platform/imx-pxp.[ch]
++
++MEDIA DRIVERS FOR ASCOT2E
++M: Sergey Kozlov <serjk@netup.ru>
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/ascot2e*
++
++MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS
++M: Jasmin Jessich <jasmin@anw.at>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/cxd2099*
++
++MEDIA DRIVERS FOR CXD2841ER
++M: Sergey Kozlov <serjk@netup.ru>
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/cxd2841er*
++
++MEDIA DRIVERS FOR CXD2880
++M: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
++L: linux-media@vger.kernel.org
++S: Supported
++W: http://linuxtv.org/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/cxd2880/*
++F: drivers/media/spi/cxd2880*
++
++MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES
++L: linux-media@vger.kernel.org
++S: Orphan
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/ddbridge/*
++
++MEDIA DRIVERS FOR FREESCALE IMX
++M: Steve Longerbeam <slongerbeam@gmail.com>
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/imx.rst
++F: Documentation/devicetree/bindings/media/imx.txt
++F: drivers/staging/media/imx/
++F: include/linux/imx-media.h
++F: include/media/imx.h
++
++MEDIA DRIVERS FOR FREESCALE IMX7
++M: Rui Miguel Silva <rmfrfs@gmail.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/imx7.rst
++F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
++F: Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
++F: drivers/staging/media/imx/imx7-media-csi.c
++F: drivers/staging/media/imx/imx7-mipi-csis.c
++
++MEDIA DRIVERS FOR HELENE
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/helene*
++
++MEDIA DRIVERS FOR HORUS3A
++M: Sergey Kozlov <serjk@netup.ru>
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/horus3a*
++
++MEDIA DRIVERS FOR LNBH25
++M: Sergey Kozlov <serjk@netup.ru>
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/lnbh25*
++
++MEDIA DRIVERS FOR MXL5XX TUNER DEMODULATORS
++L: linux-media@vger.kernel.org
++S: Orphan
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/mxl5xx*
++
++MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
++M: Sergey Kozlov <serjk@netup.ru>
++M: Abylay Ospan <aospan@netup.ru>
++L: linux-media@vger.kernel.org
++S: Supported
++W: https://linuxtv.org
++W: http://netup.tv/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/netup_unidvb/*
++
++MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
++M: Dmitry Osipenko <digetx@gmail.com>
++L: linux-media@vger.kernel.org
++L: linux-tegra@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
++F: drivers/staging/media/tegra-vde/
++
++MEDIA DRIVERS FOR RENESAS - CEU
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,ceu.yaml
++F: drivers/media/platform/renesas-ceu.c
++F: include/media/drv-intf/renesas-ceu.h
++
++MEDIA DRIVERS FOR RENESAS - DRIF
++M: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,drif.yaml
++F: drivers/media/platform/rcar_drif.c
++
++MEDIA DRIVERS FOR RENESAS - FCP
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,fcp.yaml
++F: drivers/media/platform/rcar-fcp.c
++F: include/media/rcar-fcp.h
++
++MEDIA DRIVERS FOR RENESAS - FDP1
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,fdp1.yaml
++F: drivers/media/platform/rcar_fdp1.c
++
++MEDIA DRIVERS FOR RENESAS - VIN
++M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,csi2.yaml
++F: Documentation/devicetree/bindings/media/renesas,isp.yaml
++F: Documentation/devicetree/bindings/media/renesas,vin.yaml
++F: drivers/media/platform/rcar-vin/
++
++MEDIA DRIVERS FOR RENESAS - VSP1
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++L: linux-media@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/renesas,vsp1.yaml
++F: drivers/media/platform/vsp1/
++
++MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs
++L: linux-media@vger.kernel.org
++S: Orphan
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/stv0910*
++
++MEDIA DRIVERS FOR ST STV6111 TUNER ICs
++L: linux-media@vger.kernel.org
++S: Orphan
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/dvb-frontends/stv6111*
++
++MEDIA DRIVERS FOR STM32 - DCMI
++M: Hugues Fruchet <hugues.fruchet@foss.st.com>
++L: linux-media@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
++F: drivers/media/platform/stm32/stm32-dcmi.c
++
++MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.kernel.org/project/linux-media/list/
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/
++F: Documentation/devicetree/bindings/media/
++F: Documentation/driver-api/media/
++F: Documentation/userspace-api/media/
++F: drivers/media/
++F: drivers/staging/media/
++F: include/linux/platform_data/media/
++F: include/media/
++F: include/uapi/linux/dvb/
++F: include/uapi/linux/ivtv*
++F: include/uapi/linux/media.h
++F: include/uapi/linux/meye.h
++F: include/uapi/linux/uvcvideo.h
++F: include/uapi/linux/v4l2-*
++F: include/uapi/linux/videodev2.h
++
++MEDIATEK BLUETOOTH DRIVER
++M: Sean Wang <sean.wang@mediatek.com>
++L: linux-bluetooth@vger.kernel.org
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/net/mediatek-bluetooth.txt
++F: drivers/bluetooth/btmtkuart.c
++
++MEDIATEK BOARD LEVEL SHUTDOWN DRIVERS
++M: Sean Wang <sean.wang@mediatek.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt
++F: drivers/power/reset/mt6323-poweroff.c
++
++MEDIATEK CIR DRIVER
++M: Sean Wang <sean.wang@mediatek.com>
++S: Maintained
++F: drivers/media/rc/mtk-cir.c
++
++MEDIATEK DMA DRIVER
++M: Sean Wang <sean.wang@mediatek.com>
++L: dmaengine@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/dma/mtk-*
++F: drivers/dma/mediatek/
++
++MEDIATEK ETHERNET DRIVER
++M: Felix Fietkau <nbd@nbd.name>
++M: John Crispin <john@phrozen.org>
++M: Sean Wang <sean.wang@mediatek.com>
++M: Mark Lee <Mark-MC.Lee@mediatek.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/mediatek/
++
++MEDIATEK I2C CONTROLLER DRIVER
++M: Qii Wang <qii.wang@mediatek.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-mt65xx.txt
++F: drivers/i2c/busses/i2c-mt65xx.c
++
++MEDIATEK IOMMU DRIVER
++M: Yong Wu <yong.wu@mediatek.com>
++L: iommu@lists.linux-foundation.org
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/iommu/mediatek*
++F: drivers/iommu/mtk_iommu*
++F: include/dt-bindings/memory/mt*-port.h
++
++MEDIATEK JPEG DRIVER
++M: Rick Chang <rick.chang@mediatek.com>
++M: Bin Liu <bin.liu@mediatek.com>
++S: Supported
++F: Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
++F: drivers/media/platform/mtk-jpeg/
++
++MEDIATEK MDP DRIVER
++M: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
++M: Houlong Wei <houlong.wei@mediatek.com>
++M: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
++S: Supported
++F: Documentation/devicetree/bindings/media/mediatek-mdp.txt
++F: drivers/media/platform/mtk-mdp/
++F: drivers/media/platform/mtk-vpu/
++
++MEDIATEK MEDIA DRIVER
++M: Tiffany Lin <tiffany.lin@mediatek.com>
++M: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
++S: Supported
++F: Documentation/devicetree/bindings/media/mediatek-vcodec.txt
++F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
++F: drivers/media/platform/mtk-vcodec/
++F: drivers/media/platform/mtk-vpu/
++
++MEDIATEK MMC/SD/SDIO DRIVER
++M: Chaotian Jing <chaotian.jing@mediatek.com>
++S: Maintained
++F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml
++F: drivers/mmc/host/mtk-sd.c
++
++MEDIATEK MT76 WIRELESS LAN DRIVER
++M: Felix Fietkau <nbd@nbd.name>
++M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
++R: Ryder Lee <ryder.lee@mediatek.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/mediatek/mt76/
++
++MEDIATEK MT7601U WIRELESS LAN DRIVER
++M: Jakub Kicinski <kubakici@wp.pl>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/mediatek/mt7601u/
++
++MEDIATEK MT7621 CLOCK DRIVER
++M: Sergio Paracuellos <sergio.paracuellos@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/clock/mediatek,mt7621-sysc.yaml
++F: drivers/clk/ralink/clk-mt7621.c
++
++MEDIATEK MT7621/28/88 I2C DRIVER
++M: Stefan Roese <sr@denx.de>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
++F: drivers/i2c/busses/i2c-mt7621.c
++
++MEDIATEK MT7621 PHY PCI DRIVER
++M: Sergio Paracuellos <sergio.paracuellos@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml
++F: drivers/phy/ralink/phy-mt7621-pci.c
++
++MEDIATEK NAND CONTROLLER DRIVER
++L: linux-mtd@lists.infradead.org
++S: Orphan
++F: Documentation/devicetree/bindings/mtd/mtk-nand.txt
++F: drivers/mtd/nand/raw/mtk_*
++
++MEDIATEK PMIC LED DRIVER
++M: Sean Wang <sean.wang@mediatek.com>
++S: Maintained
++F: Documentation/devicetree/bindings/leds/leds-mt6323.txt
++F: drivers/leds/leds-mt6323.c
++
++MEDIATEK RANDOM NUMBER GENERATOR SUPPORT
++M: Sean Wang <sean.wang@mediatek.com>
++S: Maintained
++F: drivers/char/hw_random/mtk-rng.c
++
++MEDIATEK SWITCH DRIVER
++M: Sean Wang <sean.wang@mediatek.com>
++M: Landen Chao <Landen.Chao@mediatek.com>
++M: DENG Qingfang <dqfext@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/dsa/mt7530.*
++F: net/dsa/tag_mtk.c
++
++MEDIATEK USB3 DRD IP DRIVER
++M: Chunfeng Yun <chunfeng.yun@mediatek.com>
++L: linux-usb@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/usb/mediatek,*
++F: drivers/usb/host/xhci-mtk*
++F: drivers/usb/mtu3/
++
++MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
++M: Peter Senna Tschudin <peter.senna@gmail.com>
++M: Martin Donnelly <martin.donnelly@ge.com>
++M: Martyn Welch <martyn.welch@collabora.co.uk>
++S: Maintained
++F: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
++F: drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
++
++MEGARAID SCSI/SAS DRIVERS
++M: Kashyap Desai <kashyap.desai@broadcom.com>
++M: Sumit Saxena <sumit.saxena@broadcom.com>
++M: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
++L: megaraidlinux.pdl@broadcom.com
++L: linux-scsi@vger.kernel.org
++S: Maintained
++W: http://www.avagotech.com/support/
++F: Documentation/scsi/megaraid.rst
++F: drivers/scsi/megaraid.*
++F: drivers/scsi/megaraid/
++
++MELEXIS MLX90614 DRIVER
++M: Crt Mori <cmo@melexis.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://www.melexis.com
++F: drivers/iio/temperature/mlx90614.c
++
++MELEXIS MLX90632 DRIVER
++M: Crt Mori <cmo@melexis.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++W: http://www.melexis.com
++F: drivers/iio/temperature/mlx90632.c
++
++MELFAS MIP4 TOUCHSCREEN DRIVER
++M: Sangwon Jee <jeesw@melfas.com>
++S: Supported
++W: http://www.melfas.com
++F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
++F: drivers/input/touchscreen/melfas_mip4.c
++
++MELLANOX BLUEFIELD I2C DRIVER
++M: Khalil Blaiech <kblaiech@nvidia.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
++F: drivers/i2c/busses/i2c-mlxbf.c
++
++MELLANOX ETHERNET DRIVER (mlx4_en)
++M: Tariq Toukan <tariqt@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlx4/en_*
++
++MELLANOX ETHERNET DRIVER (mlx5e)
++M: Saeed Mahameed <saeedm@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlx5/core/en_*
++
++MELLANOX ETHERNET INNOVA DRIVERS
++R: Boris Pismenny <borisp@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlx5/core/accel/*
++F: drivers/net/ethernet/mellanox/mlx5/core/en_accel/*
++F: drivers/net/ethernet/mellanox/mlx5/core/fpga/*
++F: include/linux/mlx5/mlx5_ifc_fpga.h
++
++MELLANOX ETHERNET SWITCH DRIVERS
++M: Jiri Pirko <jiri@nvidia.com>
++M: Ido Schimmel <idosch@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlxsw/
++F: tools/testing/selftests/drivers/net/mlxsw/
++
++MELLANOX FIRMWARE FLASH LIBRARY (mlxfw)
++M: mlxsw@nvidia.com
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlxfw/
++
++MELLANOX HARDWARE PLATFORM SUPPORT
++M: Hans de Goede <hdegoede@redhat.com>
++M: Mark Gross <mgross@linux.intel.com>
++M: Vadim Pasternak <vadimp@nvidia.com>
++L: platform-driver-x86@vger.kernel.org
++S: Supported
++F: Documentation/ABI/testing/sysfs-platform-mellanox-bootctl
++F: drivers/platform/mellanox/
++F: include/linux/platform_data/mlxreg.h
++
++MELLANOX MLX4 core VPI driver
++M: Tariq Toukan <tariqt@nvidia.com>
++L: netdev@vger.kernel.org
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: drivers/net/ethernet/mellanox/mlx4/
++F: include/linux/mlx4/
++
++MELLANOX MLX4 IB driver
++M: Yishai Hadas <yishaih@nvidia.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/hw/mlx4/
++F: include/linux/mlx4/
++F: include/uapi/rdma/mlx4-abi.h
++
++MELLANOX MLX5 core VPI driver
++M: Saeed Mahameed <saeedm@nvidia.com>
++M: Leon Romanovsky <leonro@nvidia.com>
++L: netdev@vger.kernel.org
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++F: Documentation/networking/device_drivers/ethernet/mellanox/
++F: drivers/net/ethernet/mellanox/mlx5/core/
++F: include/linux/mlx5/
++
++MELLANOX MLX5 IB driver
++M: Leon Romanovsky <leonro@nvidia.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++W: http://www.mellanox.com
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/hw/mlx5/
++F: include/linux/mlx5/
++F: include/uapi/rdma/mlx5-abi.h
++
++MELLANOX MLXCPLD I2C AND MUX DRIVER
++M: Vadim Pasternak <vadimp@nvidia.com>
++M: Michael Shych <michaelsh@nvidia.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++F: Documentation/i2c/busses/i2c-mlxcpld.rst
++F: drivers/i2c/busses/i2c-mlxcpld.c
++F: drivers/i2c/muxes/i2c-mux-mlxcpld.c
++
++MELLANOX MLXCPLD LED DRIVER
++M: Vadim Pasternak <vadimp@nvidia.com>
++L: linux-leds@vger.kernel.org
++S: Supported
++F: Documentation/leds/leds-mlxcpld.rst
++F: drivers/leds/leds-mlxcpld.c
++F: drivers/leds/leds-mlxreg.c
++
++MELLANOX PLATFORM DRIVER
++M: Vadim Pasternak <vadimp@nvidia.com>
++L: platform-driver-x86@vger.kernel.org
++S: Supported
++F: drivers/platform/x86/mlx-platform.c
++
++MEMBARRIER SUPPORT
++M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
++M: "Paul E. McKenney" <paulmck@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: arch/powerpc/include/asm/membarrier.h
++F: include/uapi/linux/membarrier.h
++F: kernel/sched/membarrier.c
++
++MEMBLOCK
++M: Mike Rapoport <rppt@linux.ibm.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: Documentation/core-api/boot-time-mm.rst
++F: include/linux/memblock.h
++F: mm/memblock.c
++
++MEMORY CONTROLLER DRIVERS
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
++F: Documentation/devicetree/bindings/memory-controllers/
++F: drivers/memory/
++F: include/dt-bindings/memory/
++F: include/memory/
++
++MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA
++M: Dmitry Osipenko <digetx@gmail.com>
++L: linux-pm@vger.kernel.org
++L: linux-tegra@vger.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
++S: Maintained
++F: drivers/devfreq/tegra30-devfreq.c
++
++MEMORY MANAGEMENT
++M: Andrew Morton <akpm@linux-foundation.org>
++L: linux-mm@kvack.org
++S: Maintained
++W: http://www.linux-mm.org
++T: quilt https://ozlabs.org/~akpm/mmotm/
++T: quilt https://ozlabs.org/~akpm/mmots/
++T: git git://github.com/hnaz/linux-mm.git
++F: include/linux/gfp.h
++F: include/linux/memory_hotplug.h
++F: include/linux/mm.h
++F: include/linux/mmzone.h
++F: include/linux/pagewalk.h
++F: include/linux/vmalloc.h
++F: mm/
++F: tools/testing/selftests/vm/
++
++MEMORY TECHNOLOGY DEVICES (MTD)
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++M: Richard Weinberger <richard@nod.at>
++M: Vignesh Raghavendra <vigneshr@ti.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++W: http://www.linux-mtd.infradead.org/
++Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
++C: irc://irc.oftc.net/mtd
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/fixes
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
++F: Documentation/devicetree/bindings/mtd/
++F: drivers/mtd/
++F: include/linux/mtd/
++F: include/uapi/mtd/
++
++MEN A21 WATCHDOG DRIVER
++M: Johannes Thumshirn <morbidrsa@gmail.com>
++L: linux-watchdog@vger.kernel.org
++S: Maintained
++F: drivers/watchdog/mena21_wdt.c
++
++MEN CHAMELEON BUS (mcb)
++M: Johannes Thumshirn <morbidrsa@gmail.com>
++S: Maintained
++F: Documentation/driver-api/men-chameleon-bus.rst
++F: drivers/mcb/
++F: include/linux/mcb.h
++
++MEN F21BMC (Board Management Controller)
++M: Andreas Werner <andreas.werner@men.de>
++S: Supported
++F: Documentation/hwmon/menf21bmc.rst
++F: drivers/hwmon/menf21bmc_hwmon.c
++F: drivers/leds/leds-menf21bmc.c
++F: drivers/mfd/menf21bmc.c
++F: drivers/watchdog/menf21bmc_wdt.c
++
++MEN Z069 WATCHDOG DRIVER
++M: Johannes Thumshirn <jth@kernel.org>
++L: linux-watchdog@vger.kernel.org
++S: Maintained
++F: drivers/watchdog/menz69_wdt.c
++
++MESON AO CEC DRIVER FOR AMLOGIC SOCS
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: linux-media@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++W: http://linux-meson.com/
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
++F: drivers/media/cec/platform/meson/ao-cec-g12a.c
++F: drivers/media/cec/platform/meson/ao-cec.c
++
++MESON GE2D DRIVER FOR AMLOGIC SOCS
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: linux-media@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml
++F: drivers/media/platform/meson/ge2d/
++
++MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
++M: Liang Yang <liang.yang@amlogic.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
++F: drivers/mtd/nand/raw/meson_*
++
++MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
++M: Neil Armstrong <narmstrong@baylibre.com>
++L: linux-media@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
++F: drivers/staging/media/meson/vdec/
++
++METHODE UDPU SUPPORT
++M: Vladimir Vid <vladimir.vid@sartura.hr>
++S: Maintained
++F: arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
++
++MHI BUS
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++M: Hemant Kumar <hemantk@codeaurora.org>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi.git
++F: Documentation/ABI/stable/sysfs-bus-mhi
++F: Documentation/mhi/
++F: drivers/bus/mhi/
++F: include/linux/mhi.h
++
++MICROBLAZE ARCHITECTURE
++M: Michal Simek <monstr@monstr.eu>
++S: Supported
++W: http://www.monstr.eu/fdt/
++T: git git://git.monstr.eu/linux-2.6-microblaze.git
++F: arch/microblaze/
++
++MICROCHIP AT91 DMA DRIVERS
++M: Ludovic Desroches <ludovic.desroches@microchip.com>
++M: Tudor Ambarus <tudor.ambarus@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: dmaengine@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/dma/atmel-dma.txt
++F: drivers/dma/at_hdmac.c
++F: drivers/dma/at_hdmac_regs.h
++F: drivers/dma/at_xdmac.c
++F: include/dt-bindings/dma/at91.h
++
++MICROCHIP AT91 SERIAL DRIVER
++M: Richard Genoud <richard.genoud@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
++F: drivers/tty/serial/atmel_serial.c
++F: drivers/tty/serial/atmel_serial.h
++
++MICROCHIP AT91 USART MFD DRIVER
++M: Radu Pirea <radu_nicolae.pirea@upb.ro>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
++F: drivers/mfd/at91-usart.c
++F: include/dt-bindings/mfd/at91-usart.h
++
++MICROCHIP AT91 USART SPI DRIVER
++M: Radu Pirea <radu_nicolae.pirea@upb.ro>
++L: linux-spi@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
++F: drivers/spi/spi-at91-usart.c
++
++MICROCHIP AUDIO ASOC DRIVERS
++M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++F: sound/soc/atmel
++
++MICROCHIP ECC DRIVER
++M: Tudor Ambarus <tudor.ambarus@microchip.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/atmel-ecc.*
++
++MICROCHIP I2C DRIVER
++M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++F: drivers/i2c/busses/i2c-at91-*.c
++F: drivers/i2c/busses/i2c-at91.h
++
++MICROCHIP ISC DRIVER
++M: Eugen Hristev <eugen.hristev@microchip.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/media/atmel,isc.yaml
++F: Documentation/devicetree/bindings/media/microchip,xisc.yaml
++F: drivers/media/platform/atmel/atmel-isc-base.c
++F: drivers/media/platform/atmel/atmel-isc-regs.h
++F: drivers/media/platform/atmel/atmel-isc.h
++F: drivers/media/platform/atmel/atmel-sama5d2-isc.c
++F: drivers/media/platform/atmel/atmel-sama7g5-isc.c
++F: include/linux/atmel-isc-media.h
++
++MICROCHIP ISI DRIVER
++M: Eugen Hristev <eugen.hristev@microchip.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/platform/atmel/atmel-isi.c
++F: drivers/media/platform/atmel/atmel-isi.h
++
++MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
++M: Woojung Huh <woojung.huh@microchip.com>
++M: UNGLinuxDriver@microchip.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
++F: drivers/net/dsa/microchip/*
++F: include/linux/platform_data/microchip-ksz.h
++F: net/dsa/tag_ksz.c
++
++MICROCHIP LAN743X ETHERNET DRIVER
++M: Bryan Whitehead <bryan.whitehead@microchip.com>
++M: UNGLinuxDriver@microchip.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/microchip/lan743x_*
++
++MICROCHIP LCDFB DRIVER
++M: Nicolas Ferre <nicolas.ferre@microchip.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/atmel_lcdfb.c
++F: include/video/atmel_lcdc.h
++
++MICROCHIP MCP16502 PMIC DRIVER
++M: Claudiu Beznea <claudiu.beznea@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
++F: drivers/regulator/mcp16502.c
++
++MICROCHIP MCP3911 ADC DRIVER
++M: Marcus Folkesson <marcus.folkesson@gmail.com>
++M: Kent Gustavsson <kent@minoris.se>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
++F: drivers/iio/adc/mcp3911.c
++
++MICROCHIP MMC/SD/SDIO MCI DRIVER
++M: Ludovic Desroches <ludovic.desroches@microchip.com>
++S: Maintained
++F: drivers/mmc/host/atmel-mci.c
++
++MICROCHIP NAND DRIVER
++M: Tudor Ambarus <tudor.ambarus@microchip.com>
++L: linux-mtd@lists.infradead.org
++S: Supported
++F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
++F: drivers/mtd/nand/raw/atmel/*
++
++MICROCHIP PWM DRIVER
++M: Claudiu Beznea <claudiu.beznea@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-pwm@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pwm/atmel-pwm.txt
++F: drivers/pwm/pwm-atmel.c
++
++MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
++M: Eugen Hristev <eugen.hristev@microchip.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
++F: drivers/iio/adc/at91-sama5d2_adc.c
++F: include/dt-bindings/iio/adc/at91-sama5d2_adc.h
++
++MICROCHIP SAMA5D2-COMPATIBLE SHUTDOWN CONTROLLER
++M: Claudiu Beznea <claudiu.beznea@microchip.com>
++S: Supported
++F: drivers/power/reset/at91-sama5d2_shdwc.c
++
++MICROCHIP SPI DRIVER
++M: Tudor Ambarus <tudor.ambarus@microchip.com>
++S: Supported
++F: drivers/spi/spi-atmel.*
++
++MICROCHIP SSC DRIVER
++M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/misc/atmel-ssc.c
++F: include/linux/atmel-ssc.h
++
++MICROCHIP USB251XB DRIVER
++M: Richard Leitner <richard.leitner@skidata.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/usb/usb251xb.txt
++F: drivers/usb/misc/usb251xb.c
++
++MICROCHIP USBA UDC DRIVER
++M: Cristian Birsan <cristian.birsan@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/usb/gadget/udc/atmel_usba_udc.*
++
++MICROCHIP WILC1000 WIFI DRIVER
++M: Ajay Singh <ajay.kathat@microchip.com>
++M: Claudiu Beznea <claudiu.beznea@microchip.com>
++L: linux-wireless@vger.kernel.org
++S: Supported
++F: drivers/net/wireless/microchip/wilc1000/
++
++MICROSEMI MIPS SOCS
++M: Alexandre Belloni <alexandre.belloni@bootlin.com>
++M: UNGLinuxDriver@microchip.com
++L: linux-mips@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mips/mscc.txt
++F: Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
++F: arch/mips/boot/dts/mscc/
++F: arch/mips/configs/generic/board-ocelot.config
++F: arch/mips/generic/board-ocelot.c
++
++MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi)
++M: Don Brace <don.brace@microchip.com>
++L: storagedev@microchip.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: Documentation/scsi/smartpqi.rst
++F: drivers/scsi/smartpqi/Kconfig
++F: drivers/scsi/smartpqi/Makefile
++F: drivers/scsi/smartpqi/smartpqi*.[ch]
++F: include/linux/cciss*.h
++F: include/uapi/linux/cciss*.h
++
++MICROSOFT SURFACE BATTERY AND AC DRIVERS
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: linux-pm@vger.kernel.org
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/power/supply/surface_battery.c
++F: drivers/power/supply/surface_charger.c
++
++MICROSOFT SURFACE DTX DRIVER
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
++F: drivers/platform/surface/surface_dtx.c
++F: include/uapi/linux/surface_aggregator/dtx.h
++
++MICROSOFT SURFACE GPE LID SUPPORT DRIVER
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/surface/surface_gpe.c
++
++MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
++M: Hans de Goede <hdegoede@redhat.com>
++M: Mark Gross <mgross@linux.intel.com>
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
++F: drivers/platform/surface/
++
++MICROSOFT SURFACE HID TRANSPORT DRIVER
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: linux-input@vger.kernel.org
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/hid/surface-hid/
++
++MICROSOFT SURFACE HOT-PLUG DRIVER
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/surface/surface_hotplug.c
++
++MICROSOFT SURFACE PLATFORM PROFILE DRIVER
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/surface/surface_platform_profile.c
++
++MICROSOFT SURFACE PRO 3 BUTTON DRIVER
++M: Chen Yu <yu.c.chen@intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Supported
++F: drivers/platform/surface/surfacepro3_button.c
++
++MICROSOFT SURFACE SYSTEM AGGREGATOR SUBSYSTEM
++M: Maximilian Luz <luzmaximilian@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: https://github.com/linux-surface/surface-aggregator-module
++C: irc://irc.libera.chat/linux-surface
++F: Documentation/driver-api/surface_aggregator/
++F: drivers/platform/surface/aggregator/
++F: drivers/platform/surface/surface_acpi_notify.c
++F: drivers/platform/surface/surface_aggregator_cdev.c
++F: drivers/platform/surface/surface_aggregator_registry.c
++F: include/linux/surface_acpi_notify.h
++F: include/linux/surface_aggregator/
++F: include/uapi/linux/surface_aggregator/
++
++MICROTEK X6 SCANNER
++M: Oliver Neukum <oliver@neukum.org>
++S: Maintained
++F: drivers/usb/image/microtek.*
++
++MIKROTIK CRS3XX 98DX3236 BOARD SUPPORT
++M: Luka Kovacic <luka.kovacic@sartura.hr>
++M: Luka Perkov <luka.perkov@sartura.hr>
++S: Maintained
++F: arch/arm/boot/dts/armada-xp-crs305-1g-4s-bit.dts
++F: arch/arm/boot/dts/armada-xp-crs305-1g-4s.dts
++F: arch/arm/boot/dts/armada-xp-crs326-24g-2s-bit.dts
++F: arch/arm/boot/dts/armada-xp-crs326-24g-2s.dts
++F: arch/arm/boot/dts/armada-xp-crs328-4c-20s-4s-bit.dts
++F: arch/arm/boot/dts/armada-xp-crs328-4c-20s-4s.dts
++
++MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
++F: Documentation/driver-api/media/drivers/ccs/
++F: Documentation/userspace-api/media/drivers/ccs.rst
++F: drivers/media/i2c/ccs-pll.c
++F: drivers/media/i2c/ccs-pll.h
++F: drivers/media/i2c/ccs/
++F: include/uapi/linux/ccs.h
++F: include/uapi/linux/smiapp.h
++
++MIPS
++M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
++L: linux-mips@vger.kernel.org
++S: Maintained
++W: http://www.linux-mips.org/
++Q: https://patchwork.kernel.org/project/linux-mips/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
++F: Documentation/devicetree/bindings/mips/
++F: Documentation/mips/
++F: arch/mips/
++F: drivers/platform/mips/
++
++MIPS BOSTON DEVELOPMENT BOARD
++M: Paul Burton <paulburton@kernel.org>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/clock/img,boston-clock.txt
++F: arch/mips/boot/dts/img/boston.dts
++F: arch/mips/configs/generic/board-boston.config
++F: drivers/clk/imgtec/clk-boston.c
++F: include/dt-bindings/clock/boston-clock.h
++
++MIPS CORE DRIVERS
++M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
++M: Serge Semin <fancer.lancer@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Supported
++F: drivers/bus/mips_cdmm.c
++F: drivers/clocksource/mips-gic-timer.c
++F: drivers/cpuidle/cpuidle-cps.c
++F: drivers/irqchip/irq-mips-cpu.c
++F: drivers/irqchip/irq-mips-gic.c
++
++MIPS GENERIC PLATFORM
++M: Paul Burton <paulburton@kernel.org>
++L: linux-mips@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/power/mti,mips-cpc.yaml
++F: arch/mips/generic/
++F: arch/mips/tools/generic-board-config.sh
++
++MIPS RINT INSTRUCTION EMULATION
++M: Aleksandar Markovic <aleksandar.markovic@mips.com>
++L: linux-mips@vger.kernel.org
++S: Supported
++F: arch/mips/math-emu/dp_rint.c
++F: arch/mips/math-emu/sp_rint.c
++
++MIPS/LOONGSON1 ARCHITECTURE
++M: Keguang Zhang <keguang.zhang@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/include/asm/mach-loongson32/
++F: arch/mips/loongson32/
++F: drivers/*/*/*loongson1*
++F: drivers/*/*loongson1*
++
++MIPS/LOONGSON2EF ARCHITECTURE
++M: Jiaxun Yang <jiaxun.yang@flygoat.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/include/asm/mach-loongson2ef/
++F: arch/mips/loongson2ef/
++F: drivers/cpufreq/loongson2_cpufreq.c
++
++MIPS/LOONGSON64 ARCHITECTURE
++M: Huacai Chen <chenhuacai@kernel.org>
++M: Jiaxun Yang <jiaxun.yang@flygoat.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/include/asm/mach-loongson64/
++F: arch/mips/loongson64/
++F: drivers/irqchip/irq-loongson*
++F: drivers/platform/mips/cpu_hwmon.c
++
++MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-miropcm20*
++
++MMP SUPPORT
++R: Lubomir Rintel <lkundrak@v3.sk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Odd Fixes
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp.git
++F: arch/arm/boot/dts/mmp*
++F: arch/arm/mach-mmp/
++F: include/linux/soc/mmp/
++
++MMP USB PHY DRIVERS
++R: Lubomir Rintel <lkundrak@v3.sk>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/phy/marvell/phy-mmp3-usb.c
++F: drivers/phy/marvell/phy-pxa-usb.c
++
++MMU GATHER AND TLB INVALIDATION
++M: Will Deacon <will@kernel.org>
++M: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
++M: Andrew Morton <akpm@linux-foundation.org>
++M: Nick Piggin <npiggin@gmail.com>
++M: Peter Zijlstra <peterz@infradead.org>
++L: linux-arch@vger.kernel.org
++L: linux-mm@kvack.org
++S: Maintained
++F: arch/*/include/asm/tlb.h
++F: include/asm-generic/tlb.h
++F: mm/mmu_gather.c
++
++MN88472 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/mn88472*
++
++MN88473 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/mn88473*
++
++MODULE SUPPORT
++M: Luis Chamberlain <mcgrof@kernel.org>
++M: Jessica Yu <jeyu@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next
++F: include/linux/module.h
++F: kernel/module.c
++
++MONOLITHIC POWER SYSTEM PMIC DRIVER
++M: Saravanan Sekar <sravanhome@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
++F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml
++F: drivers/iio/adc/mp2629_adc.c
++F: drivers/mfd/mp2629.c
++F: drivers/power/supply/mp2629_charger.c
++F: drivers/regulator/mp5416.c
++F: drivers/regulator/mpq7920.c
++F: drivers/regulator/mpq7920.h
++F: include/linux/mfd/mp2629.h
++
++MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
++S: Orphan
++W: http://popies.net/meye/
++F: Documentation/userspace-api/media/drivers/meye*
++F: drivers/media/pci/meye/
++F: include/uapi/linux/meye.h
++
++MOTORCOMM PHY DRIVER
++M: Peter Geis <pgwipeout@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/phy/motorcomm.c
++
++MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
++M: Jiri Slaby <jirislaby@kernel.org>
++S: Maintained
++F: Documentation/driver-api/serial/moxa-smartio.rst
++F: drivers/tty/mxser.*
++
++MR800 AVERMEDIA USB FM RADIO DRIVER
++M: Alexey Klimov <klimov.linux@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-mr800.c
++
++MRF24J40 IEEE 802.15.4 RADIO DRIVER
++M: Alan Ott <alan@signal11.us>
++L: linux-wpan@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
++F: drivers/net/ieee802154/mrf24j40.c
++
++MSI LAPTOP SUPPORT
++M: "Lee, Chun-Yi" <jlee@suse.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/msi-laptop.c
++
++MSI WMI SUPPORT
++L: platform-driver-x86@vger.kernel.org
++S: Orphan
++F: drivers/platform/x86/msi-wmi.c
++
++MSI001 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/msi001*
++
++MSI2500 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/usb/msi2500/
++
++MSTAR INTERRUPT CONTROLLER DRIVER
++M: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
++M: Daniel Palmer <daniel@thingy.jp>
++S: Maintained
++F: Documentation/devicetree/bindings/interrupt-controller/mstar,mst-intc.yaml
++F: drivers/irqchip/irq-mst-intc.c
++
++MSYSTEMS DISKONCHIP G3 MTD DRIVER
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: drivers/mtd/devices/docg3*
++
++MT9M032 APTINA SENSOR DRIVER
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/mt9m032.c
++F: include/media/i2c/mt9m032.h
++
++MT9P031 APTINA CAMERA SENSOR
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/mt9p031.c
++F: include/media/i2c/mt9p031.h
++
++MT9T001 APTINA CAMERA SENSOR
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/mt9t001.c
++F: include/media/i2c/mt9t001.h
++
++MT9T112 APTINA CAMERA SENSOR
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/mt9t112.c
++F: include/media/i2c/mt9t112.h
++
++MT9V032 APTINA CAMERA SENSOR
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/mt9v032.txt
++F: drivers/media/i2c/mt9v032.c
++F: include/media/i2c/mt9v032.h
++
++MT9V111 APTINA CAMERA SENSOR
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml
++F: drivers/media/i2c/mt9v111.c
++
++MULTIFUNCTION DEVICES (MFD)
++M: Lee Jones <lee.jones@linaro.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
++F: Documentation/devicetree/bindings/mfd/
++F: drivers/mfd/
++F: include/dt-bindings/mfd/
++F: include/linux/mfd/
++
++MULTIMEDIA CARD (MMC) ETC. OVER SPI
++S: Orphan
++F: drivers/mmc/host/mmc_spi.c
++F: include/linux/spi/mmc_spi.h
++
++MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
++M: Ulf Hansson <ulf.hansson@linaro.org>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
++F: Documentation/devicetree/bindings/mmc/
++F: drivers/mmc/
++F: include/linux/mmc/
++F: include/uapi/linux/mmc/
++
++MULTIPLEXER SUBSYSTEM
++M: Peter Rosin <peda@axentia.se>
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-mux*
++F: Documentation/devicetree/bindings/mux/
++F: drivers/mux/
++F: include/dt-bindings/mux/
++F: include/linux/mux/
++
++MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
++M: Bin Liu <b-liu@ti.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/musb/
++
++MXL301RF MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/tuners/mxl301rf*
++
++MXL5007T MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/tuners/mxl5007t.*
++
++MXSFB DRM DRIVER
++M: Marek Vasut <marex@denx.de>
++M: Stefan Agner <stefan@agner.ch>
++L: dri-devel@lists.freedesktop.org
++S: Supported
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/devicetree/bindings/display/fsl,lcdif.yaml
++F: drivers/gpu/drm/mxsfb/
++
++MYLEX DAC960 PCI RAID Controller
++M: Hannes Reinecke <hare@kernel.org>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/myrb.*
++F: drivers/scsi/myrs.*
++
++MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
++M: Chris Lee <christopher.lee@cspi.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: https://www.cspi.com/ethernet-products/support/downloads/
++F: drivers/net/ethernet/myricom/myri10ge/
++
++NAND FLASH SUBSYSTEM
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++R: Richard Weinberger <richard@nod.at>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++W: http://www.linux-mtd.infradead.org/
++Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
++C: irc://irc.oftc.net/mtd
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
++F: drivers/mtd/nand/
++F: include/linux/mtd/*nand*.h
++
++NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
++M: Daniel Mack <zonque@gmail.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.native-instruments.com
++F: sound/usb/caiaq/
++
++NATSEMI ETHERNET DRIVER (DP8381x)
++S: Orphan
++F: drivers/net/ethernet/natsemi/natsemi.c
++
++NCR 5380 SCSI DRIVERS
++M: Finn Thain <fthain@linux-m68k.org>
++M: Michael Schmitz <schmitzmic@gmail.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: Documentation/scsi/g_NCR5380.rst
++F: drivers/scsi/NCR5380.*
++F: drivers/scsi/arm/cumana_1.c
++F: drivers/scsi/arm/oak.c
++F: drivers/scsi/atari_scsi.*
++F: drivers/scsi/dmx3191d.c
++F: drivers/scsi/g_NCR5380.*
++F: drivers/scsi/mac_scsi.*
++F: drivers/scsi/sun3_scsi.*
++F: drivers/scsi/sun3_scsi_vme.c
++
++NCSI LIBRARY
++M: Samuel Mendoza-Jonas <sam@mendozajonas.com>
++S: Maintained
++F: net/ncsi/
++
++NCT6775 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/nct6775.rst
++F: drivers/hwmon/nct6775.c
++
++NETDEVSIM
++M: Jakub Kicinski <kuba@kernel.org>
++S: Maintained
++F: drivers/net/netdevsim/*
++
++NETEM NETWORK EMULATOR
++M: Stephen Hemminger <stephen@networkplumber.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: net/sched/sch_netem.c
++
++NETERION 10GbE DRIVERS (s2io/vxge)
++M: Jon Mason <jdmason@kudzu.us>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/ethernet/neterion/s2io.rst
++F: Documentation/networking/device_drivers/ethernet/neterion/vxge.rst
++F: drivers/net/ethernet/neterion/
++
++NETFILTER
++M: Pablo Neira Ayuso <pablo@netfilter.org>
++M: Jozsef Kadlecsik <kadlec@netfilter.org>
++M: Florian Westphal <fw@strlen.de>
++L: netfilter-devel@vger.kernel.org
++L: coreteam@netfilter.org
++S: Maintained
++W: http://www.netfilter.org/
++W: http://www.iptables.org/
++W: http://www.nftables.org/
++Q: http://patchwork.ozlabs.org/project/netfilter-devel/list/
++C: irc://irc.libera.chat/netfilter
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
++F: include/linux/netfilter*
++F: include/linux/netfilter/
++F: include/net/netfilter/
++F: include/uapi/linux/netfilter*
++F: include/uapi/linux/netfilter/
++F: net/*/netfilter.c
++F: net/*/netfilter/
++F: net/bridge/br_netfilter*.c
++F: net/netfilter/
++
++NETROM NETWORK LAYER
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://www.linux-ax25.org/
++F: include/net/netrom.h
++F: include/uapi/linux/netrom.h
++F: net/netrom/
++
++NETRONIX EMBEDDED CONTROLLER
++M: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
++S: Maintained
++F: Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
++F: drivers/mfd/ntxec.c
++F: drivers/pwm/pwm-ntxec.c
++F: drivers/rtc/rtc-ntxec.c
++F: include/linux/mfd/ntxec.h
++
++NETRONOME ETHERNET DRIVERS
++M: Simon Horman <simon.horman@corigine.com>
++R: Jakub Kicinski <kuba@kernel.org>
++L: oss-drivers@corigine.com
++S: Maintained
++F: drivers/net/ethernet/netronome/
++
++NETWORK BLOCK DEVICE (NBD)
++M: Josef Bacik <josef@toxicpanda.com>
++L: linux-block@vger.kernel.org
++L: nbd@other.debian.org
++S: Maintained
++F: Documentation/admin-guide/blockdev/nbd.rst
++F: drivers/block/nbd.c
++F: include/trace/events/nbd.h
++F: include/uapi/linux/nbd.h
++
++NETWORK DROP MONITOR
++M: Neil Horman <nhorman@tuxdriver.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: https://fedorahosted.org/dropwatch/
++F: include/uapi/linux/net_dropmon.h
++F: net/core/drop_monitor.c
++
++NETWORKING DRIVERS
++M: "David S. Miller" <davem@davemloft.net>
++M: Jakub Kicinski <kuba@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
++F: Documentation/devicetree/bindings/net/
++F: drivers/connector/
++F: drivers/net/
++F: include/linux/etherdevice.h
++F: include/linux/fcdevice.h
++F: include/linux/fddidevice.h
++F: include/linux/hippidevice.h
++F: include/linux/if_*
++F: include/linux/inetdevice.h
++F: include/linux/netdevice.h
++F: include/uapi/linux/if_*
++F: include/uapi/linux/netdevice.h
++
++NETWORKING DRIVERS (WIRELESS)
++M: Kalle Valo <kvalo@codeaurora.org>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-wireless/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git
++F: Documentation/devicetree/bindings/net/wireless/
++F: drivers/net/wireless/
++
++NETWORKING [DSA]
++M: Andrew Lunn <andrew@lunn.ch>
++M: Vivien Didelot <vivien.didelot@gmail.com>
++M: Florian Fainelli <f.fainelli@gmail.com>
++M: Vladimir Oltean <olteanv@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/
++F: drivers/net/dsa/
++F: include/linux/dsa/
++F: include/linux/platform_data/dsa.h
++F: include/net/dsa.h
++F: net/dsa/
++
++NETWORKING [GENERAL]
++M: "David S. Miller" <davem@davemloft.net>
++M: Jakub Kicinski <kuba@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/netdevbpf/list/
++B: mailto:netdev@vger.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
++F: Documentation/networking/
++F: include/linux/in.h
++F: include/linux/net.h
++F: include/linux/netdevice.h
++F: include/net/
++F: include/uapi/linux/in.h
++F: include/uapi/linux/net.h
++F: include/uapi/linux/net_namespace.h
++F: include/uapi/linux/netdevice.h
++F: lib/net_utils.c
++F: lib/random32.c
++F: net/
++F: tools/testing/selftests/net/
++
++NETWORKING [IPSEC]
++M: Steffen Klassert <steffen.klassert@secunet.com>
++M: Herbert Xu <herbert@gondor.apana.org.au>
++M: "David S. Miller" <davem@davemloft.net>
++L: netdev@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git
++F: include/net/xfrm.h
++F: include/uapi/linux/xfrm.h
++F: net/ipv4/ah4.c
++F: net/ipv4/esp4*
++F: net/ipv4/ip_vti.c
++F: net/ipv4/ipcomp.c
++F: net/ipv4/xfrm*
++F: net/ipv6/ah6.c
++F: net/ipv6/esp6*
++F: net/ipv6/ip6_vti.c
++F: net/ipv6/ipcomp6.c
++F: net/ipv6/xfrm*
++F: net/key/
++F: net/xfrm/
++F: tools/testing/selftests/net/ipsec.c
++
++NETWORKING [IPv4/IPv6]
++M: "David S. Miller" <davem@davemloft.net>
++M: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
++M: David Ahern <dsahern@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
++F: arch/x86/net/*
++F: include/net/ip*
++F: net/ipv4/
++F: net/ipv6/
++
++NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK)
++M: Paul Moore <paul@paul-moore.com>
++L: netdev@vger.kernel.org
++L: linux-security-module@vger.kernel.org
++S: Maintained
++W: https://github.com/netlabel
++F: Documentation/netlabel/
++F: include/net/calipso.h
++F: include/net/cipso_ipv4.h
++F: include/net/netlabel.h
++F: include/uapi/linux/netfilter/xt_CONNSECMARK.h
++F: include/uapi/linux/netfilter/xt_SECMARK.h
++F: net/ipv4/cipso_ipv4.c
++F: net/ipv6/calipso.c
++F: net/netfilter/xt_CONNSECMARK.c
++F: net/netfilter/xt_SECMARK.c
++F: net/netlabel/
++
++NETWORKING [MPTCP]
++M: Mat Martineau <mathew.j.martineau@linux.intel.com>
++M: Matthieu Baerts <matthieu.baerts@tessares.net>
++L: netdev@vger.kernel.org
++L: mptcp@lists.linux.dev
++S: Maintained
++W: https://github.com/multipath-tcp/mptcp_net-next/wiki
++B: https://github.com/multipath-tcp/mptcp_net-next/issues
++F: Documentation/networking/mptcp-sysctl.rst
++F: include/net/mptcp.h
++F: include/trace/events/mptcp.h
++F: include/uapi/linux/mptcp.h
++F: net/mptcp/
++F: tools/testing/selftests/net/mptcp/
++
++NETWORKING [TCP]
++M: Eric Dumazet <edumazet@google.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/linux/tcp.h
++F: include/net/tcp.h
++F: include/trace/events/tcp.h
++F: include/uapi/linux/tcp.h
++F: net/ipv4/syncookies.c
++F: net/ipv4/tcp*.c
++F: net/ipv6/syncookies.c
++F: net/ipv6/tcp*.c
++
++NETWORKING [TLS]
++M: Boris Pismenny <borisp@nvidia.com>
++M: John Fastabend <john.fastabend@gmail.com>
++M: Daniel Borkmann <daniel@iogearbox.net>
++M: Jakub Kicinski <kuba@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/net/tls.h
++F: include/uapi/linux/tls.h
++F: net/tls/*
++
++NETWORKING [WIRELESS]
++L: linux-wireless@vger.kernel.org
++Q: http://patchwork.kernel.org/project/linux-wireless/list/
++
++NETXEN (1/10) GbE SUPPORT
++M: Manish Chopra <manishc@marvell.com>
++M: Rahul Verma <rahulv@marvell.com>
++M: GR-Linux-NIC-Dev@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/qlogic/netxen/
++
++NET_FAILOVER MODULE
++M: Sridhar Samudrala <sridhar.samudrala@intel.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/net_failover.rst
++F: drivers/net/net_failover.c
++F: include/net/net_failover.h
++
++NEXTHOP
++M: David Ahern <dsahern@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/net/netns/nexthop.h
++F: include/net/nexthop.h
++F: include/uapi/linux/nexthop.h
++F: net/ipv4/nexthop.c
++
++NFC SUBSYSTEM
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-nfc@lists.01.org (subscribers-only)
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/nfc/
++F: drivers/nfc/
++F: include/linux/platform_data/nfcmrvl.h
++F: include/net/nfc/
++F: include/uapi/linux/nfc.h
++F: net/nfc/
++
++NFC VIRTUAL NCI DEVICE DRIVER
++M: Bongsu Jeon <bongsu.jeon@samsung.com>
++L: netdev@vger.kernel.org
++L: linux-nfc@lists.01.org (subscribers-only)
++S: Supported
++F: drivers/nfc/virtual_ncidev.c
++F: tools/testing/selftests/nci/
++
++NFS, SUNRPC, AND LOCKD CLIENTS
++M: Trond Myklebust <trond.myklebust@hammerspace.com>
++M: Anna Schumaker <anna.schumaker@netapp.com>
++L: linux-nfs@vger.kernel.org
++S: Maintained
++W: http://client.linux-nfs.org
++T: git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git
++F: fs/lockd/
++F: fs/nfs/
++F: fs/nfs_common/
++F: include/linux/lockd/
++F: include/linux/nfs*
++F: include/linux/sunrpc/
++F: include/uapi/linux/nfs*
++F: include/uapi/linux/sunrpc/
++F: net/sunrpc/
++F: Documentation/filesystems/nfs/
++
++NILFS2 FILESYSTEM
++M: Ryusuke Konishi <konishi.ryusuke@gmail.com>
++L: linux-nilfs@vger.kernel.org
++S: Supported
++W: https://nilfs.sourceforge.io/
++W: https://nilfs.osdn.jp/
++T: git git://github.com/konis/nilfs2.git
++F: Documentation/filesystems/nilfs2.rst
++F: fs/nilfs2/
++F: include/trace/events/nilfs2.h
++F: include/uapi/linux/nilfs2_api.h
++F: include/uapi/linux/nilfs2_ondisk.h
++
++NINJA SCSI-3 / NINJA SCSI-32Bi (16bit/CardBus) PCMCIA SCSI HOST ADAPTER DRIVER
++M: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
++S: Maintained
++W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
++F: Documentation/scsi/NinjaSCSI.rst
++F: drivers/scsi/pcmcia/nsp_*
++
++NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
++M: GOTO Masanori <gotom@debian.or.jp>
++M: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
++S: Maintained
++W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
++F: Documentation/scsi/NinjaSCSI.rst
++F: drivers/scsi/nsp32*
++
++NIOS2 ARCHITECTURE
++M: Dinh Nguyen <dinguyen@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
++F: arch/nios2/
++
++NITRO ENCLAVES (NE)
++M: Andra Paraschiv <andraprs@amazon.com>
++M: Alexandru Vasile <lexnv@amazon.com>
++M: Alexandru Ciobotaru <alcioa@amazon.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++W: https://aws.amazon.com/ec2/nitro/nitro-enclaves/
++F: Documentation/virt/ne_overview.rst
++F: drivers/virt/nitro_enclaves/
++F: include/linux/nitro_enclaves.h
++F: include/uapi/linux/nitro_enclaves.h
++F: samples/nitro_enclaves/
++
++NOHZ, DYNTICKS SUPPORT
++M: Frederic Weisbecker <fweisbec@gmail.com>
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Ingo Molnar <mingo@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/nohz
++F: include/linux/sched/nohz.h
++F: include/linux/tick.h
++F: kernel/time/tick*.*
++
++NOKIA N900 CAMERA SUPPORT (ET8EK8 SENSOR, AD5820 FOCUS)
++M: Pavel Machek <pavel@ucw.cz>
++M: Sakari Ailus <sakari.ailus@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/ad5820.c
++F: drivers/media/i2c/et8ek8
++
++NOKIA N900 POWER SUPPLY DRIVERS
++R: Pali Rohár <pali@kernel.org>
++F: drivers/power/supply/bq2415x_charger.c
++F: drivers/power/supply/bq27xxx_battery.c
++F: drivers/power/supply/bq27xxx_battery_i2c.c
++F: drivers/power/supply/isp1704_charger.c
++F: drivers/power/supply/rx51_battery.c
++F: include/linux/power/bq2415x_charger.h
++F: include/linux/power/bq27xxx_battery.h
++
++NOLIBC HEADER FILE
++M: Willy Tarreau <w@1wt.eu>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git
++F: tools/include/nolibc/
++
++NSDEPS
++M: Matthias Maennich <maennich@google.com>
++S: Maintained
++F: Documentation/core-api/symbol-namespaces.rst
++F: scripts/nsdeps
++
++NTB AMD DRIVER
++M: Sanjay R Mehta <sanju.mehta@amd.com>
++M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
++L: linux-ntb@googlegroups.com
++S: Supported
++F: drivers/ntb/hw/amd/
++
++NTB DRIVER CORE
++M: Jon Mason <jdmason@kudzu.us>
++M: Dave Jiang <dave.jiang@intel.com>
++M: Allen Hubbe <allenbh@gmail.com>
++L: linux-ntb@googlegroups.com
++S: Supported
++W: https://github.com/jonmason/ntb/wiki
++T: git git://github.com/jonmason/ntb.git
++F: drivers/net/ntb_netdev.c
++F: drivers/ntb/
++F: include/linux/ntb.h
++F: include/linux/ntb_transport.h
++F: tools/testing/selftests/ntb/
++
++NTB IDT DRIVER
++M: Serge Semin <fancer.lancer@gmail.com>
++L: linux-ntb@googlegroups.com
++S: Supported
++F: drivers/ntb/hw/idt/
++
++NTB INTEL DRIVER
++M: Dave Jiang <dave.jiang@intel.com>
++L: linux-ntb@googlegroups.com
++S: Supported
++W: https://github.com/davejiang/linux/wiki
++T: git https://github.com/davejiang/linux.git
++F: drivers/ntb/hw/intel/
++
++NTFS FILESYSTEM
++M: Anton Altaparmakov <anton@tuxera.com>
++L: linux-ntfs-dev@lists.sourceforge.net
++S: Supported
++W: http://www.tuxera.com/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git
++F: Documentation/filesystems/ntfs.rst
++F: fs/ntfs/
++
++NTFS3 FILESYSTEM
++M: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
++L: ntfs3@lists.linux.dev
++S: Supported
++W: http://www.paragon-software.com/
++T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git
++F: Documentation/filesystems/ntfs3.rst
++F: fs/ntfs3/
++
++NUBUS SUBSYSTEM
++M: Finn Thain <fthain@linux-m68k.org>
++L: linux-m68k@lists.linux-m68k.org
++S: Maintained
++F: arch/*/include/asm/nubus.h
++F: drivers/nubus/
++F: include/linux/nubus.h
++F: include/uapi/linux/nubus.h
++
++NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
++M: Antonino Daplas <adaplas@gmail.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/nvidia/
++F: drivers/video/fbdev/riva/
++
++NVM EXPRESS DRIVER
++M: Keith Busch <kbusch@kernel.org>
++M: Jens Axboe <axboe@fb.com>
++M: Christoph Hellwig <hch@lst.de>
++M: Sagi Grimberg <sagi@grimberg.me>
++L: linux-nvme@lists.infradead.org
++S: Supported
++W: http://git.infradead.org/nvme.git
++T: git://git.infradead.org/nvme.git
++F: drivers/nvme/host/
++F: include/linux/nvme.h
++F: include/uapi/linux/nvme_ioctl.h
++
++NVM EXPRESS FC TRANSPORT DRIVERS
++M: James Smart <james.smart@broadcom.com>
++L: linux-nvme@lists.infradead.org
++S: Supported
++F: drivers/nvme/host/fc.c
++F: drivers/nvme/target/fc.c
++F: drivers/nvme/target/fcloop.c
++F: include/linux/nvme-fc-driver.h
++F: include/linux/nvme-fc.h
++
++NVM EXPRESS TARGET DRIVER
++M: Christoph Hellwig <hch@lst.de>
++M: Sagi Grimberg <sagi@grimberg.me>
++M: Chaitanya Kulkarni <kch@nvidia.com>
++L: linux-nvme@lists.infradead.org
++S: Supported
++W: http://git.infradead.org/nvme.git
++T: git://git.infradead.org/nvme.git
++F: drivers/nvme/target/
++
++NVMEM FRAMEWORK
++M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git
++F: Documentation/ABI/stable/sysfs-bus-nvmem
++F: Documentation/devicetree/bindings/nvmem/
++F: drivers/nvmem/
++F: include/linux/nvmem-consumer.h
++F: include/linux/nvmem-provider.h
++
++NXP C45 TJA11XX PHY DRIVER
++M: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/phy/nxp-c45-tja11xx.c
++
++NXP FSPI DRIVER
++M: Ashish Kumar <ashish.kumar@nxp.com>
++R: Yogesh Gaur <yogeshgaur.83@gmail.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
++F: drivers/spi/spi-nxp-fspi.c
++
++NXP FXAS21002C DRIVER
++M: Rui Miguel Silva <rmfrfs@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml
++F: drivers/iio/gyro/fxas21002c.h
++F: drivers/iio/gyro/fxas21002c_core.c
++F: drivers/iio/gyro/fxas21002c_i2c.c
++F: drivers/iio/gyro/fxas21002c_spi.c
++
++NXP i.MX CLOCK DRIVERS
++M: Abel Vesa <abel.vesa@nxp.com>
++L: linux-clk@vger.kernel.org
++L: linux-imx@nxp.com
++S: Maintained
++F: drivers/clk/imx/
++
++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 PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
++M: Jagan Teki <jagan@amarulasolutions.com>
++S: Maintained
++F: Documentation/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml
++F: drivers/regulator/pf8x00-regulator.c
++
++NXP PTN5150A CC LOGIC AND EXTCON DRIVER
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml
++F: drivers/extcon/extcon-ptn5150.c
++
++NXP SGTL5000 DRIVER
++M: Fabio Estevam <festevam@gmail.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/sgtl5000.yaml
++F: sound/soc/codecs/sgtl5000*
++
++NXP SJA1105 ETHERNET SWITCH DRIVER
++M: Vladimir Oltean <olteanv@gmail.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/net/dsa/sja1105
++F: drivers/net/pcs/pcs-xpcs-nxp.c
++
++NXP TDA998X DRM DRIVER
++M: Russell King <linux@armlinux.org.uk>
++S: Maintained
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-devel
++T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-fixes
++F: drivers/gpu/drm/i2c/tda998x_drv.c
++F: include/drm/i2c/tda998x.h
++F: include/dt-bindings/display/tda998x.h
++K: "nxp,tda998x"
++
++NXP TFA9879 DRIVER
++M: Peter Rosin <peda@axentia.se>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/tfa9879.txt
++F: sound/soc/codecs/tfa9879*
++
++NXP/Goodix TFA989X (TFA1) DRIVER
++M: Stephan Gerhold <stephan@gerhold.net>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
++F: sound/soc/codecs/tfa989x.c
++
++NXP-NCI NFC DRIVER
++R: Charles Gorand <charles.gorand@effinnov.com>
++L: linux-nfc@lists.01.org (subscribers-only)
++S: Supported
++F: drivers/nfc/nxp-nci
++
++NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER
++M: Mirela Rabulea <mirela.rabulea@nxp.com>
++R: NXP Linux Team <linux-imx@nxp.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/imx8-jpeg.yaml
++F: drivers/media/platform/imx-jpeg
++
++NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
++M: Jonas Malaco <jonas@protocubo.io>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/nzxt-kraken2.rst
++F: drivers/hwmon/nzxt-kraken2.c
++
++OBJAGG
++M: Jiri Pirko <jiri@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: include/linux/objagg.h
++F: lib/objagg.c
++F: lib/test_objagg.c
++
++OBJTOOL
++M: Josh Poimboeuf <jpoimboe@redhat.com>
++M: Peter Zijlstra <peterz@infradead.org>
++S: Supported
++F: tools/objtool/
++F: include/linux/objtool.h
++
++OCELOT ETHERNET SWITCH DRIVER
++M: Vladimir Oltean <vladimir.oltean@nxp.com>
++M: Claudiu Manoil <claudiu.manoil@nxp.com>
++M: Alexandre Belloni <alexandre.belloni@bootlin.com>
++M: UNGLinuxDriver@microchip.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/dsa/ocelot/*
++F: drivers/net/ethernet/mscc/
++F: include/soc/mscc/ocelot*
++F: net/dsa/tag_ocelot.c
++F: net/dsa/tag_ocelot_8021q.c
++F: tools/testing/selftests/drivers/net/ocelot/*
++
++OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
++M: Frederic Barrat <fbarrat@linux.ibm.com>
++M: Andrew Donnellan <ajd@linux.ibm.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: Documentation/userspace-api/accelerators/ocxl.rst
++F: arch/powerpc/include/asm/pnv-ocxl.h
++F: arch/powerpc/platforms/powernv/ocxl.c
++F: drivers/misc/ocxl/
++F: include/misc/ocxl*
++F: include/uapi/misc/ocxl.h
++
++OMAP AUDIO SUPPORT
++M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
++M: Jarkko Nikula <jarkko.nikula@bitmer.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: sound/soc/ti/n810.c
++F: sound/soc/ti/omap*
++F: sound/soc/ti/rx51.c
++F: sound/soc/ti/sdma-pcm.*
++
++OMAP CLOCK FRAMEWORK SUPPORT
++M: Paul Walmsley <paul@pwsan.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/*omap*/*clock*
++
++OMAP DEVICE TREE SUPPORT
++M: Benoît Cousson <bcousson@baylibre.com>
++M: Tony Lindgren <tony@atomide.com>
++L: linux-omap@vger.kernel.org
++L: devicetree@vger.kernel.org
++S: Maintained
++F: arch/arm/boot/dts/*am3*
++F: arch/arm/boot/dts/*am4*
++F: arch/arm/boot/dts/*am5*
++F: arch/arm/boot/dts/*dra7*
++F: arch/arm/boot/dts/*omap*
++F: arch/arm/boot/dts/logicpd-som-lv*
++F: arch/arm/boot/dts/logicpd-torpedo*
++
++OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
++L: linux-omap@vger.kernel.org
++L: linux-fbdev@vger.kernel.org
++S: Orphan
++F: Documentation/arm/omap/dss.rst
++F: drivers/video/fbdev/omap2/
++
++OMAP FRAMEBUFFER SUPPORT
++L: linux-fbdev@vger.kernel.org
++L: linux-omap@vger.kernel.org
++S: Orphan
++F: drivers/video/fbdev/omap/
++
++OMAP GENERAL PURPOSE MEMORY CONTROLLER SUPPORT
++M: Roger Quadros <rogerq@kernel.org>
++M: Tony Lindgren <tony@atomide.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/mach-omap2/*gpmc*
++F: drivers/memory/omap-gpmc.c
++
++OMAP GPIO DRIVER
++M: Grygorii Strashko <grygorii.strashko@ti.com>
++M: Santosh Shilimkar <ssantosh@kernel.org>
++M: Kevin Hilman <khilman@kernel.org>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/ti,omap-gpio.yaml
++F: drivers/gpio/gpio-omap.c
++
++OMAP HARDWARE SPINLOCK SUPPORT
++M: Ohad Ben-Cohen <ohad@wizery.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: drivers/hwspinlock/omap_hwspinlock.c
++
++OMAP HS MMC SUPPORT
++L: linux-mmc@vger.kernel.org
++L: linux-omap@vger.kernel.org
++S: Orphan
++F: drivers/mmc/host/omap_hsmmc.c
++
++OMAP HWMOD DATA
++M: Paul Walmsley <paul@pwsan.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/mach-omap2/omap_hwmod*data*
++
++OMAP HWMOD SUPPORT
++M: Benoît Cousson <bcousson@baylibre.com>
++M: Paul Walmsley <paul@pwsan.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/mach-omap2/omap_hwmod.*
++
++OMAP I2C DRIVER
++M: Vignesh R <vigneshr@ti.com>
++L: linux-omap@vger.kernel.org
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/ti,omap4-i2c.yaml
++F: drivers/i2c/busses/i2c-omap.c
++
++OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/ti,omap3isp.txt
++F: drivers/media/platform/omap3isp/
++F: drivers/staging/media/omap4iss/
++
++OMAP MMC SUPPORT
++M: Aaro Koskinen <aaro.koskinen@iki.fi>
++L: linux-omap@vger.kernel.org
++S: Odd Fixes
++F: drivers/mmc/host/omap.c
++
++OMAP POWER MANAGEMENT SUPPORT
++M: Kevin Hilman <khilman@kernel.org>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/*omap*/*pm*
++F: drivers/cpufreq/omap-cpufreq.c
++
++OMAP POWERDOMAIN SOC ADAPTATION LAYER SUPPORT
++M: Rajendra Nayak <rnayak@codeaurora.org>
++M: Paul Walmsley <paul@pwsan.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/mach-omap2/prm*
++
++OMAP RANDOM NUMBER GENERATOR SUPPORT
++M: Deepak Saxena <dsaxena@plexity.net>
++S: Maintained
++F: drivers/char/hw_random/omap-rng.c
++
++OMAP USB SUPPORT
++L: linux-usb@vger.kernel.org
++L: linux-omap@vger.kernel.org
++S: Orphan
++F: arch/arm/*omap*/usb*
++F: drivers/usb/*/*omap*
++
++OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
++M: Mark Jackson <mpfj@newflow.co.uk>
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: arch/arm/boot/dts/am335x-nano.dts
++
++OMAP1 SUPPORT
++M: Aaro Koskinen <aaro.koskinen@iki.fi>
++M: Tony Lindgren <tony@atomide.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-omap/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
++F: arch/arm/configs/omap1_defconfig
++F: arch/arm/mach-omap1/
++F: arch/arm/plat-omap/
++F: drivers/i2c/busses/i2c-omap.c
++F: include/linux/platform_data/ams-delta-fiq.h
++F: include/linux/platform_data/i2c-omap.h
++
++OMAP2+ SUPPORT
++M: Tony Lindgren <tony@atomide.com>
++L: linux-omap@vger.kernel.org
++S: Maintained
++W: http://www.muru.com/linux/omap/
++W: http://linux.omap.com/
++Q: http://patchwork.kernel.org/project/linux-omap/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
++F: arch/arm/configs/omap2plus_defconfig
++F: arch/arm/mach-omap2/
++F: arch/arm/plat-omap/
++F: drivers/bus/ti-sysc.c
++F: drivers/i2c/busses/i2c-omap.c
++F: drivers/irqchip/irq-omap-intc.c
++F: drivers/mfd/*omap*.c
++F: drivers/mfd/menelaus.c
++F: drivers/mfd/palmas.c
++F: drivers/mfd/tps65217.c
++F: drivers/mfd/tps65218.c
++F: drivers/mfd/tps65910.c
++F: drivers/mfd/twl-core.[ch]
++F: drivers/mfd/twl4030*.c
++F: drivers/mfd/twl6030*.c
++F: drivers/mfd/twl6040*.c
++F: drivers/regulator/palmas-regulator*.c
++F: drivers/regulator/pbias-regulator.c
++F: drivers/regulator/tps65217-regulator.c
++F: drivers/regulator/tps65218-regulator.c
++F: drivers/regulator/tps65910-regulator.c
++F: drivers/regulator/twl-regulator.c
++F: drivers/regulator/twl6030-regulator.c
++F: include/linux/platform_data/i2c-omap.h
++F: include/linux/platform_data/ti-sysc.h
++
++OMFS FILESYSTEM
++M: Bob Copeland <me@bobcopeland.com>
++L: linux-karma-devel@lists.sourceforge.net
++S: Maintained
++F: Documentation/filesystems/omfs.rst
++F: fs/omfs/
++
++OMNIKEY CARDMAN 4000 DRIVER
++M: Harald Welte <laforge@gnumonks.org>
++S: Maintained
++F: drivers/char/pcmcia/cm4000_cs.c
++F: include/linux/cm4000_cs.h
++F: include/uapi/linux/cm4000_cs.h
++
++OMNIKEY CARDMAN 4040 DRIVER
++M: Harald Welte <laforge@gnumonks.org>
++S: Maintained
++F: drivers/char/pcmcia/cm4040_cs.*
++
++OMNIVISION OV02A10 SENSOR DRIVER
++M: Dongchun Zhu <dongchun.zhu@mediatek.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml
++F: drivers/media/i2c/ov02a10.c
++
++OMNIVISION OV13858 SENSOR DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov13858.c
++
++OMNIVISION OV2680 SENSOR DRIVER
++M: Rui Miguel Silva <rmfrfs@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml
++F: drivers/media/i2c/ov2680.c
++
++OMNIVISION OV2685 SENSOR DRIVER
++M: Shunqian Zheng <zhengsq@rock-chips.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov2685.c
++
++OMNIVISION OV2740 SENSOR DRIVER
++M: Tianshu Qiu <tian.shu.qiu@intel.com>
++R: Shawn Tu <shawnx.tu@intel.com>
++R: Bingbu Cao <bingbu.cao@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov2740.c
++
++OMNIVISION OV5640 SENSOR DRIVER
++M: Steve Longerbeam <slongerbeam@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov5640.c
++
++OMNIVISION OV5647 SENSOR DRIVER
++M: Dave Stevenson <dave.stevenson@raspberrypi.com>
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ovti,ov5647.yaml
++F: drivers/media/i2c/ov5647.c
++
++OMNIVISION OV5670 SENSOR DRIVER
++M: Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
++M: Hyungwoo Yang <hyungwoo.yang@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov5670.c
++
++OMNIVISION OV5675 SENSOR DRIVER
++M: Shawn Tu <shawnx.tu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov5675.c
++
++OMNIVISION OV5695 SENSOR DRIVER
++M: Shunqian Zheng <zhengsq@rock-chips.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov5695.c
++
++OMNIVISION OV7670 SENSOR DRIVER
++L: linux-media@vger.kernel.org
++S: Orphan
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ov7670.txt
++F: drivers/media/i2c/ov7670.c
++
++OMNIVISION OV772x SENSOR DRIVER
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml
++F: drivers/media/i2c/ov772x.c
++F: include/media/i2c/ov772x.h
++
++OMNIVISION OV7740 SENSOR DRIVER
++M: Wenyou Yang <wenyou.yang@microchip.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
++F: drivers/media/i2c/ov7740.c
++
++OMNIVISION OV8856 SENSOR DRIVER
++M: Dongchun Zhu <dongchun.zhu@mediatek.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml
++F: drivers/media/i2c/ov8856.c
++
++OMNIVISION OV9282 SENSOR DRIVER
++M: Paul J. Murphy <paul.j.murphy@intel.com>
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml
++F: drivers/media/i2c/ov9282.c
++
++OMNIVISION OV9640 SENSOR DRIVER
++M: Petr Cvek <petrcvekcz@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/ov9640.*
++
++OMNIVISION OV9650 SENSOR DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++R: Akinobu Mita <akinobu.mita@gmail.com>
++R: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/ov9650.txt
++F: drivers/media/i2c/ov9650.c
++
++OMNIVISION OV9734 SENSOR DRIVER
++M: Tianshu Qiu <tian.shu.qiu@intel.com>
++R: Bingbu Cao <bingbu.cao@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/ov9734.c
++
++ONENAND FLASH DRIVER
++M: Kyungmin Park <kyungmin.park@samsung.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: drivers/mtd/nand/onenand/
++F: include/linux/mtd/onenand*.h
++
++ONION OMEGA2+ BOARD
++M: Harvey Hunt <harveyhuntnexus@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/boot/dts/ralink/omega2p.dts
++
++OP-TEE DRIVER
++M: Jens Wiklander <jens.wiklander@linaro.org>
++L: op-tee@lists.trustedfirmware.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-optee-devices
++F: drivers/tee/optee/
++
++OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
++M: Sumit Garg <sumit.garg@linaro.org>
++L: op-tee@lists.trustedfirmware.org
++S: Maintained
++F: drivers/char/hw_random/optee-rng.c
++
++OPA-VNIC DRIVER
++M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
++M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/ulp/opa_vnic
++
++OPEN FIRMWARE AND DEVICE TREE OVERLAYS
++M: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
++M: Frank Rowand <frowand.list@gmail.com>
++L: devicetree@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/dynamic-resolution-notes.rst
++F: Documentation/devicetree/overlay-notes.rst
++F: drivers/of/overlay.c
++F: drivers/of/resolver.c
++K: of_overlay_notifier_
++
++OPEN FIRMWARE AND FLATTENED DEVICE TREE
++M: Rob Herring <robh+dt@kernel.org>
++M: Frank Rowand <frowand.list@gmail.com>
++L: devicetree@vger.kernel.org
++S: Maintained
++W: http://www.devicetree.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
++F: Documentation/ABI/testing/sysfs-firmware-ofw
++F: drivers/of/
++F: include/linux/of*.h
++F: scripts/dtc/
++
++OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
++M: Rob Herring <robh+dt@kernel.org>
++L: devicetree@vger.kernel.org
++S: Maintained
++Q: http://patchwork.ozlabs.org/project/devicetree-bindings/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
++F: Documentation/devicetree/
++F: arch/*/boot/dts/
++F: include/dt-bindings/
++
++OPENCOMPUTE PTP CLOCK DRIVER
++M: Jonathan Lemon <jonathan.lemon@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/ptp/ptp_ocp.c
++
++OPENCORES I2C BUS DRIVER
++M: Peter Korsgaard <peter@korsgaard.com>
++M: Andrew Lunn <andrew@lunn.ch>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-ocores.txt
++F: Documentation/i2c/busses/i2c-ocores.rst
++F: drivers/i2c/busses/i2c-ocores.c
++F: include/linux/platform_data/i2c-ocores.h
++
++OPENRISC ARCHITECTURE
++M: Jonas Bonn <jonas@southpole.se>
++M: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
++M: Stafford Horne <shorne@gmail.com>
++L: openrisc@lists.librecores.org
++S: Maintained
++W: http://openrisc.io
++T: git git://github.com/openrisc/linux.git
++F: Documentation/devicetree/bindings/openrisc/
++F: Documentation/openrisc/
++F: arch/openrisc/
++F: drivers/irqchip/irq-ompic.c
++F: drivers/irqchip/irq-or1k-*
++
++OPENVSWITCH
++M: Pravin B Shelar <pshelar@ovn.org>
++L: netdev@vger.kernel.org
++L: dev@openvswitch.org
++S: Maintained
++W: http://openvswitch.org
++F: include/uapi/linux/openvswitch.h
++F: net/openvswitch/
++
++OPERATING PERFORMANCE POINTS (OPP)
++M: Viresh Kumar <vireshk@kernel.org>
++M: Nishanth Menon <nm@ti.com>
++M: Stephen Boyd <sboyd@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git
++F: Documentation/devicetree/bindings/opp/
++F: Documentation/power/opp.rst
++F: drivers/opp/
++F: include/linux/pm_opp.h
++
++OPL4 DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: sound/drivers/opl4/
++
++ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
++M: Mark Fasheh <mark@fasheh.com>
++M: Joel Becker <jlbec@evilplan.org>
++M: Joseph Qi <joseph.qi@linux.alibaba.com>
++L: ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
++S: Supported
++W: http://ocfs2.wiki.kernel.org
++F: Documentation/filesystems/dlmfs.rst
++F: Documentation/filesystems/ocfs2.rst
++F: fs/ocfs2/
++
++ORANGEFS FILESYSTEM
++M: Mike Marshall <hubcap@omnibond.com>
++R: Martin Brandenburg <martin@omnibond.com>
++L: devel@lists.orangefs.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
++F: Documentation/filesystems/orangefs.rst
++F: fs/orangefs/
++
++ORINOCO DRIVER
++L: linux-wireless@vger.kernel.org
++S: Orphan
++W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco
++W: http://www.nongnu.org/orinoco/
++F: drivers/net/wireless/intersil/orinoco/
++
++OV2659 OMNIVISION SENSOR DRIVER
++M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
++F: drivers/media/i2c/ov2659.c
++F: include/media/i2c/ov2659.h
++
++OVERLAY FILESYSTEM
++M: Miklos Szeredi <miklos@szeredi.hu>
++L: linux-unionfs@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
++F: Documentation/filesystems/overlayfs.rst
++F: fs/overlayfs/
++
++P54 WIRELESS DRIVER
++M: Christian Lamparter <chunkeey@googlemail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/en/users/Drivers/p54
++F: drivers/net/wireless/intersil/p54/
++
++PACKING
++M: Vladimir Oltean <olteanv@gmail.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/core-api/packing.rst
++F: include/linux/packing.h
++F: lib/packing.c
++
++PADATA PARALLEL EXECUTION MECHANISM
++M: Steffen Klassert <steffen.klassert@secunet.com>
++M: Daniel Jordan <daniel.m.jordan@oracle.com>
++L: linux-crypto@vger.kernel.org
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/core-api/padata.rst
++F: include/linux/padata.h
++F: kernel/padata.c
++
++PAGE POOL
++M: Jesper Dangaard Brouer <hawk@kernel.org>
++M: Ilias Apalodimas <ilias.apalodimas@linaro.org>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/page_pool.rst
++F: include/net/page_pool.h
++F: include/trace/events/page_pool.h
++F: net/core/page_pool.c
++
++PANASONIC LAPTOP ACPI EXTRAS DRIVER
++M: Kenneth Chan <kenneth.t.chan@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/panasonic-laptop.c
++
++PARALLAX PING IIO SENSOR DRIVER
++M: Andreas Klinger <ak@it-klinger.de>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/proximity/parallax-ping.yaml
++F: drivers/iio/proximity/ping.c
++
++PARALLEL LCD/KEYPAD PANEL DRIVER
++M: Willy Tarreau <willy@haproxy.com>
++M: Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
++S: Odd Fixes
++F: Documentation/admin-guide/lcd-panel-cgram.rst
++F: drivers/auxdisplay/panel.c
++
++PARALLEL PORT SUBSYSTEM
++M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
++M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
++L: linux-parport@lists.infradead.org (subscribers-only)
++S: Maintained
++F: Documentation/driver-api/parport*.rst
++F: drivers/char/ppdev.c
++F: drivers/parport/
++F: include/linux/parport*.h
++F: include/uapi/linux/ppdev.h
++
++PARAVIRT_OPS INTERFACE
++M: Juergen Gross <jgross@suse.com>
++M: Deep Shah <sdeep@vmware.com>
++M: "VMware, Inc." <pv-drivers@vmware.com>
++L: virtualization@lists.linux-foundation.org
++S: Supported
++F: Documentation/virt/paravirt_ops.rst
++F: arch/*/include/asm/paravirt*.h
++F: arch/*/kernel/paravirt*
++F: include/linux/hypervisor.h
++
++PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
++M: Tim Waugh <tim@cyberelk.net>
++L: linux-parport@lists.infradead.org (subscribers-only)
++S: Maintained
++F: Documentation/admin-guide/blockdev/paride.rst
++F: drivers/block/paride/
++
++PARISC ARCHITECTURE
++M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
++M: Helge Deller <deller@gmx.de>
++L: linux-parisc@vger.kernel.org
++S: Maintained
++W: https://parisc.wiki.kernel.org
++Q: http://patchwork.kernel.org/project/linux-parisc/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git
++F: Documentation/parisc/
++F: arch/parisc/
++F: drivers/char/agp/parisc-agp.c
++F: drivers/input/misc/hp_sdc_rtc.c
++F: drivers/input/serio/gscps2.c
++F: drivers/input/serio/hp_sdc*
++F: drivers/parisc/
++F: drivers/parport/parport_gsc.*
++F: drivers/tty/serial/8250/8250_gsc.c
++F: drivers/video/console/sti*
++F: drivers/video/fbdev/sti*
++F: drivers/video/logo/logo_parisc*
++F: include/linux/hp_sdc.h
++
++PARMAN
++M: Jiri Pirko <jiri@nvidia.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: include/linux/parman.h
++F: lib/parman.c
++F: lib/test_parman.c
++
++PC ENGINES APU BOARD DRIVER
++M: Enrico Weigelt, metux IT consult <info@metux.net>
++S: Maintained
++F: drivers/platform/x86/pcengines-apuv2.c
++
++PC87360 HARDWARE MONITORING DRIVER
++M: Jim Cromie <jim.cromie@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/pc87360.rst
++F: drivers/hwmon/pc87360.c
++
++PC8736x GPIO DRIVER
++M: Jim Cromie <jim.cromie@gmail.com>
++S: Maintained
++F: drivers/char/pc8736x_gpio.c
++
++PC87427 HARDWARE MONITORING DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/pc87427.rst
++F: drivers/hwmon/pc87427.c
++
++PCA9532 LED DRIVER
++M: Riku Voipio <riku.voipio@iki.fi>
++S: Maintained
++F: drivers/leds/leds-pca9532.c
++F: include/linux/leds-pca9532.h
++
++PCA9541 I2C BUS MASTER SELECTOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/muxes/i2c-mux-pca9541.c
++
++PCDP - PRIMARY CONSOLE AND DEBUG PORT
++M: Khalid Aziz <khalid@gonehiking.org>
++S: Maintained
++F: drivers/firmware/pcdp.*
++
++PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
++M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
++M: Pali Rohár <pali@kernel.org>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/aardvark-pci.txt
++F: drivers/pci/controller/pci-aardvark.c
++
++PCI DRIVER FOR ALTERA PCIE IP
++M: Joyce Ooi <joyce.ooi@intel.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/altera-pcie.txt
++F: drivers/pci/controller/pcie-altera.c
++
++PCI DRIVER FOR APPLIEDMICRO XGENE
++M: Toan Le <toan@os.amperecomputing.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/xgene-pci.txt
++F: drivers/pci/controller/pci-xgene.c
++
++PCI DRIVER FOR ARM VERSATILE PLATFORM
++M: Rob Herring <robh@kernel.org>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/versatile.yaml
++F: drivers/pci/controller/pci-versatile.c
++
++PCI DRIVER FOR ARMADA 8K
++M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/pci-armada8k.txt
++F: drivers/pci/controller/dwc/pcie-armada8k.c
++
++PCI DRIVER FOR CADENCE PCIE IP
++M: Tom Joseph <tjoseph@cadence.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/cdns,*
++F: drivers/pci/controller/cadence/
++
++PCI DRIVER FOR FREESCALE LAYERSCAPE
++M: Minghuan Lian <minghuan.Lian@nxp.com>
++M: Mingkai Hu <mingkai.hu@nxp.com>
++M: Roy Zang <roy.zang@nxp.com>
++L: linuxppc-dev@lists.ozlabs.org
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/pci/controller/dwc/*layerscape*
++
++PCI DRIVER FOR GENERIC OF HOSTS
++M: Will Deacon <will@kernel.org>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/host-generic-pci.yaml
++F: drivers/pci/controller/pci-host-common.c
++F: drivers/pci/controller/pci-host-generic.c
++
++PCI DRIVER FOR IMX6
++M: Richard Zhu <hongxing.zhu@nxp.com>
++M: Lucas Stach <l.stach@pengutronix.de>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
++F: drivers/pci/controller/dwc/*imx6*
++
++PCI DRIVER FOR FU740
++M: Paul Walmsley <paul.walmsley@sifive.com>
++M: Greentime Hu <greentime.hu@sifive.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
++F: drivers/pci/controller/dwc/pcie-fu740.c
++
++PCI DRIVER FOR INTEL IXP4XX
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++F: Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml
++F: drivers/pci/controller/pci-ixp4xx.c
++
++PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
++M: Nirmal Patel <nirmal.patel@linux.intel.com>
++R: Jonathan Derrick <jonathan.derrick@linux.dev>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: drivers/pci/controller/vmd.c
++
++PCI DRIVER FOR MICROSEMI SWITCHTEC
++M: Kurt Schwemmer <kurt.schwemmer@microsemi.com>
++M: Logan Gunthorpe <logang@deltatee.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-switchtec
++F: Documentation/driver-api/switchtec.rst
++F: drivers/ntb/hw/mscc/
++F: drivers/pci/switch/switchtec*
++F: include/linux/switchtec.h
++F: include/uapi/linux/switchtec_ioctl.h
++
++PCI DRIVER FOR MOBIVEIL PCIE IP
++M: Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
++M: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
++F: drivers/pci/controller/mobiveil/pcie-mobiveil*
++
++PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
++M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/pci/controller/*mvebu*
++
++PCI DRIVER FOR NVIDIA TEGRA
++M: Thierry Reding <thierry.reding@gmail.com>
++L: linux-tegra@vger.kernel.org
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
++F: drivers/pci/controller/pci-tegra.c
++
++PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER
++M: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
++F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
++
++PCI DRIVER FOR RENESAS R-CAR
++M: Marek Vasut <marek.vasut+renesas@gmail.com>
++M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
++L: linux-pci@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/*rcar*
++F: drivers/pci/controller/*rcar*
++
++PCI DRIVER FOR SAMSUNG EXYNOS
++M: Jingoo Han <jingoohan1@gmail.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: drivers/pci/controller/dwc/pci-exynos.c
++
++PCI DRIVER FOR SYNOPSYS DESIGNWARE
++M: Jingoo Han <jingoohan1@gmail.com>
++M: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
++F: Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
++F: drivers/pci/controller/dwc/*designware*
++
++PCI DRIVER FOR TI DRA7XX/J721E
++M: Kishon Vijay Abraham I <kishon@ti.com>
++L: linux-omap@vger.kernel.org
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/pci/ti-pci.txt
++F: drivers/pci/controller/cadence/pci-j721e.c
++F: drivers/pci/controller/dwc/pci-dra7xx.c
++
++PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
++F: drivers/pci/controller/pci-v3-semi.c
++
++PCI ENDPOINT SUBSYSTEM
++M: Kishon Vijay Abraham I <kishon@ti.com>
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++R: Krzysztof Wilczyński <kw@linux.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/PCI/endpoint/*
++F: Documentation/misc-devices/pci-endpoint-test.rst
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
++F: drivers/misc/pci_endpoint_test.c
++F: drivers/pci/endpoint/
++F: tools/pci/
++
++PCI ENHANCED ERROR HANDLING (EEH) FOR POWERPC
++M: Russell Currey <ruscur@russell.cc>
++M: Oliver O'Halloran <oohall@gmail.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++F: Documentation/PCI/pci-error-recovery.rst
++F: Documentation/powerpc/eeh-pci-error-recovery.rst
++F: arch/powerpc/include/*/eeh*.h
++F: arch/powerpc/kernel/eeh*.c
++F: arch/powerpc/platforms/*/eeh*.c
++F: drivers/pci/pcie/aer.c
++F: drivers/pci/pcie/dpc.c
++F: drivers/pci/pcie/err.c
++
++PCI ERROR RECOVERY
++M: Linas Vepstas <linasvepstas@gmail.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/PCI/pci-error-recovery.rst
++
++PCI MSI DRIVER FOR ALTERA MSI IP
++M: Joyce Ooi <joyce.ooi@intel.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
++F: drivers/pci/controller/pcie-altera-msi.c
++
++PCI MSI DRIVER FOR APPLIEDMICRO XGENE
++M: Toan Le <toan@os.amperecomputing.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
++F: drivers/pci/controller/pci-xgene-msi.c
++
++PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++R: Rob Herring <robh@kernel.org>
++R: Krzysztof Wilczyński <kw@linux.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++Q: http://patchwork.ozlabs.org/project/linux-pci/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
++F: drivers/pci/controller/
++
++PCI SUBSYSTEM
++M: Bjorn Helgaas <bhelgaas@google.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++Q: http://patchwork.ozlabs.org/project/linux-pci/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
++F: Documentation/PCI/
++F: Documentation/devicetree/bindings/pci/
++F: arch/x86/kernel/early-quirks.c
++F: arch/x86/kernel/quirks.c
++F: arch/x86/pci/
++F: drivers/acpi/pci*
++F: drivers/pci/
++F: include/asm-generic/pci*
++F: include/linux/of_pci.h
++F: include/linux/pci*
++F: include/uapi/linux/pci*
++F: lib/pci*
++
++PCIE DRIVER FOR AMAZON ANNAPURNA LABS
++M: Jonathan Chocron <jonnyc@amazon.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/pcie-al.txt
++F: drivers/pci/controller/dwc/pcie-al.c
++
++PCIE DRIVER FOR AMLOGIC MESON
++M: Yue Wang <yue.wang@Amlogic.com>
++L: linux-pci@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Maintained
++F: drivers/pci/controller/dwc/pci-meson.c
++
++PCIE DRIVER FOR AXIS ARTPEC
++M: Jesper Nilsson <jesper.nilsson@axis.com>
++L: linux-arm-kernel@axis.com
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/axis,artpec*
++F: drivers/pci/controller/dwc/*artpec*
++
++PCIE DRIVER FOR CAVIUM THUNDERX
++M: Robert Richter <rric@kernel.org>
++L: linux-pci@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Odd Fixes
++F: drivers/pci/controller/pci-thunder-*
++
++PCIE DRIVER FOR HISILICON
++M: Zhou Wang <wangzhou1@hisilicon.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: drivers/pci/controller/dwc/pcie-hisi.c
++
++PCIE DRIVER FOR HISILICON KIRIN
++M: Xiaowei Song <songxiaowei@hisilicon.com>
++M: Binghui Wang <wangbinghui@hisilicon.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
++F: drivers/pci/controller/dwc/pcie-kirin.c
++
++PCIE DRIVER FOR HISILICON STB
++M: Shawn Guo <shawn.guo@linaro.org>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt
++F: drivers/pci/controller/dwc/pcie-histb.c
++
++PCIE DRIVER FOR INTEL KEEM BAY
++M: Srikanth Thokala <srikanth.thokala@intel.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/intel,keembay-pcie*
++F: drivers/pci/controller/dwc/pcie-keembay.c
++
++PCIE DRIVER FOR INTEL LGM GW SOC
++M: Rahul Tanwar <rtanwar@maxlinear.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/intel-gw-pcie.yaml
++F: drivers/pci/controller/dwc/pcie-intel-gw.c
++
++PCIE DRIVER FOR MEDIATEK
++M: Ryder Lee <ryder.lee@mediatek.com>
++M: Jianjun Wang <jianjun.wang@mediatek.com>
++L: linux-pci@vger.kernel.org
++L: linux-mediatek@lists.infradead.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/mediatek*
++F: drivers/pci/controller/*mediatek*
++
++PCIE DRIVER FOR MICROCHIP
++M: Daire McNamara <daire.mcnamara@microchip.com>
++L: linux-pci@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/pci/microchip*
++F: drivers/pci/controller/*microchip*
++
++PCIE DRIVER FOR QUALCOMM MSM
++M: Stanimir Varbanov <svarbanov@mm-sol.com>
++L: linux-pci@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: drivers/pci/controller/dwc/*qcom*
++
++PCIE DRIVER FOR ROCKCHIP
++M: Shawn Lin <shawn.lin@rock-chips.com>
++L: linux-pci@vger.kernel.org
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/rockchip-pcie*
++F: drivers/pci/controller/pcie-rockchip*
++
++PCIE DRIVER FOR SOCIONEXT UNIPHIER
++M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pci/uniphier-pcie*
++F: drivers/pci/controller/dwc/pcie-uniphier*
++
++PCIE DRIVER FOR ST SPEAR13XX
++M: Pratyush Anand <pratyush.anand@gmail.com>
++L: linux-pci@vger.kernel.org
++S: Maintained
++F: drivers/pci/controller/dwc/*spear*
++
++PCMCIA SUBSYSTEM
++M: Dominik Brodowski <linux@dominikbrodowski.net>
++S: Odd Fixes
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git
++F: Documentation/pcmcia/
++F: drivers/pcmcia/
++F: include/pcmcia/
++F: tools/pcmcia/
++
++PCNET32 NETWORK DRIVER
++M: Don Fry <pcnet32@frontier.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/amd/pcnet32.c
++
++PCRYPT PARALLEL CRYPTO ENGINE
++M: Steffen Klassert <steffen.klassert@secunet.com>
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: crypto/pcrypt.c
++F: include/crypto/pcrypt.h
++
++PEAQ WMI HOTKEYS DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/peaq-wmi.c
++
++PENSANDO ETHERNET DRIVERS
++M: Shannon Nelson <snelson@pensando.io>
++M: drivers@pensando.io
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/ethernet/pensando/ionic.rst
++F: drivers/net/ethernet/pensando/
++
++PER-CPU MEMORY ALLOCATOR
++M: Dennis Zhou <dennis@kernel.org>
++M: Tejun Heo <tj@kernel.org>
++M: Christoph Lameter <cl@linux.com>
++L: linux-mm@kvack.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
++F: arch/*/include/asm/percpu.h
++F: include/linux/percpu*.h
++F: lib/percpu*.c
++F: mm/percpu*.c
++
++PER-TASK DELAY ACCOUNTING
++M: Balbir Singh <bsingharora@gmail.com>
++S: Maintained
++F: include/linux/delayacct.h
++F: kernel/delayacct.c
++
++PERFORMANCE EVENTS SUBSYSTEM
++M: Peter Zijlstra <peterz@infradead.org>
++M: Ingo Molnar <mingo@redhat.com>
++M: Arnaldo Carvalho de Melo <acme@kernel.org>
++R: Mark Rutland <mark.rutland@arm.com>
++R: Alexander Shishkin <alexander.shishkin@linux.intel.com>
++R: Jiri Olsa <jolsa@redhat.com>
++R: Namhyung Kim <namhyung@kernel.org>
++L: linux-perf-users@vger.kernel.org
++L: linux-kernel@vger.kernel.org
++S: Supported
++W: https://perf.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
++F: arch/*/events/*
++F: arch/*/events/*/*
++F: arch/*/include/asm/perf_event.h
++F: arch/*/kernel/*/*/perf_event*.c
++F: arch/*/kernel/*/perf_event*.c
++F: arch/*/kernel/perf_callchain.c
++F: arch/*/kernel/perf_event*.c
++F: include/linux/perf_event.h
++F: include/uapi/linux/perf_event.h
++F: kernel/events/*
++F: tools/lib/perf/
++F: tools/perf/
++
++PERFORMANCE EVENTS TOOLING ARM64
++R: John Garry <john.garry@huawei.com>
++R: Will Deacon <will@kernel.org>
++R: Mathieu Poirier <mathieu.poirier@linaro.org>
++R: Leo Yan <leo.yan@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: tools/build/feature/test-libopencsd.c
++F: tools/perf/arch/arm*/
++F: tools/perf/pmu-events/arch/arm64/
++F: tools/perf/util/arm-spe*
++F: tools/perf/util/cs-etm*
++
++PERSONALITY HANDLING
++M: Christoph Hellwig <hch@infradead.org>
++L: linux-abi-devel@lists.sourceforge.net
++S: Maintained
++F: include/linux/personality.h
++F: include/uapi/linux/personality.h
++
++PHOENIX RC FLIGHT CONTROLLER ADAPTER
++M: Marcus Folkesson <marcus.folkesson@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/input/devices/pxrc.rst
++F: drivers/input/joystick/pxrc.c
++
++PHONET PROTOCOL
++M: Remi Denis-Courmont <courmisch@gmail.com>
++S: Supported
++F: Documentation/networking/phonet.rst
++F: include/linux/phonet.h
++F: include/net/phonet/
++F: include/uapi/linux/phonet.h
++F: net/phonet/
++
++PHRAM MTD DRIVER
++M: Joern Engel <joern@lazybastard.org>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++F: drivers/mtd/devices/phram.c
++
++PICOLCD HID DRIVER
++M: Bruno Prémont <bonbons@linux-vserver.org>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-picolcd*
++
++PIDFD API
++M: Christian Brauner <christian@brauner.io>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
++F: samples/pidfd/
++F: tools/testing/selftests/clone3/
++F: tools/testing/selftests/pid_namespace/
++F: tools/testing/selftests/pidfd/
++K: (?i)pidfd
++K: (?i)clone3
++K: \b(clone_args|kernel_clone_args)\b
++
++PIN CONTROL SUBSYSTEM
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
++F: Documentation/devicetree/bindings/pinctrl/
++F: Documentation/driver-api/pin-control.rst
++F: drivers/pinctrl/
++F: include/linux/pinctrl/
++
++PIN CONTROLLER - AMD
++M: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
++M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
++S: Maintained
++F: drivers/pinctrl/pinctrl-amd.c
++
++PIN CONTROLLER - FREESCALE
++M: Dong Aisheng <aisheng.dong@nxp.com>
++M: Fabio Estevam <festevam@gmail.com>
++M: Shawn Guo <shawnguo@kernel.org>
++M: Stefan Agner <stefan@agner.ch>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pinctrl/fsl,*
++F: drivers/pinctrl/freescale/
++
++PIN CONTROLLER - INTEL
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++M: Andy Shevchenko <andy@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
++F: drivers/pinctrl/intel/
++
++PIN CONTROLLER - KEEMBAY
++M: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>
++S: Supported
++F: drivers/pinctrl/pinctrl-keembay*
++
++PIN CONTROLLER - MEDIATEK
++M: Sean Wang <sean.wang@kernel.org>
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml
++F: Documentation/devicetree/bindings/pinctrl/mediatek,mt6797-pinctrl.yaml
++F: Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml
++F: Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml
++F: drivers/pinctrl/mediatek/
++
++PIN CONTROLLER - MICROCHIP AT91
++M: Ludovic Desroches <ludovic.desroches@microchip.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-gpio@vger.kernel.org
++S: Supported
++F: drivers/gpio/gpio-sama5d2-piobu.c
++F: drivers/pinctrl/pinctrl-at91*
++
++PIN CONTROLLER - QUALCOMM
++M: Bjorn Andersson <bjorn.andersson@linaro.org>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/pinctrl/qcom,*.txt
++F: drivers/pinctrl/qcom/
++
++PIN CONTROLLER - RENESAS
++M: Geert Uytterhoeven <geert+renesas@glider.be>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-pinctrl
++F: Documentation/devicetree/bindings/pinctrl/renesas,*
++F: drivers/pinctrl/renesas/
++
++PIN CONTROLLER - SAMSUNG
++M: Tomasz Figa <tomasz.figa@gmail.com>
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
++F: Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
++F: drivers/pinctrl/samsung/
++F: include/dt-bindings/pinctrl/samsung.h
++
++PIN CONTROLLER - SINGLE
++M: Tony Lindgren <tony@atomide.com>
++M: Haojian Zhuang <haojian.zhuang@linaro.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: drivers/pinctrl/pinctrl-single.c
++
++PIN CONTROLLER - ST SPEAR
++M: Viresh Kumar <vireshk@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.st.com/spear
++F: drivers/pinctrl/spear/
++
++PKTCDVD DRIVER
++M: linux-block@vger.kernel.org
++S: Orphan
++F: drivers/block/pktcdvd.c
++F: include/linux/pktcdvd.h
++F: include/uapi/linux/pktcdvd.h
++
++PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER
++M: Tomasz Duszynski <tduszyns@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
++F: drivers/iio/chemical/pms7003.c
++
++PLDMFW LIBRARY
++M: Jacob Keller <jacob.e.keller@intel.com>
++S: Maintained
++F: Documentation/driver-api/pldmfw/
++F: include/linux/pldmfw.h
++F: lib/pldmfw/
++
++PLX DMA DRIVER
++M: Logan Gunthorpe <logang@deltatee.com>
++S: Maintained
++F: drivers/dma/plx_dma.c
++
++PM6764TR DRIVER
++M: Charles Hsu <hsu.yungteng@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/pm6764tr.rst
++F: drivers/hwmon/pmbus/pm6764tr.c
++
++PM-GRAPH UTILITY
++M: "Todd E Brandt" <todd.e.brandt@linux.intel.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++W: https://01.org/pm-graph
++B: https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools
++T: git git://github.com/intel/pm-graph
++F: tools/power/pm-graph
++
++PMBUS HARDWARE MONITORING DRIVERS
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++W: http://hwmon.wiki.kernel.org/
++W: http://www.roeck-us.net/linux/drivers/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
++F: Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
++F: Documentation/devicetree/bindings/hwmon/ltc2978.txt
++F: Documentation/devicetree/bindings/hwmon/max31785.txt
++F: Documentation/hwmon/adm1275.rst
++F: Documentation/hwmon/ibm-cffps.rst
++F: Documentation/hwmon/ir35221.rst
++F: Documentation/hwmon/lm25066.rst
++F: Documentation/hwmon/ltc2978.rst
++F: Documentation/hwmon/ltc3815.rst
++F: Documentation/hwmon/max16064.rst
++F: Documentation/hwmon/max20751.rst
++F: Documentation/hwmon/max31785.rst
++F: Documentation/hwmon/max34440.rst
++F: Documentation/hwmon/max8688.rst
++F: Documentation/hwmon/pmbus-core.rst
++F: Documentation/hwmon/pmbus.rst
++F: Documentation/hwmon/tps40422.rst
++F: Documentation/hwmon/ucd9000.rst
++F: Documentation/hwmon/ucd9200.rst
++F: Documentation/hwmon/zl6100.rst
++F: drivers/hwmon/pmbus/
++F: include/linux/pmbus.h
++
++PMC SIERRA MaxRAID DRIVER
++L: linux-scsi@vger.kernel.org
++S: Orphan
++W: http://www.pmc-sierra.com/
++F: drivers/scsi/pmcraid.*
++
++PMC SIERRA PM8001 DRIVER
++M: Jack Wang <jinpu.wang@cloud.ionos.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/pm8001/
++
++PNI RM3100 IIO DRIVER
++M: Song Qiang <songqiang1304521@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.yaml
++F: drivers/iio/magnetometer/rm3100*
++
++PNP SUPPORT
++M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
++L: linux-acpi@vger.kernel.org
++S: Maintained
++F: drivers/pnp/
++F: include/linux/pnp.h
++
++POSIX CLOCKS and TIMERS
++M: Thomas Gleixner <tglx@linutronix.de>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
++F: fs/timerfd.c
++F: include/linux/time_namespace.h
++F: include/linux/timer*
++F: kernel/time/*timer*
++F: kernel/time/namespace.c
++
++POWER MANAGEMENT CORE
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
++F: drivers/base/power/
++F: drivers/powercap/
++F: include/linux/intel_rapl.h
++F: include/linux/pm.h
++F: include/linux/pm_*
++F: include/linux/powercap.h
++F: kernel/configs/nopm.config
++
++DYNAMIC THERMAL POWER MANAGEMENT (DTPM)
++M: Daniel Lezcano <daniel.lezcano@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
++F: drivers/powercap/dtpm*
++F: include/linux/dtpm.h
++
++POWER STATE COORDINATION INTERFACE (PSCI)
++M: Mark Rutland <mark.rutland@arm.com>
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/firmware/psci/
++F: include/linux/psci.h
++F: include/uapi/linux/psci.h
++
++POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
++M: Sebastian Reichel <sre@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
++F: Documentation/ABI/testing/sysfs-class-power
++F: Documentation/devicetree/bindings/power/supply/
++F: drivers/power/supply/
++F: include/linux/power/
++F: include/linux/power_supply.h
++
++POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
++M: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/char/powernv-op-panel.c
++
++PPP OVER ATM (RFC 2364)
++M: Mitchell Blank Jr <mitch@sfgoth.com>
++S: Maintained
++F: include/uapi/linux/atmppp.h
++F: net/atm/pppoatm.c
++
++PPP OVER ETHERNET
++M: Michal Ostrowski <mostrows@earthlink.net>
++S: Maintained
++F: drivers/net/ppp/pppoe.c
++F: drivers/net/ppp/pppox.c
++
++PPP OVER L2TP
++M: James Chapman <jchapman@katalix.com>
++S: Maintained
++F: include/linux/if_pppol2tp.h
++F: include/uapi/linux/if_pppol2tp.h
++F: net/l2tp/l2tp_ppp.c
++
++PPP PROTOCOL DRIVERS AND COMPRESSORS
++M: Paul Mackerras <paulus@samba.org>
++L: linux-ppp@vger.kernel.org
++S: Maintained
++F: drivers/net/ppp/ppp_*
++
++PPS SUPPORT
++M: Rodolfo Giometti <giometti@enneenne.com>
++L: linuxpps@ml.enneenne.com (subscribers-only)
++S: Maintained
++W: http://wiki.enneenne.com/index.php/LinuxPPS_support
++F: Documentation/ABI/testing/sysfs-pps
++F: Documentation/devicetree/bindings/pps/pps-gpio.txt
++F: Documentation/driver-api/pps.rst
++F: drivers/pps/
++F: include/linux/pps*.h
++F: include/uapi/linux/pps.h
++
++PPTP DRIVER
++M: Dmitry Kozlov <xeb@mail.ru>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://sourceforge.net/projects/accel-pptp
++F: drivers/net/ppp/pptp.c
++
++PRESSURE STALL INFORMATION (PSI)
++M: Johannes Weiner <hannes@cmpxchg.org>
++S: Maintained
++F: include/linux/psi*
++F: kernel/sched/psi.c
++
++PRINTK
++M: Petr Mladek <pmladek@suse.com>
++M: Sergey Senozhatsky <senozhatsky@chromium.org>
++R: Steven Rostedt <rostedt@goodmis.org>
++R: John Ogness <john.ogness@linutronix.de>
++S: Maintained
++F: include/linux/printk.h
++F: kernel/printk/
++
++PRINTK INDEXING
++R: Chris Down <chris@chrisdown.name>
++S: Maintained
++F: kernel/printk/index.c
++
++PROC FILESYSTEM
++L: linux-kernel@vger.kernel.org
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: Documentation/filesystems/proc.rst
++F: fs/proc/
++F: include/linux/proc_fs.h
++F: tools/testing/selftests/proc/
++
++PROC SYSCTL
++M: Luis Chamberlain <mcgrof@kernel.org>
++M: Kees Cook <keescook@chromium.org>
++M: Iurii Zaikin <yzaikin@google.com>
++L: linux-kernel@vger.kernel.org
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/proc/proc_sysctl.c
++F: include/linux/sysctl.h
++F: kernel/sysctl-test.c
++F: kernel/sysctl.c
++F: tools/testing/selftests/sysctl/
++
++PS3 NETWORK SUPPORT
++M: Geoff Levand <geoff@infradead.org>
++L: netdev@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/net/ethernet/toshiba/ps3_gelic_net.*
++
++PS3 PLATFORM SUPPORT
++M: Geoff Levand <geoff@infradead.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: arch/powerpc/boot/ps3*
++F: arch/powerpc/include/asm/lv1call.h
++F: arch/powerpc/include/asm/ps3*.h
++F: arch/powerpc/platforms/ps3/
++F: drivers/*/ps3*
++F: drivers/ps3/
++F: drivers/rtc/rtc-ps3.c
++F: drivers/usb/host/*ps3.c
++F: sound/ppc/snd_ps3*
++
++PS3VRAM DRIVER
++M: Jim Paris <jim@jtan.com>
++M: Geoff Levand <geoff@infradead.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: drivers/block/ps3vram.c
++
++PSAMPLE PACKET SAMPLING SUPPORT
++M: Yotam Gigi <yotam.gi@gmail.com>
++S: Maintained
++F: include/net/psample.h
++F: include/uapi/linux/psample.h
++F: net/psample
++
++PSTORE FILESYSTEM
++M: Kees Cook <keescook@chromium.org>
++M: Anton Vorontsov <anton@enomsg.org>
++M: Colin Cross <ccross@android.com>
++M: Tony Luck <tony.luck@intel.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
++F: Documentation/admin-guide/ramoops.rst
++F: Documentation/admin-guide/pstore-blk.rst
++F: Documentation/devicetree/bindings/reserved-memory/ramoops.txt
++F: drivers/acpi/apei/erst.c
++F: drivers/firmware/efi/efi-pstore.c
++F: fs/pstore/
++F: include/linux/pstore*
++K: \b(pstore|ramoops)
++
++PTP HARDWARE CLOCK SUPPORT
++M: Richard Cochran <richardcochran@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://linuxptp.sourceforge.net/
++F: Documentation/ABI/testing/sysfs-ptp
++F: Documentation/driver-api/ptp.rst
++F: drivers/net/phy/dp83640*
++F: drivers/ptp/*
++F: include/linux/ptp_cl*
++
++PTP VIRTUAL CLOCK SUPPORT
++M: Yangbo Lu <yangbo.lu@nxp.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/ptp/ptp_vclock.c
++F: net/ethtool/phc_vclocks.c
++
++PTRACE SUPPORT
++M: Oleg Nesterov <oleg@redhat.com>
++S: Maintained
++F: arch/*/*/ptrace*.c
++F: arch/*/include/asm/ptrace*.h
++F: arch/*/ptrace*.c
++F: include/asm-generic/syscall.h
++F: include/linux/ptrace.h
++F: include/linux/regset.h
++F: include/linux/tracehook.h
++F: include/uapi/linux/ptrace.h
++F: include/uapi/linux/ptrace.h
++F: kernel/ptrace.c
++
++PULSE8-CEC DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/pulse8-cec.rst
++F: drivers/media/cec/usb/pulse8/
++
++PVRUSB2 VIDEO4LINUX DRIVER
++M: Mike Isely <isely@pobox.com>
++L: pvrusb2@isely.net (subscribers-only)
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://www.isely.net/pvrusb2/
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/driver-api/media/drivers/pvrusb2*
++F: drivers/media/usb/pvrusb2/
++
++PWC WEBCAM DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/pwc/*
++F: include/trace/events/pwc.h
++
++PWM FAN DRIVER
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/hwmon/pwm-fan.txt
++F: Documentation/hwmon/pwm-fan.rst
++F: drivers/hwmon/pwm-fan.c
++
++PWM IR Transmitter
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/pwm-ir-tx.c
++
++PWM SUBSYSTEM
++M: Thierry Reding <thierry.reding@gmail.com>
++R: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
++M: Lee Jones <lee.jones@linaro.org>
++L: linux-pwm@vger.kernel.org
++S: Maintained
++Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
++F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
++F: Documentation/devicetree/bindings/pwm/
++F: Documentation/driver-api/pwm.rst
++F: drivers/gpio/gpio-mvebu.c
++F: drivers/pwm/
++F: drivers/video/backlight/pwm_bl.c
++F: include/linux/pwm.h
++F: include/linux/pwm_backlight.h
++K: pwm_(config|apply_state|ops)
++
++PXA GPIO DRIVER
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-pxa.c
++
++PXA MMCI DRIVER
++S: Orphan
++
++PXA RTC DRIVER
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-rtc@vger.kernel.org
++S: Maintained
++
++PXA2xx/PXA3xx SUPPORT
++M: Daniel Mack <daniel@zonque.org>
++M: Haojian Zhuang <haojian.zhuang@gmail.com>
++M: Robert Jarzmik <robert.jarzmik@free.fr>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://github.com/hzhuang1/linux.git
++T: git git://github.com/rjarzmik/linux.git
++F: arch/arm/boot/dts/pxa*
++F: arch/arm/mach-pxa/
++F: drivers/dma/pxa*
++F: drivers/pcmcia/pxa2xx*
++F: drivers/pinctrl/pxa/
++F: drivers/spi/spi-pxa2xx*
++F: drivers/usb/gadget/udc/pxa2*
++F: include/sound/pxa2xx-lib.h
++F: sound/arm/pxa*
++F: sound/soc/pxa/
++
++QAT DRIVER
++M: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
++L: qat-linux@intel.com
++S: Supported
++F: drivers/crypto/qat/
++
++QCOM AUDIO (ASoC) DRIVERS
++M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
++M: Banajit Goswami <bgoswami@codeaurora.org>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++F: sound/soc/codecs/lpass-va-macro.c
++F: sound/soc/codecs/lpass-wsa-macro.*
++F: sound/soc/codecs/msm8916-wcd-analog.c
++F: sound/soc/codecs/msm8916-wcd-digital.c
++F: sound/soc/codecs/wcd9335.*
++F: sound/soc/codecs/wcd934x.c
++F: sound/soc/codecs/wcd-clsh-v2.*
++F: sound/soc/codecs/wsa881x.c
++F: sound/soc/qcom/
++
++QCOM IPA DRIVER
++M: Alex Elder <elder@kernel.org>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ipa/
++
++QEMU MACHINE EMULATOR AND VIRTUALIZER SUPPORT
++M: Gabriel Somlo <somlo@cmu.edu>
++M: "Michael S. Tsirkin" <mst@redhat.com>
++L: qemu-devel@nongnu.org
++S: Maintained
++F: drivers/firmware/qemu_fw_cfg.c
++F: include/uapi/linux/qemu_fw_cfg.h
++
++QIB DRIVER
++M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
++M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/hw/qib/
++
++QLOGIC QL41xxx FCOE DRIVER
++M: Saurav Kashyap <skashyap@marvell.com>
++M: Javed Hasan <jhasan@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/qedf/
++
++QLOGIC QL41xxx ISCSI DRIVER
++M: Nilesh Javali <njavali@marvell.com>
++M: Manish Rangankar <mrangankar@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/qedi/
++
++QLOGIC QL4xxx ETHERNET DRIVER
++M: Ariel Elior <aelior@marvell.com>
++M: GR-everest-linux-l2@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/qlogic/qed/
++F: drivers/net/ethernet/qlogic/qede/
++F: include/linux/qed/
++
++QLOGIC QL4xxx RDMA DRIVER
++M: Michal Kalderon <mkalderon@marvell.com>
++M: Ariel Elior <aelior@marvell.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/hw/qedr/
++F: include/uapi/rdma/qedr-abi.h
++
++QLOGIC QLA1280 SCSI DRIVER
++M: Michael Reed <mdr@sgi.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/qla1280.[ch]
++
++QLOGIC QLA2XXX FC-SCSI DRIVER
++M: Nilesh Javali <njavali@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/qla2xxx/
++
++QLOGIC QLA3XXX NETWORK DRIVER
++M: GR-Linux-NIC-Dev@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/qlogic/qla3xxx.*
++
++QLOGIC QLA4XXX iSCSI DRIVER
++M: Nilesh Javali <njavali@marvell.com>
++M: Manish Rangankar <mrangankar@marvell.com>
++M: GR-QLogic-Storage-Upstream@marvell.com
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/qla4xxx/
++
++QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
++M: Shahed Shaikh <shshaikh@marvell.com>
++M: Manish Chopra <manishc@marvell.com>
++M: GR-Linux-NIC-Dev@marvell.com
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/qlogic/qlcnic/
++
++QLOGIC QLGE 10Gb ETHERNET DRIVER
++M: Manish Chopra <manishc@marvell.com>
++M: GR-Linux-NIC-Dev@marvell.com
++M: Coiby Xu <coiby.xu@gmail.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: Documentation/networking/device_drivers/qlogic/qlge.rst
++F: drivers/staging/qlge/
++
++QM1D1B0004 MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/tuners/qm1d1b0004*
++
++QM1D1C0042 MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/tuners/qm1d1c0042*
++
++QNX4 FILESYSTEM
++M: Anders Larsen <al@alarsen.net>
++S: Maintained
++W: http://www.alarsen.net/linux/qnx4fs/
++F: fs/qnx4/
++F: include/uapi/linux/qnx4_fs.h
++F: include/uapi/linux/qnxtypes.h
++
++QORIQ DPAA2 FSL-MC BUS DRIVER
++M: Stuart Yoder <stuyoder@gmail.com>
++M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/stable/sysfs-bus-fsl-mc
++F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
++F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
++F: drivers/bus/fsl-mc/
++F: include/uapi/linux/fsl_mc.h
++
++QT1010 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/qt1010*
++
++QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
++M: Kalle Valo <kvalo@codeaurora.org>
++L: ath10k@lists.infradead.org
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
++F: drivers/net/wireless/ath/ath10k/
++
++QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
++M: Kalle Valo <kvalo@codeaurora.org>
++L: ath11k@lists.infradead.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
++F: drivers/net/wireless/ath/ath11k/
++
++QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
++M: ath9k-devel@qca.qualcomm.com
++L: linux-wireless@vger.kernel.org
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/Drivers/ath9k
++F: drivers/net/wireless/ath/ath9k/
++
++QUALCOMM CAMERA SUBSYSTEM DRIVER
++M: Robert Foss <robert.foss@linaro.org>
++M: Todor Tomov <todor.too@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/media/qcom_camss.rst
++F: Documentation/devicetree/bindings/media/*camss*
++F: drivers/media/platform/qcom/camss/
++
++QUALCOMM CORE POWER REDUCTION (CPR) AVS DRIVER
++M: Niklas Cassel <nks@flawful.org>
++L: linux-pm@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
++F: drivers/soc/qcom/cpr.c
++
++QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
++M: Ilia Lin <ilia.lin@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
++F: drivers/cpufreq/qcom-cpufreq-nvmem.c
++
++QUALCOMM CRYPTO DRIVERS
++M: Thara Gopinath <thara.gopinath@linaro.org>
++L: linux-crypto@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: drivers/crypto/qce/
++
++QUALCOMM EMAC GIGABIT ETHERNET DRIVER
++M: Timur Tabi <timur@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/qualcomm/emac/
++
++QUALCOMM ETHQOS ETHERNET DRIVER
++M: Vinod Koul <vkoul@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/qcom,ethqos.txt
++F: drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
++
++QUALCOMM GENERIC INTERFACE I2C DRIVER
++M: Akash Asthana <akashast@codeaurora.org>
++M: Mukesh Savaliya <msavaliy@codeaurora.org>
++L: linux-i2c@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Supported
++F: drivers/i2c/busses/i2c-qcom-geni.c
++
++QUALCOMM HEXAGON ARCHITECTURE
++M: Brian Cain <bcain@codeaurora.org>
++L: linux-hexagon@vger.kernel.org
++S: Supported
++F: arch/hexagon/
++
++QUALCOMM HIDMA DRIVER
++M: Sinan Kaya <okaya@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++L: linux-arm-msm@vger.kernel.org
++L: dmaengine@vger.kernel.org
++S: Supported
++F: drivers/dma/qcom/hidma*
++
++QUALCOMM I2C CCI DRIVER
++M: Loic Poulain <loic.poulain@linaro.org>
++M: Robert Foss <robert.foss@linaro.org>
++L: linux-i2c@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
++F: drivers/i2c/busses/i2c-qcom-cci.c
++
++QUALCOMM IOMMU
++M: Rob Clark <robdclark@gmail.com>
++L: iommu@lists.linux-foundation.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: drivers/iommu/arm/arm-smmu/qcom_iommu.c
++
++QUALCOMM IPC ROUTER (QRTR) DRIVER
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: include/trace/events/qrtr.h
++F: include/uapi/linux/qrtr.h
++F: net/qrtr/
++
++QUALCOMM IPCC MAILBOX DRIVER
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-arm-msm@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml
++F: drivers/mailbox/qcom-ipcc.c
++F: include/dt-bindings/mailbox/qcom-ipcc.h
++
++QUALCOMM IPQ4019 USB PHY DRIVER
++M: Robert Marko <robert.marko@sartura.hr>
++M: Luka Perkov <luka.perkov@sartura.hr>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml
++F: drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
++
++QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER
++M: Robert Marko <robert.marko@sartura.hr>
++M: Luka Perkov <luka.perkov@sartura.hr>
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml
++F: drivers/regulator/vqmmc-ipq4019-regulator.c
++
++QUALCOMM RMNET DRIVER
++M: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
++M: Sean Tranchetti <stranche@codeaurora.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/networking/device_drivers/cellular/qualcomm/rmnet.rst
++F: drivers/net/ethernet/qualcomm/rmnet/
++F: include/linux/if_rmnet.h
++
++QUALCOMM TSENS THERMAL DRIVER
++M: Amit Kucheria <amitk@kernel.org>
++M: Thara Gopinath <thara.gopinath@linaro.org>
++L: linux-pm@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
++F: drivers/thermal/qcom/
++
++QUALCOMM VENUS VIDEO ACCELERATOR DRIVER
++M: Stanimir Varbanov <stanimir.varbanov@linaro.org>
++L: linux-media@vger.kernel.org
++L: linux-arm-msm@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/*venus*
++F: drivers/media/platform/qcom/venus/
++
++QUALCOMM WCN36XX WIRELESS DRIVER
++M: Kalle Valo <kvalo@codeaurora.org>
++L: wcn36xx@lists.infradead.org
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/Drivers/wcn36xx
++T: git git://github.com/KrasnikovEugene/wcn36xx.git
++F: drivers/net/wireless/ath/wcn36xx/
++
++QUANTENNA QTNFMAC WIRELESS DRIVER
++M: Igor Mitsyanko <imitsyanko@quantenna.com>
++R: Sergey Matyukevich <geomatsi@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/quantenna
++
++RADEON and AMDGPU DRM DRIVERS
++M: Alex Deucher <alexander.deucher@amd.com>
++M: Christian König <christian.koenig@amd.com>
++M: Pan, Xinhui <Xinhui.Pan@amd.com>
++L: amd-gfx@lists.freedesktop.org
++S: Supported
++T: git https://gitlab.freedesktop.org/agd5f/linux.git
++B: https://gitlab.freedesktop.org/drm/amd/-/issues
++C: irc://irc.oftc.net/radeon
++F: drivers/gpu/drm/amd/
++F: drivers/gpu/drm/radeon/
++F: include/uapi/drm/amdgpu_drm.h
++F: include/uapi/drm/radeon_drm.h
++
++RADEON FRAMEBUFFER DISPLAY DRIVER
++M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/aty/radeon*
++F: include/uapi/linux/radeonfb.h
++
++RADIOSHARK RADIO DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-shark.c
++
++RADIOSHARK2 RADIO DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-shark2.c
++F: drivers/media/radio/radio-tea5777.c
++
++RADOS BLOCK DEVICE (RBD)
++M: Ilya Dryomov <idryomov@gmail.com>
++R: Dongsheng Yang <dongsheng.yang@easystack.cn>
++L: ceph-devel@vger.kernel.org
++S: Supported
++W: http://ceph.com/
++T: git git://github.com/ceph/ceph-client.git
++F: Documentation/ABI/testing/sysfs-bus-rbd
++F: drivers/block/rbd.c
++F: drivers/block/rbd_types.h
++
++RAGE128 FRAMEBUFFER DISPLAY DRIVER
++M: Paul Mackerras <paulus@samba.org>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/aty/aty128fb.c
++
++RAINSHADOW-CEC DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/cec/usb/rainshadow/
++
++RALINK MIPS ARCHITECTURE
++M: John Crispin <john@phrozen.org>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/ralink
++
++RALINK RT2X00 WIRELESS LAN DRIVER
++M: Stanislaw Gruszka <stf_xl@wp.pl>
++M: Helmut Schaa <helmut.schaa@googlemail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/ralink/rt2x00/
++
++RAMDISK RAM BLOCK DEVICE DRIVER
++M: Jens Axboe <axboe@kernel.dk>
++S: Maintained
++F: Documentation/admin-guide/blockdev/ramdisk.rst
++F: drivers/block/brd.c
++
++RANCHU VIRTUAL BOARD FOR MIPS
++M: Miodrag Dinic <miodrag.dinic@mips.com>
++L: linux-mips@vger.kernel.org
++S: Supported
++F: arch/mips/configs/generic/board-ranchu.config
++F: arch/mips/generic/board-ranchu.c
++
++RANDOM NUMBER DRIVER
++M: "Theodore Ts'o" <tytso@mit.edu>
++S: Maintained
++F: drivers/char/random.c
++
++RAPIDIO SUBSYSTEM
++M: Matt Porter <mporter@kernel.crashing.org>
++M: Alexandre Bounine <alex.bou9@gmail.com>
++S: Maintained
++F: drivers/rapidio/
++
++RAS INFRASTRUCTURE
++M: Tony Luck <tony.luck@intel.com>
++M: Borislav Petkov <bp@alien8.de>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/ras.rst
++F: drivers/ras/
++F: include/linux/ras.h
++F: include/ras/ras_event.h
++
++RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
++L: linux-wireless@vger.kernel.org
++S: Orphan
++F: drivers/net/wireless/ray*
++
++RC-CORE / LIRC FRAMEWORK
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/driver-api/media/rc-core.rst
++F: Documentation/userspace-api/media/rc/
++F: drivers/media/rc/
++F: include/media/rc-map.h
++F: include/media/rc-core.h
++F: include/uapi/linux/lirc.h
++
++RCMM REMOTE CONTROLS DECODER
++M: Patrick Lerda <patrick9876@free.fr>
++S: Maintained
++F: drivers/media/rc/ir-rcmm-decoder.c
++
++RCUTORTURE TEST FRAMEWORK
++M: "Paul E. McKenney" <paulmck@kernel.org>
++M: Josh Triplett <josh@joshtriplett.org>
++R: Steven Rostedt <rostedt@goodmis.org>
++R: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
++R: Lai Jiangshan <jiangshanlai@gmail.com>
++L: rcu@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
++F: tools/testing/selftests/rcutorture
++
++RDACM20 Camera Sensor
++M: Jacopo Mondi <jacopo+renesas@jmondi.org>
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
++M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml
++F: drivers/media/i2c/max9271.c
++F: drivers/media/i2c/max9271.h
++F: drivers/media/i2c/rdacm20.c
++
++RDACM21 Camera Sensor
++M: Jacopo Mondi <jacopo+renesas@jmondi.org>
++M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
++M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
++M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml
++F: drivers/media/i2c/max9271.c
++F: drivers/media/i2c/max9271.h
++F: drivers/media/i2c/rdacm21.c
++
++RDC R-321X SoC
++M: Florian Fainelli <florian@openwrt.org>
++S: Maintained
++
++RDC R6040 FAST ETHERNET DRIVER
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/rdc/r6040.c
++
++RDMAVT - RDMA verbs software
++M: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
++M: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/sw/rdmavt
++
++RDS - RELIABLE DATAGRAM SOCKETS
++M: Santosh Shilimkar <santosh.shilimkar@oracle.com>
++L: netdev@vger.kernel.org
++L: linux-rdma@vger.kernel.org
++L: rds-devel@oss.oracle.com (moderated for non-subscribers)
++S: Supported
++W: https://oss.oracle.com/projects/rds/
++F: Documentation/networking/rds.rst
++F: net/rds/
++
++RDT - RESOURCE ALLOCATION
++M: Fenghua Yu <fenghua.yu@intel.com>
++M: Reinette Chatre <reinette.chatre@intel.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/x86/resctrl*
++F: arch/x86/include/asm/resctrl.h
++F: arch/x86/kernel/cpu/resctrl/
++F: tools/testing/selftests/resctrl/
++
++READ-COPY UPDATE (RCU)
++M: "Paul E. McKenney" <paulmck@kernel.org>
++M: Josh Triplett <josh@joshtriplett.org>
++R: Steven Rostedt <rostedt@goodmis.org>
++R: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
++R: Lai Jiangshan <jiangshanlai@gmail.com>
++R: Joel Fernandes <joel@joelfernandes.org>
++L: rcu@vger.kernel.org
++S: Supported
++W: http://www.rdrop.com/users/paulmck/RCU/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
++F: Documentation/RCU/
++F: include/linux/rcu*
++F: kernel/rcu/
++X: Documentation/RCU/torture.rst
++X: include/linux/srcu*.h
++X: kernel/rcu/srcu*.c
++
++REAL TIME CLOCK (RTC) SUBSYSTEM
++M: Alessandro Zummo <a.zummo@towertech.it>
++M: Alexandre Belloni <alexandre.belloni@bootlin.com>
++L: linux-rtc@vger.kernel.org
++S: Maintained
++Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
++F: Documentation/admin-guide/rtc.rst
++F: Documentation/devicetree/bindings/rtc/
++F: drivers/rtc/
++F: include/linux/platform_data/rtc-*
++F: include/linux/rtc.h
++F: include/linux/rtc/
++F: include/uapi/linux/rtc.h
++F: tools/testing/selftests/rtc/
++
++REALTEK AUDIO CODECS
++M: Oder Chiou <oder_chiou@realtek.com>
++S: Maintained
++F: include/sound/rt*.h
++F: sound/soc/codecs/rt*
++
++REALTEK RTL83xx SMI DSA ROUTER CHIPS
++M: Linus Walleij <linus.walleij@linaro.org>
++S: Maintained
++F: Documentation/devicetree/bindings/net/dsa/realtek-smi.txt
++F: drivers/net/dsa/realtek-smi*
++F: drivers/net/dsa/rtl83*
++
++REALTEK WIRELESS DRIVER (rtlwifi family)
++M: Ping-Ke Shih <pkshih@realtek.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
++F: drivers/net/wireless/realtek/rtlwifi/
++
++REALTEK WIRELESS DRIVER (rtw88)
++M: Yan-Hsuan Chuang <tony0620emma@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/realtek/rtw88/
++
++REDPINE WIRELESS DRIVER
++M: Amitkumar Karwar <amitkarwar@gmail.com>
++M: Siva Rebbagondla <siva8118@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/rsi/
++
++REGISTER MAP ABSTRACTION
++M: Mark Brown <broonie@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
++F: Documentation/devicetree/bindings/regmap/
++F: drivers/base/regmap/
++F: include/linux/regmap.h
++
++REISERFS FILE SYSTEM
++L: reiserfs-devel@vger.kernel.org
++S: Supported
++F: fs/reiserfs/
++
++REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
++M: Ohad Ben-Cohen <ohad@wizery.com>
++M: Bjorn Andersson <bjorn.andersson@linaro.org>
++M: Mathieu Poirier <mathieu.poirier@linaro.org>
++L: linux-remoteproc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rproc-next
++F: Documentation/ABI/testing/sysfs-class-remoteproc
++F: Documentation/devicetree/bindings/remoteproc/
++F: Documentation/staging/remoteproc.rst
++F: drivers/remoteproc/
++F: include/linux/remoteproc.h
++F: include/linux/remoteproc/
++
++REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
++M: Ohad Ben-Cohen <ohad@wizery.com>
++M: Bjorn Andersson <bjorn.andersson@linaro.org>
++M: Mathieu Poirier <mathieu.poirier@linaro.org>
++L: linux-remoteproc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rpmsg-next
++F: Documentation/ABI/testing/sysfs-bus-rpmsg
++F: Documentation/staging/rpmsg.rst
++F: drivers/rpmsg/
++F: include/linux/rpmsg.h
++F: include/linux/rpmsg/
++F: include/uapi/linux/rpmsg.h
++F: samples/rpmsg/
++
++REMOTE PROCESSOR MESSAGING (RPMSG) WWAN CONTROL DRIVER
++M: Stephan Gerhold <stephan@gerhold.net>
++L: netdev@vger.kernel.org
++L: linux-remoteproc@vger.kernel.org
++S: Maintained
++F: drivers/net/wwan/rpmsg_wwan_ctrl.c
++
++RENESAS CLOCK DRIVERS
++M: Geert Uytterhoeven <geert+renesas@glider.be>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-clk
++F: Documentation/devicetree/bindings/clock/renesas,*
++F: drivers/clk/renesas/
++
++RENESAS EMEV2 I2C DRIVER
++M: Wolfram Sang <wsa+renesas@sang-engineering.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.yaml
++F: drivers/i2c/busses/i2c-emev2.c
++
++RENESAS ETHERNET DRIVERS
++R: Sergey Shtylyov <s.shtylyov@omp.ru>
++L: netdev@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++F: Documentation/devicetree/bindings/net/renesas,*.yaml
++F: drivers/net/ethernet/renesas/
++F: include/linux/sh_eth.h
++
++RENESAS R-CAR GYROADC DRIVER
++M: Marek Vasut <marek.vasut@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml
++F: drivers/iio/adc/rcar-gyroadc.c
++
++RENESAS R-CAR I2C DRIVERS
++M: Wolfram Sang <wsa+renesas@sang-engineering.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml
++F: Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
++F: drivers/i2c/busses/i2c-rcar.c
++F: drivers/i2c/busses/i2c-sh_mobile.c
++
++RENESAS R-CAR THERMAL DRIVERS
++M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.yaml
++F: Documentation/devicetree/bindings/thermal/rcar-thermal.yaml
++F: drivers/thermal/rcar_gen3_thermal.c
++F: drivers/thermal/rcar_thermal.c
++
++RENESAS RIIC DRIVER
++M: Chris Brandt <chris.brandt@renesas.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/i2c/renesas,riic.yaml
++F: drivers/i2c/busses/i2c-riic.c
++
++RENESAS USB PHY DRIVER
++M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
++L: linux-renesas-soc@vger.kernel.org
++S: Maintained
++F: drivers/phy/renesas/phy-rcar-gen3-usb*.c
++
++RENESAS RZ/G2L A/D DRIVER
++M: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
++L: linux-iio@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
++F: drivers/iio/adc/rzg2l_adc.c
++
++RESET CONTROLLER FRAMEWORK
++M: Philipp Zabel <p.zabel@pengutronix.de>
++S: Maintained
++T: git git://git.pengutronix.de/git/pza/linux
++F: Documentation/devicetree/bindings/reset/
++F: Documentation/driver-api/reset.rst
++F: drivers/reset/
++F: include/dt-bindings/reset/
++F: include/linux/reset-controller.h
++F: include/linux/reset.h
++F: include/linux/reset/
++K: \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
++
++RESTARTABLE SEQUENCES SUPPORT
++M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
++M: Peter Zijlstra <peterz@infradead.org>
++M: "Paul E. McKenney" <paulmck@kernel.org>
++M: Boqun Feng <boqun.feng@gmail.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: include/trace/events/rseq.h
++F: include/uapi/linux/rseq.h
++F: kernel/rseq.c
++F: tools/testing/selftests/rseq/
++
++RFKILL
++M: Johannes Berg <johannes@sipsolutions.net>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
++F: Documentation/ABI/stable/sysfs-class-rfkill
++F: Documentation/driver-api/rfkill.rst
++F: include/linux/rfkill.h
++F: include/uapi/linux/rfkill.h
++F: net/rfkill/
++
++RHASHTABLE
++M: Thomas Graf <tgraf@suug.ch>
++M: Herbert Xu <herbert@gondor.apana.org.au>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/linux/rhashtable-types.h
++F: include/linux/rhashtable.h
++F: lib/rhashtable.c
++F: lib/test_rhashtable.c
++
++RICOH R5C592 MEMORYSTICK DRIVER
++M: Maxim Levitsky <maximlevitsky@gmail.com>
++S: Maintained
++F: drivers/memstick/host/r592.*
++
++RICOH SMARTMEDIA/XD DRIVER
++M: Maxim Levitsky <maximlevitsky@gmail.com>
++S: Maintained
++F: drivers/mtd/nand/raw/r852.c
++F: drivers/mtd/nand/raw/r852.h
++
++RISC-V ARCHITECTURE
++M: Paul Walmsley <paul.walmsley@sifive.com>
++M: Palmer Dabbelt <palmer@dabbelt.com>
++M: Albert Ou <aou@eecs.berkeley.edu>
++L: linux-riscv@lists.infradead.org
++S: Supported
++P: Documentation/riscv/patch-acceptance.rst
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
++F: arch/riscv/
++N: riscv
++K: riscv
++
++RISC-V/MICROCHIP POLARFIRE SOC SUPPORT
++M: Lewis Hanly <lewis.hanly@microchip.com>
++L: linux-riscv@lists.infradead.org
++S: Supported
++F: drivers/mailbox/mailbox-mpfs.c
++F: drivers/soc/microchip/
++F: include/soc/microchip/mpfs.h
++
++RNBD BLOCK DRIVERS
++M: Md. Haris Iqbal <haris.iqbal@ionos.com>
++M: Jack Wang <jinpu.wang@ionos.com>
++L: linux-block@vger.kernel.org
++S: Maintained
++F: drivers/block/rnbd/
++
++ROCCAT DRIVERS
++M: Stefan Achatz <erazor_de@users.sourceforge.net>
++S: Maintained
++W: http://sourceforge.net/projects/roccat/
++F: Documentation/ABI/*/sysfs-driver-hid-roccat*
++F: drivers/hid/hid-roccat*
++F: include/linux/hid-roccat*
++
++ROCKCHIP ISP V1 DRIVER
++M: Helen Koike <helen.koike@collabora.com>
++M: Dafna Hirschfeld <dafna.hirschfeld@collabora.com>
++L: linux-media@vger.kernel.org
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++F: Documentation/admin-guide/media/rkisp1.rst
++F: Documentation/devicetree/bindings/media/rockchip-isp1.yaml
++F: Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst
++F: drivers/media/platform/rockchip/rkisp1
++F: include/uapi/linux/rkisp1-config.h
++
++ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
++M: Jacob Chen <jacob-chen@iotwrt.com>
++M: Ezequiel Garcia <ezequiel@collabora.com>
++L: linux-media@vger.kernel.org
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/rockchip-rga.yaml
++F: drivers/media/platform/rockchip/rga/
++
++ROCKCHIP VIDEO DECODER DRIVER
++M: Ezequiel Garcia <ezequiel@collabora.com>
++L: linux-media@vger.kernel.org
++L: linux-rockchip@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/media/rockchip,vdec.yaml
++F: drivers/staging/media/rkvdec/
++
++ROCKER DRIVER
++M: Jiri Pirko <jiri@resnulli.us>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/rocker/
++
++ROCKETPORT EXPRESS/INFINITY DRIVER
++M: Kevin Cernekee <cernekee@gmail.com>
++L: linux-serial@vger.kernel.org
++S: Odd Fixes
++F: drivers/tty/serial/rp2.*
++
++ROHM BD99954 CHARGER IC
++R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
++L: linux-power@fi.rohmeurope.com
++S: Supported
++F: drivers/power/supply/bd99954-charger.c
++F: drivers/power/supply/bd99954-charger.h
++
++ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER
++M: Tomasz Duszynski <tduszyns@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/iio/light/bh1750.yaml
++F: drivers/iio/light/bh1750.c
++
++ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
++M: Marek Vasut <marek.vasut+renesas@gmail.com>
++L: linux-kernel@vger.kernel.org
++L: linux-renesas-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/mfd/bd9571mwv.txt
++F: drivers/gpio/gpio-bd9571mwv.c
++F: drivers/mfd/bd9571mwv.c
++F: drivers/regulator/bd9571mwv-regulator.c
++F: include/linux/mfd/bd9571mwv.h
++
++ROHM POWER MANAGEMENT IC DEVICE DRIVERS
++R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
++L: linux-power@fi.rohmeurope.com
++S: Supported
++F: Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
++F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
++F: drivers/clk/clk-bd718x7.c
++F: drivers/gpio/gpio-bd70528.c
++F: drivers/gpio/gpio-bd71815.c
++F: drivers/gpio/gpio-bd71828.c
++F: drivers/mfd/rohm-bd70528.c
++F: drivers/mfd/rohm-bd71828.c
++F: drivers/mfd/rohm-bd718x7.c
++F: drivers/mfd/rohm-bd9576.c
++F: drivers/power/supply/bd70528-charger.c
++F: drivers/regulator/bd70528-regulator.c
++F: drivers/regulator/bd71815-regulator.c
++F: drivers/regulator/bd71828-regulator.c
++F: drivers/regulator/bd718x7-regulator.c
++F: drivers/regulator/bd9576-regulator.c
++F: drivers/regulator/rohm-regulator.c
++F: drivers/rtc/rtc-bd70528.c
++F: drivers/watchdog/bd70528_wdt.c
++F: drivers/watchdog/bd9576_wdt.c
++F: include/linux/mfd/rohm-bd70528.h
++F: include/linux/mfd/rohm-bd71815.h
++F: include/linux/mfd/rohm-bd71828.h
++F: include/linux/mfd/rohm-bd718x7.h
++F: include/linux/mfd/rohm-bd957x.h
++F: include/linux/mfd/rohm-generic.h
++F: include/linux/mfd/rohm-shared.h
++
++ROSE NETWORK LAYER
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://www.linux-ax25.org/
++F: include/net/rose.h
++F: include/uapi/linux/rose.h
++F: net/rose/
++
++ROTATION DRIVER FOR ALLWINNER A83T
++M: Jernej Skrabec <jernej.skrabec@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
++F: drivers/media/platform/sunxi/sun8i-rotate/
++
++RTL2830 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/rtl2830*
++
++RTL2832 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/rtl2832*
++
++RTL2832_SDR MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/rtl2832_sdr*
++
++RTL8180 WIRELESS DRIVER
++L: linux-wireless@vger.kernel.org
++S: Orphan
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
++F: drivers/net/wireless/realtek/rtl818x/rtl8180/
++
++RTL8187 WIRELESS DRIVER
++M: Herton Ronaldo Krzesinski <herton@canonical.com>
++M: Hin-Tak Leung <htl10@users.sourceforge.net>
++M: Larry Finger <Larry.Finger@lwfinger.net>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++W: https://wireless.wiki.kernel.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
++F: drivers/net/wireless/realtek/rtl818x/rtl8187/
++
++RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
++M: Jes Sorensen <Jes.Sorensen@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
++F: drivers/net/wireless/realtek/rtl8xxxu/
++
++RTRS TRANSPORT DRIVERS
++M: Md. Haris Iqbal <haris.iqbal@ionos.com>
++M: Jack Wang <jinpu.wang@ionos.com>
++L: linux-rdma@vger.kernel.org
++S: Maintained
++F: drivers/infiniband/ulp/rtrs/
++
++RXRPC SOCKETS (AF_RXRPC)
++M: David Howells <dhowells@redhat.com>
++M: Marc Dionne <marc.dionne@auristor.com>
++L: linux-afs@lists.infradead.org
++S: Supported
++W: https://www.infradead.org/~dhowells/kafs/
++F: Documentation/networking/rxrpc.rst
++F: include/keys/rxrpc-type.h
++F: include/net/af_rxrpc.h
++F: include/trace/events/rxrpc.h
++F: include/uapi/linux/rxrpc.h
++F: net/rxrpc/
++
++S3 SAVAGE FRAMEBUFFER DRIVER
++M: Antonino Daplas <adaplas@gmail.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/savage/
++
++S390
++M: Heiko Carstens <hca@linux.ibm.com>
++M: Vasily Gorbik <gor@linux.ibm.com>
++M: Christian Borntraeger <borntraeger@de.ibm.com>
++R: Alexander Gordeev <agordeev@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
++F: Documentation/driver-api/s390-drivers.rst
++F: Documentation/s390/
++F: arch/s390/
++F: drivers/s390/
++
++S390 COMMON I/O LAYER
++M: Vineeth Vijayan <vneethv@linux.ibm.com>
++M: Peter Oberparleiter <oberpar@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/s390/cio/
++
++S390 DASD DRIVER
++M: Stefan Haberland <sth@linux.ibm.com>
++M: Jan Hoeppner <hoeppner@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: block/partitions/ibm.c
++F: drivers/s390/block/dasd*
++F: include/linux/dasd_mod.h
++
++S390 IOMMU (PCI)
++M: Matthew Rosato <mjrosato@linux.ibm.com>
++M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/iommu/s390-iommu.c
++
++S390 IUCV NETWORK LAYER
++M: Julian Wiedmann <jwi@linux.ibm.com>
++M: Karsten Graul <kgraul@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/s390/net/*iucv*
++F: include/net/iucv/
++F: net/iucv/
++
++S390 NETWORK DRIVERS
++M: Julian Wiedmann <jwi@linux.ibm.com>
++M: Karsten Graul <kgraul@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/s390/net/
++
++S390 PCI SUBSYSTEM
++M: Niklas Schnelle <schnelle@linux.ibm.com>
++M: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: arch/s390/pci/
++F: drivers/pci/hotplug/s390_pci_hpc.c
++F: Documentation/s390/pci.rst
++
++S390 VFIO AP DRIVER
++M: Tony Krowiak <akrowiak@linux.ibm.com>
++M: Halil Pasic <pasic@linux.ibm.com>
++M: Jason Herne <jjherne@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: Documentation/s390/vfio-ap.rst
++F: drivers/s390/crypto/vfio_ap_drv.c
++F: drivers/s390/crypto/vfio_ap_ops.c
++F: drivers/s390/crypto/vfio_ap_private.h
++
++S390 VFIO-CCW DRIVER
++M: Eric Farman <farman@linux.ibm.com>
++M: Matthew Rosato <mjrosato@linux.ibm.com>
++R: Halil Pasic <pasic@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++L: kvm@vger.kernel.org
++S: Supported
++F: Documentation/s390/vfio-ccw.rst
++F: drivers/s390/cio/vfio_ccw*
++F: include/uapi/linux/vfio_ccw.h
++
++S390 VFIO-PCI DRIVER
++M: Matthew Rosato <mjrosato@linux.ibm.com>
++M: Eric Farman <farman@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++L: kvm@vger.kernel.org
++S: Supported
++F: drivers/vfio/pci/vfio_pci_zdev.c
++F: include/uapi/linux/vfio_zdev.h
++
++S390 ZCRYPT DRIVER
++M: Harald Freudenberger <freude@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/s390/crypto/
++
++S390 ZFCP DRIVER
++M: Steffen Maier <maier@linux.ibm.com>
++M: Benjamin Block <bblock@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: drivers/s390/scsi/zfcp_*
++
++S3C ADC BATTERY DRIVER
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-samsung-soc@vger.kernel.org
++S: Odd Fixes
++F: drivers/power/supply/s3c_adc_battery.c
++F: include/linux/s3c_adc_battery.h
++
++S3C24XX SD/MMC Driver
++M: Ben Dooks <ben-linux@fluff.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/mmc/host/s3cmci.*
++
++SAA6588 RDS RECEIVER DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/saa6588*
++
++SAA7134 VIDEO4LINUX DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/driver-api/media/drivers/saa7134*
++F: drivers/media/pci/saa7134/
++
++SAA7146 VIDEO4LINUX-2 DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/common/saa7146/
++F: drivers/media/pci/saa7146/
++F: include/media/drv-intf/saa7146*
++
++SAFESETID SECURITY MODULE
++M: Micah Morton <mortonm@chromium.org>
++S: Supported
++F: Documentation/admin-guide/LSM/SafeSetID.rst
++F: security/safesetid/
++
++SAMSUNG AUDIO (ASoC) DRIVERS
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++F: Documentation/devicetree/bindings/sound/samsung*
++F: sound/soc/samsung/
++
++SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++L: linux-crypto@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml
++F: drivers/crypto/exynos-rng.c
++
++SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
++M: Łukasz Stelmach <l.stelmach@samsung.com>
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.yaml
++F: drivers/char/hw_random/exynos-trng.c
++
++SAMSUNG FRAMEBUFFER DRIVER
++M: Jingoo Han <jingoohan1@gmail.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/s3c-fb.c
++
++SAMSUNG INTERCONNECT DRIVERS
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++M: Artur Świgoń <a.swigon@samsung.com>
++L: linux-pm@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Supported
++F: drivers/interconnect/samsung/
++
++SAMSUNG LAPTOP DRIVER
++M: Corentin Chary <corentin.chary@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/samsung-laptop.c
++
++SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++L: linux-kernel@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
++F: Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
++F: Documentation/devicetree/bindings/regulator/samsung,s2m*.txt
++F: Documentation/devicetree/bindings/regulator/samsung,s5m*.txt
++F: drivers/clk/clk-s2mps11.c
++F: drivers/mfd/sec*.c
++F: drivers/regulator/s2m*.c
++F: drivers/regulator/s5m*.c
++F: drivers/rtc/rtc-s5m.c
++F: include/linux/mfd/samsung/
++
++SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER
++M: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
++L: linux-media@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/s3c-camif/
++F: include/media/drv-intf/s3c_camif.h
++
++SAMSUNG S3FWRN5 NFC DRIVER
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Krzysztof Opasiak <k.opasiak@samsung.com>
++L: linux-nfc@lists.01.org (subscribers-only)
++S: Maintained
++F: Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
++F: drivers/nfc/s3fwrn5
++
++SAMSUNG S5C73M3 CAMERA DRIVER
++M: Andrzej Hajda <a.hajda@samsung.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/i2c/s5c73m3/*
++
++SAMSUNG S5K5BAF CAMERA DRIVER
++M: Andrzej Hajda <a.hajda@samsung.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/i2c/s5k5baf.c
++
++SAMSUNG S5P Security SubSystem (SSS) DRIVER
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Vladimir Zapolskiy <vz@mleia.com>
++L: linux-crypto@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/crypto/samsung-slimsss.yaml
++F: Documentation/devicetree/bindings/crypto/samsung-sss.yaml
++F: drivers/crypto/s5p-sss.c
++
++SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: linux-media@vger.kernel.org
++S: Supported
++Q: https://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/platform/exynos4-is/
++
++SAMSUNG SOC CLOCK DRIVERS
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++M: Tomasz Figa <tomasz.figa@gmail.com>
++M: Chanwoo Choi <cw00.choi@samsung.com>
++L: linux-samsung-soc@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
++F: Documentation/devicetree/bindings/clock/exynos*.txt
++F: Documentation/devicetree/bindings/clock/samsung,*.yaml
++F: Documentation/devicetree/bindings/clock/samsung,s3c*
++F: Documentation/devicetree/bindings/clock/samsung,s5p*
++F: drivers/clk/samsung/
++F: include/dt-bindings/clock/exynos*.h
++F: include/dt-bindings/clock/s3c*.h
++F: include/dt-bindings/clock/s5p*.h
++F: include/dt-bindings/clock/samsung,*.h
++F: include/linux/clk/samsung.h
++F: include/linux/platform_data/clk-s3c2410.h
++
++SAMSUNG SPI DRIVERS
++M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
++M: Andi Shyti <andi@etezian.org>
++L: linux-spi@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spi/spi-samsung.txt
++F: drivers/spi/spi-s3c*
++F: include/linux/platform_data/spi-s3c64xx.h
++F: include/linux/spi/s3c24xx-fiq.h
++
++SAMSUNG SXGBE DRIVERS
++M: Byungho An <bh74.an@samsung.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/samsung/sxgbe/
++
++SAMSUNG THERMAL DRIVER
++M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++L: linux-pm@vger.kernel.org
++L: linux-samsung-soc@vger.kernel.org
++S: Supported
++T: git https://github.com/lmajewski/linux-samsung-thermal.git
++F: drivers/thermal/samsung/
++
++SAMSUNG USB2 PHY DRIVER
++M: Sylwester Nawrocki <s.nawrocki@samsung.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/phy/samsung-phy.txt
++F: Documentation/driver-api/phy/samsung-usb2.rst
++F: drivers/phy/samsung/phy-exynos4210-usb2.c
++F: drivers/phy/samsung/phy-exynos4x12-usb2.c
++F: drivers/phy/samsung/phy-exynos5250-usb2.c
++F: drivers/phy/samsung/phy-s5pv210-usb2.c
++F: drivers/phy/samsung/phy-samsung-usb2.c
++F: drivers/phy/samsung/phy-samsung-usb2.h
++
++SANCLOUD BEAGLEBONE ENHANCED DEVICE TREE
++M: Paul Barker <paul.barker@sancloud.com>
++R: Marc Murphy <marc.murphy@sancloud.com>
++S: Supported
++F: arch/arm/boot/dts/am335x-sancloud*
++
++SC1200 WDT DRIVER
++M: Zwane Mwaikambo <zwanem@gmail.com>
++S: Maintained
++F: drivers/watchdog/sc1200wdt.c
++
++SCHEDULER
++M: Ingo Molnar <mingo@redhat.com>
++M: Peter Zijlstra <peterz@infradead.org>
++M: Juri Lelli <juri.lelli@redhat.com> (SCHED_DEADLINE)
++M: Vincent Guittot <vincent.guittot@linaro.org> (SCHED_NORMAL)
++R: Dietmar Eggemann <dietmar.eggemann@arm.com> (SCHED_NORMAL)
++R: Steven Rostedt <rostedt@goodmis.org> (SCHED_FIFO/SCHED_RR)
++R: Ben Segall <bsegall@google.com> (CONFIG_CFS_BANDWIDTH)
++R: Mel Gorman <mgorman@suse.de> (CONFIG_NUMA_BALANCING)
++R: Daniel Bristot de Oliveira <bristot@redhat.com> (SCHED_DEADLINE)
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
++F: include/linux/preempt.h
++F: include/linux/sched.h
++F: include/linux/wait.h
++F: include/uapi/linux/sched.h
++F: kernel/sched/
++
++SCR24X CHIP CARD INTERFACE DRIVER
++M: Lubomir Rintel <lkundrak@v3.sk>
++S: Supported
++F: drivers/char/pcmcia/scr24x_cs.c
++
++SCSI RDMA PROTOCOL (SRP) INITIATOR
++M: Bart Van Assche <bvanassche@acm.org>
++L: linux-rdma@vger.kernel.org
++S: Supported
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/ulp/srp/
++F: include/scsi/srp.h
++
++SCSI RDMA PROTOCOL (SRP) TARGET
++M: Bart Van Assche <bvanassche@acm.org>
++L: linux-rdma@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++Q: http://patchwork.kernel.org/project/linux-rdma/list/
++F: drivers/infiniband/ulp/srpt/
++
++SCSI SG DRIVER
++M: Doug Gilbert <dgilbert@interlog.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++W: http://sg.danny.cz/sg
++F: Documentation/scsi/scsi-generic.rst
++F: drivers/scsi/sg.c
++F: include/scsi/sg.h
++
++SCSI SUBSYSTEM
++M: "James E.J. Bottomley" <jejb@linux.ibm.com>
++M: "Martin K. Petersen" <martin.petersen@oracle.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++Q: https://patchwork.kernel.org/project/linux-scsi/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
++F: Documentation/devicetree/bindings/scsi/
++F: drivers/scsi/
++F: include/scsi/
++
++SCSI TAPE DRIVER
++M: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: Documentation/scsi/st.rst
++F: drivers/scsi/st.*
++F: drivers/scsi/st_*.h
++
++SCSI TARGET CORE USER DRIVER
++M: Bodo Stroesser <bostroesser@gmail.com>
++L: linux-scsi@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++F: Documentation/target/tcmu-design.rst
++F: drivers/target/target_core_user.c
++F: include/uapi/linux/target_core_user.h
++
++SCSI TARGET SUBSYSTEM
++M: "Martin K. Petersen" <martin.petersen@oracle.com>
++L: linux-scsi@vger.kernel.org
++L: target-devel@vger.kernel.org
++S: Supported
++W: http://www.linux-iscsi.org
++Q: https://patchwork.kernel.org/project/target-devel/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
++F: Documentation/target/
++F: drivers/target/
++F: include/target/
++
++SCTP PROTOCOL
++M: Vlad Yasevich <vyasevich@gmail.com>
++M: Neil Horman <nhorman@tuxdriver.com>
++M: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
++L: linux-sctp@vger.kernel.org
++S: Maintained
++W: http://lksctp.sourceforge.net
++F: Documentation/networking/sctp.rst
++F: include/linux/sctp.h
++F: include/net/sctp/
++F: include/uapi/linux/sctp.h
++F: net/sctp/
++
++SCx200 CPU SUPPORT
++M: Jim Cromie <jim.cromie@gmail.com>
++S: Odd Fixes
++F: Documentation/i2c/busses/scx200_acb.rst
++F: arch/x86/platform/scx200/
++F: drivers/i2c/busses/scx200*
++F: drivers/mtd/maps/scx200_docflash.c
++F: drivers/watchdog/scx200_wdt.c
++F: include/linux/scx200.h
++
++SCx200 GPIO DRIVER
++M: Jim Cromie <jim.cromie@gmail.com>
++S: Maintained
++F: drivers/char/scx200_gpio.c
++F: include/linux/scx200_gpio.h
++
++SCx200 HRT CLOCKSOURCE DRIVER
++M: Jim Cromie <jim.cromie@gmail.com>
++S: Maintained
++F: drivers/clocksource/scx200_hrt.c
++
++SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER
++M: Sascha Sommer <saschasommer@freenet.de>
++L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
++S: Maintained
++F: drivers/mmc/host/sdricoh_cs.c
++
++SECO BOARDS CEC DRIVER
++M: Ettore Chimenti <ek5.chimenti@gmail.com>
++S: Maintained
++F: drivers/media/cec/platform/seco/seco-cec.c
++F: drivers/media/cec/platform/seco/seco-cec.h
++
++SECURE COMPUTING
++M: Kees Cook <keescook@chromium.org>
++R: Andy Lutomirski <luto@amacapital.net>
++R: Will Drewry <wad@chromium.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
++F: Documentation/userspace-api/seccomp_filter.rst
++F: include/linux/seccomp.h
++F: include/uapi/linux/seccomp.h
++F: kernel/seccomp.c
++F: tools/testing/selftests/kselftest_harness.h
++F: tools/testing/selftests/seccomp/*
++K: \bsecure_computing
++K: \bTIF_SECCOMP\b
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
++M: Al Cooper <alcooperx@gmail.com>
++L: linux-mmc@vger.kernel.org
++L: bcm-kernel-feedback-list@broadcom.com
++S: Maintained
++F: drivers/mmc/host/sdhci-brcmstb*
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
++M: Adrian Hunter <adrian.hunter@intel.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci*
++F: include/linux/mmc/sdhci*
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
++M: Eugen Hristev <eugen.hristev@microchip.com>
++L: linux-mmc@vger.kernel.org
++S: Supported
++F: drivers/mmc/host/sdhci-of-at91.c
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
++M: Ben Dooks <ben-linux@fluff.org>
++M: Jaehoon Chung <jh80.chung@samsung.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci-s3c*
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
++M: Viresh Kumar <vireshk@kernel.org>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci-spear.c
++
++SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
++M: Kishon Vijay Abraham I <kishon@ti.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci-omap.c
++
++SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
++M: Jonathan Derrick <jonathan.derrick@intel.com>
++M: Revanth Rajashekar <revanth.rajashekar@intel.com>
++L: linux-block@vger.kernel.org
++S: Supported
++F: block/opal_proto.h
++F: block/sed*
++F: include/linux/sed*
++F: include/uapi/linux/sed*
++
++SECURITY CONTACT
++M: Security Officers <security@kernel.org>
++S: Supported
++F: Documentation/admin-guide/security-bugs.rst
++
++SECURITY SUBSYSTEM
++M: James Morris <jmorris@namei.org>
++M: "Serge E. Hallyn" <serge@hallyn.com>
++L: linux-security-module@vger.kernel.org (suggested Cc:)
++S: Supported
++W: http://kernsec.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
++F: security/
++X: security/selinux/
++
++SELINUX SECURITY MODULE
++M: Paul Moore <paul@paul-moore.com>
++M: Stephen Smalley <stephen.smalley.work@gmail.com>
++M: Eric Paris <eparis@parisplace.org>
++L: selinux@vger.kernel.org
++S: Supported
++W: https://selinuxproject.org
++W: https://github.com/SELinuxProject
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
++F: Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
++F: Documentation/ABI/obsolete/sysfs-selinux-disable
++F: Documentation/admin-guide/LSM/SELinux.rst
++F: include/trace/events/avc.h
++F: include/uapi/linux/selinux_netlink.h
++F: scripts/selinux/
++F: security/selinux/
++
++SENSABLE PHANTOM
++M: Jiri Slaby <jirislaby@kernel.org>
++S: Maintained
++F: drivers/misc/phantom.c
++F: include/uapi/linux/phantom.h
++
++SENSIRION SCD30 CARBON DIOXIDE SENSOR DRIVER
++M: Tomasz Duszynski <tomasz.duszynski@octakon.com>
++S: Maintained
++F: Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
++F: drivers/iio/chemical/scd30.h
++F: drivers/iio/chemical/scd30_core.c
++F: drivers/iio/chemical/scd30_i2c.c
++F: drivers/iio/chemical/scd30_serial.c
++
++SENSIRION SGP40 GAS SENSOR DRIVER
++M: Andreas Klinger <ak@it-klinger.de>
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
++F: drivers/iio/chemical/sgp40.c
++
++SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
++M: Tomasz Duszynski <tduszyns@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml
++F: drivers/iio/chemical/sps30.c
++F: drivers/iio/chemical/sps30_i2c.c
++F: drivers/iio/chemical/sps30_serial.c
++
++SERIAL DEVICE BUS
++M: Rob Herring <robh@kernel.org>
++L: linux-serial@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/serial/serial.yaml
++F: drivers/tty/serdev/
++F: include/linux/serdev.h
++
++SERIAL DRIVERS
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-serial@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/serial/
++F: drivers/tty/serial/
++
++SERIAL IR RECEIVER
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/serial_ir.c
++
++SERIAL LOW-POWER INTER-CHIP MEDIA BUS (SLIMbus)
++M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/slimbus/
++F: drivers/slimbus/
++F: include/linux/slimbus.h
++
++SFC NETWORK DRIVER
++M: Edward Cree <ecree.xilinx@gmail.com>
++M: Martin Habets <habetsm.xilinx@gmail.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/sfc/
++
++SFF/SFP/SFP+ MODULE SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++L: netdev@vger.kernel.org
++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\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate)
++
++SGI GRU DRIVER
++M: Dimitri Sivanich <dimitri.sivanich@hpe.com>
++S: Maintained
++F: drivers/misc/sgi-gru/
++
++SGI XP/XPC/XPNET DRIVER
++M: Robin Holt <robinmholt@gmail.com>
++M: Steve Wahl <steve.wahl@hpe.com>
++R: Mike Travis <mike.travis@hpe.com>
++S: Maintained
++F: drivers/misc/sgi-xp/
++
++SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
++M: Karsten Graul <kgraul@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++S: Supported
++W: http://www.ibm.com/developerworks/linux/linux390/
++F: net/smc/
++
++SHARP GP2AP002A00F/GP2AP002S00F SENSOR DRIVER
++M: Linus Walleij <linus.walleij@linaro.org>
++L: linux-iio@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
++F: Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml
++F: drivers/iio/light/gp2ap002.c
++
++SHARP RJ54N1CB0C SENSOR DRIVER
++M: Jacopo Mondi <jacopo@jmondi.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/rj54n1cb0c.c
++F: include/media/i2c/rj54n1cb0c.h
++
++SH_VOU V4L2 OUTPUT DRIVER
++L: linux-media@vger.kernel.org
++S: Orphan
++F: drivers/media/platform/sh_vou.c
++F: include/media/drv-intf/sh_vou.h
++
++SI2157 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/si2157*
++
++SI2165 MEDIA DRIVER
++M: Matthias Schwarzott <zzam@gentoo.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/si2165*
++
++SI2168 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/si2168*
++
++SI470X FM RADIO RECEIVER I2C DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/si470x/radio-si470x-i2c.c
++
++SI470X FM RADIO RECEIVER USB DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/si470x/radio-si470x-common.c
++F: drivers/media/radio/si470x/radio-si470x-usb.c
++F: drivers/media/radio/si470x/radio-si470x.h
++
++SI4713 FM RADIO TRANSMITTER I2C DRIVER
++M: Eduardo Valentin <edubezval@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/si4713/si4713.?
++
++SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
++M: Eduardo Valentin <edubezval@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/si4713/radio-platform-si4713.c
++
++SI4713 FM RADIO TRANSMITTER USB DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/si4713/radio-usb-si4713.c
++
++SIANO DVB DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/common/siano/
++F: drivers/media/mmc/siano/
++F: drivers/media/usb/siano/
++F: drivers/media/usb/siano/
++
++SIFIVE DRIVERS
++M: Palmer Dabbelt <palmer@dabbelt.com>
++M: Paul Walmsley <paul.walmsley@sifive.com>
++L: linux-riscv@lists.infradead.org
++S: Supported
++T: git git://github.com/sifive/riscv-linux.git
++N: sifive
++K: [^@]sifive
++
++SIFIVE FU540 SYSTEM-ON-CHIP
++M: Paul Walmsley <paul.walmsley@sifive.com>
++M: Palmer Dabbelt <palmer@dabbelt.com>
++L: linux-riscv@lists.infradead.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pjw/sifive.git
++N: fu540
++K: fu540
++
++SIFIVE PDMA DRIVER
++M: Green Wan <green.wan@sifive.com>
++S: Maintained
++F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
++F: drivers/dma/sf-pdma/
++
++SILEAD TOUCHSCREEN DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/input/touchscreen/silead.c
++F: drivers/platform/x86/touchscreen_dmi.c
++
++SILICON LABS WIRELESS DRIVERS (for WFxxx series)
++M: Jérôme Pouiller <jerome.pouiller@silabs.com>
++S: Supported
++F: drivers/staging/wfx/
++
++SILICON MOTION SM712 FRAME BUFFER DRIVER
++M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
++M: Teddy Wang <teddy.wang@siliconmotion.com>
++M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: Documentation/fb/sm712fb.rst
++F: drivers/video/fbdev/sm712*
++
++SILVACO I3C DUAL-ROLE MASTER
++M: Miquel Raynal <miquel.raynal@bootlin.com>
++M: Conor Culhane <conor.culhane@silvaco.com>
++L: linux-i3c@lists.infradead.org
++S: Maintained
++F: Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
++F: drivers/i3c/master/svc-i3c-master.c
++
++SIMPLEFB FB DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/display/simple-framebuffer.yaml
++F: drivers/video/fbdev/simplefb.c
++F: include/linux/platform_data/simplefb.h
++
++SIMTEC EB110ATX (Chalice CATS)
++M: Simtec Linux Team <linux@simtec.co.uk>
++S: Supported
++W: http://www.simtec.co.uk/products/EB110ATX/
++
++SIMTEC EB2410ITX (BAST)
++M: Simtec Linux Team <linux@simtec.co.uk>
++S: Supported
++W: http://www.simtec.co.uk/products/EB2410ITX/
++F: arch/arm/mach-s3c/bast-ide.c
++F: arch/arm/mach-s3c/bast-irq.c
++F: arch/arm/mach-s3c/mach-bast.c
++
++SIOX
++M: Thorsten Scherer <t.scherer@eckelmann.de>
++M: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
++R: Pengutronix Kernel Team <kernel@pengutronix.de>
++S: Supported
++F: drivers/gpio/gpio-siox.c
++F: drivers/siox/*
++F: include/trace/events/siox.h
++
++SIPHASH PRF ROUTINES
++M: Jason A. Donenfeld <Jason@zx2c4.com>
++S: Maintained
++F: include/linux/siphash.h
++F: lib/siphash.c
++F: lib/test_siphash.c
++
++SIS 190 ETHERNET DRIVER
++M: Francois Romieu <romieu@fr.zoreil.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/sis/sis190.c
++
++SIS 900/7016 FAST ETHERNET DRIVER
++M: Daniele Venzano <venza@brownhat.org>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.brownhat.org/sis900.html
++F: drivers/net/ethernet/sis/sis900.*
++
++SIS FRAMEBUFFER DRIVER
++M: Thomas Winischhofer <thomas@winischhofer.net>
++S: Maintained
++W: http://www.winischhofer.net/linuxsisvga.shtml
++F: Documentation/fb/sisfb.rst
++F: drivers/video/fbdev/sis/
++F: include/video/sisfb.h
++
++SIS I2C TOUCHSCREEN DRIVER
++M: Mika Penttilä <mika.penttila@nextfour.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt
++F: drivers/input/touchscreen/sis_i2c.c
++
++SIS USB2VGA DRIVER
++M: Thomas Winischhofer <thomas@winischhofer.net>
++S: Maintained
++W: http://www.winischhofer.at/linuxsisusbvga.shtml
++F: drivers/usb/misc/sisusbvga/
++
++SLAB ALLOCATOR
++M: Christoph Lameter <cl@linux.com>
++M: Pekka Enberg <penberg@kernel.org>
++M: David Rientjes <rientjes@google.com>
++M: Joonsoo Kim <iamjoonsoo.kim@lge.com>
++M: Andrew Morton <akpm@linux-foundation.org>
++M: Vlastimil Babka <vbabka@suse.cz>
++L: linux-mm@kvack.org
++S: Maintained
++F: include/linux/sl?b*.h
++F: mm/sl?b*
++
++SLEEPABLE READ-COPY UPDATE (SRCU)
++M: Lai Jiangshan <jiangshanlai@gmail.com>
++M: "Paul E. McKenney" <paulmck@kernel.org>
++M: Josh Triplett <josh@joshtriplett.org>
++R: Steven Rostedt <rostedt@goodmis.org>
++R: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
++L: rcu@vger.kernel.org
++S: Supported
++W: http://www.rdrop.com/users/paulmck/RCU/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
++F: include/linux/srcu*.h
++F: kernel/rcu/srcu*.c
++
++SMACK SECURITY MODULE
++M: Casey Schaufler <casey@schaufler-ca.com>
++L: linux-security-module@vger.kernel.org
++S: Maintained
++W: http://schaufler-ca.com
++T: git git://github.com/cschaufler/smack-next
++F: Documentation/admin-guide/LSM/Smack.rst
++F: security/smack/
++
++SMC91x ETHERNET DRIVER
++M: Nicolas Pitre <nico@fluxnic.net>
++S: Odd Fixes
++F: drivers/net/ethernet/smsc/smc91x.*
++
++SECURE MONITOR CALL(SMC) CALLING CONVENTION (SMCCC)
++M: Mark Rutland <mark.rutland@arm.com>
++M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
++M: Sudeep Holla <sudeep.holla@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/firmware/smccc/
++F: include/linux/arm-smccc.h
++
++SMM665 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/smm665.rst
++F: drivers/hwmon/smm665.c
++
++SMSC EMC2103 HARDWARE MONITOR DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/emc2103.rst
++F: drivers/hwmon/emc2103.c
++
++SMSC SCH5627 HARDWARE MONITOR DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-hwmon@vger.kernel.org
++S: Supported
++F: Documentation/hwmon/sch5627.rst
++F: drivers/hwmon/sch5627.c
++
++SMSC UFX6000 and UFX7000 USB to VGA DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/smscufx.c
++
++SMSC47B397 HARDWARE MONITOR DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/smsc47b397.rst
++F: drivers/hwmon/smsc47b397.c
++
++SMSC911x ETHERNET DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/smsc/smsc911x.*
++F: include/linux/smsc911x.h
++
++SMSC9420 PCI ETHERNET DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/smsc/smsc9420.*
++
++SOCIONEXT (SNI) AVE NETWORK DRIVER
++M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/socionext,uniphier-ave4.yaml
++F: drivers/net/ethernet/socionext/sni_ave.c
++
++SOCIONEXT (SNI) NETSEC NETWORK DRIVER
++M: Jassi Brar <jaswinder.singh@linaro.org>
++M: Ilias Apalodimas <ilias.apalodimas@linaro.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/socionext-netsec.txt
++F: drivers/net/ethernet/socionext/netsec.c
++
++SOCIONEXT (SNI) Synquacer SPI DRIVER
++M: Masahisa Kojima <masahisa.kojima@linaro.org>
++M: Jassi Brar <jaswinder.singh@linaro.org>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/spi/spi-synquacer.txt
++F: drivers/spi/spi-synquacer.c
++
++SOCIONEXT SYNQUACER I2C DRIVER
++M: Ard Biesheuvel <ardb@kernel.org>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/i2c/i2c-synquacer.txt
++F: drivers/i2c/busses/i2c-synquacer.c
++
++SOCIONEXT UNIPHIER SOUND DRIVER
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Orphan
++F: sound/soc/uniphier/
++
++SOEKRIS NET48XX LED SUPPORT
++M: Chris Boot <bootc@bootc.net>
++S: Maintained
++F: drivers/leds/leds-net48xx.c
++
++SOFT-IWARP DRIVER (siw)
++M: Bernard Metzler <bmt@zurich.ibm.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/sw/siw/
++F: include/uapi/rdma/siw-abi.h
++
++SOFT-ROCE DRIVER (rxe)
++M: Zhu Yanjun <zyjzyj2000@gmail.com>
++L: linux-rdma@vger.kernel.org
++S: Supported
++F: drivers/infiniband/sw/rxe/
++F: include/uapi/rdma/rdma_user_rxe.h
++
++SOFTLOGIC 6x10 MPEG CODEC
++M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
++M: Anton Sviridenko <anton@corp.bluecherry.net>
++M: Andrey Utkin <andrey_utkin@fastmail.com>
++M: Ismael Luceno <ismael@iodev.co.uk>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/pci/solo6x10/
++
++SOFTWARE DELEGATED EXCEPTION INTERFACE (SDEI)
++M: James Morse <james.morse@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/firmware/sdei.txt
++F: drivers/firmware/arm_sdei.c
++F: include/linux/arm_sdei.h
++F: include/uapi/linux/arm_sdei.h
++
++SOFTWARE NODES
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++R: Heikki Krogerus <heikki.krogerus@linux.intel.com>
++L: linux-acpi@vger.kernel.org
++S: Maintained
++F: drivers/base/swnode.c
++
++SOFTWARE RAID (Multiple Disks) SUPPORT
++M: Song Liu <song@kernel.org>
++L: linux-raid@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git
++F: drivers/md/Kconfig
++F: drivers/md/Makefile
++F: drivers/md/md*
++F: drivers/md/raid*
++F: include/linux/raid/
++F: include/uapi/linux/raid/
++
++SOLIDRUN CLEARFOG SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++S: Maintained
++F: arch/arm/boot/dts/armada-388-clearfog*
++F: arch/arm/boot/dts/armada-38x-solidrun-*
++
++SOLIDRUN CUBOX-I/HUMMINGBOARD SUPPORT
++M: Russell King <linux@armlinux.org.uk>
++S: Maintained
++F: arch/arm/boot/dts/imx6*-cubox-i*
++F: arch/arm/boot/dts/imx6*-hummingboard*
++F: arch/arm/boot/dts/imx6*-sr-*
++
++SONIC NETWORK DRIVER
++M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/natsemi/sonic.*
++
++SONICS SILICON BACKPLANE DRIVER (SSB)
++M: Michael Buesch <m@bues.ch>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/ssb/
++F: include/linux/ssb/
++
++SONY IMX208 SENSOR DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/imx208.c
++
++SONY IMX214 SENSOR DRIVER
++M: Ricardo Ribalda <ribalda@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml
++F: drivers/media/i2c/imx214.c
++
++SONY IMX219 SENSOR DRIVER
++M: Dave Stevenson <dave.stevenson@raspberrypi.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/imx219.yaml
++F: drivers/media/i2c/imx219.c
++
++SONY IMX258 SENSOR DRIVER
++M: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/imx258.yaml
++F: drivers/media/i2c/imx258.c
++
++SONY IMX274 SENSOR DRIVER
++M: Leon Luo <leonl@leopardimaging.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml
++F: drivers/media/i2c/imx274.c
++
++SONY IMX290 SENSOR DRIVER
++M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/imx290.txt
++F: drivers/media/i2c/imx290.c
++
++SONY IMX319 SENSOR DRIVER
++M: Bingbu Cao <bingbu.cao@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/imx319.c
++
++SONY IMX334 SENSOR DRIVER
++M: Paul J. Murphy <paul.j.murphy@intel.com>
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml
++F: drivers/media/i2c/imx334.c
++
++SONY IMX335 SENSOR DRIVER
++M: Paul J. Murphy <paul.j.murphy@intel.com>
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml
++F: drivers/media/i2c/imx335.c
++
++SONY IMX355 SENSOR DRIVER
++M: Tianshu Qiu <tian.shu.qiu@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/imx355.c
++
++SONY IMX412 SENSOR DRIVER
++M: Paul J. Murphy <paul.j.murphy@intel.com>
++M: Daniele Alessandrelli <daniele.alessandrelli@intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml
++F: drivers/media/i2c/imx412.c
++
++SONY MEMORYSTICK SUBSYSTEM
++M: Maxim Levitsky <maximlevitsky@gmail.com>
++M: Alex Dubov <oakad@yahoo.com>
++M: Ulf Hansson <ulf.hansson@linaro.org>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
++F: drivers/memstick/
++F: include/linux/memstick.h
++
++SONY VAIO CONTROL DEVICE DRIVER
++M: Mattia Dongili <malattia@linux.it>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
++F: Documentation/admin-guide/laptops/sony-laptop.rst
++F: drivers/char/sonypi.c
++F: drivers/platform/x86/sony-laptop.c
++F: include/linux/sony-laptop.h
++
++SOUND
++M: Jaroslav Kysela <perex@perex.cz>
++M: Takashi Iwai <tiwai@suse.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.alsa-project.org/
++Q: http://patchwork.kernel.org/project/alsa-devel/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: Documentation/sound/
++F: include/sound/
++F: include/uapi/sound/
++F: sound/
++
++SOUND - COMPRESSED AUDIO
++M: Vinod Koul <vkoul@kernel.org>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: Documentation/sound/designs/compress-offload.rst
++F: include/sound/compress_driver.h
++F: include/uapi/sound/compress_*
++F: sound/core/compress_offload.c
++F: sound/soc/soc-compress.c
++
++SOUND - DMAENGINE HELPERS
++M: Lars-Peter Clausen <lars@metafoo.de>
++S: Supported
++F: include/sound/dmaengine_pcm.h
++F: sound/core/pcm_dmaengine.c
++F: sound/soc/soc-generic-dmaengine-pcm.c
++
++SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
++M: Liam Girdwood <lgirdwood@gmail.com>
++M: Mark Brown <broonie@kernel.org>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++W: http://alsa-project.org/main/index.php/ASoC
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
++F: Documentation/devicetree/bindings/sound/
++F: Documentation/sound/soc/
++F: include/dt-bindings/sound/
++F: include/sound/soc*
++F: sound/soc/
++
++SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
++M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
++M: Liam Girdwood <lgirdwood@gmail.com>
++M: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
++M: Kai Vehmanen <kai.vehmanen@linux.intel.com>
++M: Daniel Baluta <daniel.baluta@nxp.com>
++L: sound-open-firmware@alsa-project.org (moderated for non-subscribers)
++S: Supported
++W: https://github.com/thesofproject/linux/
++F: sound/soc/sof/
++
++SOUNDWIRE SUBSYSTEM
++M: Vinod Koul <vkoul@kernel.org>
++M: Bard Liao <yung-chuan.liao@linux.intel.com>
++R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
++R: Sanyog Kale <sanyog.r.kale@intel.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git
++F: Documentation/driver-api/soundwire/
++F: drivers/soundwire/
++F: include/linux/soundwire/
++
++SP2 MEDIA DRIVER
++M: Olli Salonen <olli.salonen@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/sp2*
++
++SPARC + UltraSPARC (sparc/sparc64)
++M: "David S. Miller" <davem@davemloft.net>
++L: sparclinux@vger.kernel.org
++S: Maintained
++Q: http://patchwork.ozlabs.org/project/sparclinux/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
++F: arch/sparc/
++F: drivers/sbus/
++
++SPARC SERIAL DRIVERS
++M: "David S. Miller" <davem@davemloft.net>
++L: sparclinux@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
++F: drivers/tty/serial/suncore.c
++F: drivers/tty/serial/sunhv.c
++F: drivers/tty/serial/sunsab.c
++F: drivers/tty/serial/sunsab.h
++F: drivers/tty/serial/sunsu.c
++F: drivers/tty/serial/sunzilog.c
++F: drivers/tty/serial/sunzilog.h
++F: drivers/tty/vcc.c
++F: include/linux/sunserialcore.h
++
++SPARSE CHECKER
++M: "Luc Van Oostenryck" <luc.vanoostenryck@gmail.com>
++L: linux-sparse@vger.kernel.org
++S: Maintained
++W: https://sparse.docs.kernel.org/
++T: git git://git.kernel.org/pub/scm/devel/sparse/sparse.git
++Q: https://patchwork.kernel.org/project/linux-sparse/list/
++B: https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools
++F: include/linux/compiler.h
++
++SPEAKUP CONSOLE SPEECH DRIVER
++M: William Hubbs <w.d.hubbs@gmail.com>
++M: Chris Brannon <chris@the-brannons.com>
++M: Kirk Reiser <kirk@reisers.ca>
++M: Samuel Thibault <samuel.thibault@ens-lyon.org>
++L: speakup@linux-speakup.org
++S: Odd Fixes
++W: http://www.linux-speakup.org/
++W: https://github.com/linux-speakup/speakup
++B: https://github.com/linux-speakup/speakup/issues
++F: drivers/accessibility/speakup/
++
++SPEAR CLOCK FRAMEWORK SUPPORT
++M: Viresh Kumar <vireshk@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.st.com/spear
++F: drivers/clk/spear/
++
++SPEAR PLATFORM SUPPORT
++M: Viresh Kumar <vireshk@kernel.org>
++M: Shiraz Hashim <shiraz.linux.kernel@gmail.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++W: http://www.st.com/spear
++F: arch/arm/boot/dts/spear*
++F: arch/arm/mach-spear/
++
++SPI NOR SUBSYSTEM
++M: Tudor Ambarus <tudor.ambarus@microchip.com>
++R: Michael Walle <michael@walle.cc>
++R: Pratyush Yadav <p.yadav@ti.com>
++L: linux-mtd@lists.infradead.org
++S: Maintained
++W: http://www.linux-mtd.infradead.org/
++Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
++C: irc://irc.oftc.net/mtd
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next
++F: drivers/mtd/spi-nor/
++F: include/linux/mtd/spi-nor.h
++
++SPI SUBSYSTEM
++M: Mark Brown <broonie@kernel.org>
++L: linux-spi@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/spi-devel-general/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
++F: Documentation/devicetree/bindings/spi/
++F: Documentation/spi/
++F: drivers/spi/
++F: include/linux/spi/
++F: include/uapi/linux/spi/
++F: tools/spi/
++
++SPIDERNET NETWORK DRIVER for CELL
++M: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
++M: Geoff Levand <geoff@infradead.org>
++L: netdev@vger.kernel.org
++L: linuxppc-dev@lists.ozlabs.org
++S: Maintained
++F: Documentation/networking/device_drivers/ethernet/toshiba/spider_net.rst
++F: drivers/net/ethernet/toshiba/spider_net*
++
++SPMI SUBSYSTEM
++M: Stephen Boyd <sboyd@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git
++F: Documentation/devicetree/bindings/spmi/
++F: drivers/spmi/
++F: include/dt-bindings/spmi/spmi.h
++F: include/linux/spmi.h
++F: include/trace/events/spmi.h
++
++SPU FILE SYSTEM
++M: Jeremy Kerr <jk@ozlabs.org>
++L: linuxppc-dev@lists.ozlabs.org
++S: Supported
++W: http://www.ibm.com/developerworks/power/cell/
++F: Documentation/filesystems/spufs/spufs.rst
++F: arch/powerpc/platforms/cell/spufs/
++
++SQUASHFS FILE SYSTEM
++M: Phillip Lougher <phillip@squashfs.org.uk>
++L: squashfs-devel@lists.sourceforge.net (subscribers-only)
++S: Maintained
++W: http://squashfs.org.uk
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git
++F: Documentation/filesystems/squashfs.rst
++F: fs/squashfs/
++
++SRM (Alpha) environment access
++M: Jan-Benedict Glaw <jbglaw@lug-owl.de>
++S: Maintained
++F: arch/alpha/kernel/srm_env.c
++
++ST LSM6DSx IMU IIO DRIVER
++M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++W: http://www.st.com/
++F: Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml
++F: drivers/iio/imu/st_lsm6dsx/
++
++ST MIPID02 CSI-2 TO PARALLEL BRIDGE DRIVER
++M: Mickael Guene <mickael.guene@st.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt
++F: drivers/media/i2c/st-mipid02.c
++
++ST STM32 I2C/SMBUS DRIVER
++M: Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com>
++M: Alain Volmat <alain.volmat@foss.st.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-stm32*
++
++ST STM32 SPI DRIVER
++M: Alain Volmat <alain.volmat@foss.st.com>
++L: linux-spi@vger.kernel.org
++S: Maintained
++F: drivers/spi/spi-stm32.c
++
++ST STPDDC60 DRIVER
++M: Daniel Nilsson <daniel.nilsson@flex.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/stpddc60.rst
++F: drivers/hwmon/pmbus/stpddc60.c
++
++ST VL53L0X ToF RANGER(I2C) IIO DRIVER
++M: Song Qiang <songqiang1304521@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml
++F: drivers/iio/proximity/vl53l0x-i2c.c
++
++STABLE BRANCH
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++M: Sasha Levin <sashal@kernel.org>
++L: stable@vger.kernel.org
++S: Supported
++F: Documentation/process/stable-kernel-rules.rst
++
++STAGING - ATOMISP DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++R: Sakari Ailus <sakari.ailus@linux.intel.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/staging/media/atomisp/
++
++STAGING - FIELDBUS SUBSYSTEM
++M: Sven Van Asbroeck <TheSven73@gmail.com>
++S: Maintained
++F: drivers/staging/fieldbus/*
++F: drivers/staging/fieldbus/Documentation/
++
++STAGING - HMS ANYBUS-S BUS
++M: Sven Van Asbroeck <TheSven73@gmail.com>
++S: Maintained
++F: drivers/staging/fieldbus/anybuss/
++
++STAGING - INDUSTRIAL IO
++M: Jonathan Cameron <jic23@kernel.org>
++L: linux-iio@vger.kernel.org
++S: Odd Fixes
++F: Documentation/devicetree/bindings/staging/iio/
++F: drivers/staging/iio/
++
++STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
++M: Marc Dietrich <marvin24@gmx.de>
++L: ac100@lists.launchpad.net (moderated for non-subscribers)
++L: linux-tegra@vger.kernel.org
++S: Maintained
++F: drivers/staging/nvec/
++
++STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON)
++M: Jens Frederich <jfrederich@gmail.com>
++M: Jon Nettleton <jon.nettleton@gmail.com>
++S: Maintained
++W: http://wiki.laptop.org/go/DCON
++F: drivers/staging/olpc_dcon/
++
++STAGING - REALTEK RTL8188EU DRIVERS
++M: Larry Finger <Larry.Finger@lwfinger.net>
++M: Phillip Potter <phil@philpotter.co.uk>
++S: Supported
++F: drivers/staging/r8188eu/
++
++STAGING - REALTEK RTL8712U DRIVERS
++M: Larry Finger <Larry.Finger@lwfinger.net>
++M: Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
++S: Odd Fixes
++F: drivers/staging/rtl8712/
++
++STAGING - SEPS525 LCD CONTROLLER DRIVERS
++M: Michael Hennerich <michael.hennerich@analog.com>
++L: linux-fbdev@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
++F: drivers/staging/fbtft/fb_seps525.c
++
++STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER
++M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
++M: Teddy Wang <teddy.wang@siliconmotion.com>
++M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/staging/sm750fb/
++
++STAGING - VIA VT665X DRIVERS
++M: Forest Bond <forest@alittletooquiet.net>
++S: Odd Fixes
++F: drivers/staging/vt665?/
++
++STAGING SUBSYSTEM
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-staging@lists.linux.dev
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
++F: drivers/staging/
++
++STARFIRE/DURALAN NETWORK DRIVER
++M: Ion Badulescu <ionut@badula.org>
++S: Odd Fixes
++F: drivers/net/ethernet/adaptec/starfire*
++
++STATIC BRANCH/CALL
++M: Peter Zijlstra <peterz@infradead.org>
++M: Josh Poimboeuf <jpoimboe@redhat.com>
++M: Jason Baron <jbaron@akamai.com>
++R: Steven Rostedt <rostedt@goodmis.org>
++R: Ard Biesheuvel <ardb@kernel.org>
++S: Supported
++F: arch/*/include/asm/jump_label*.h
++F: arch/*/include/asm/static_call*.h
++F: arch/*/kernel/jump_label.c
++F: arch/*/kernel/static_call.c
++F: include/linux/jump_label*.h
++F: include/linux/static_call*.h
++F: kernel/jump_label.c
++F: kernel/static_call.c
++
++STI AUDIO (ASoC) DRIVERS
++M: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
++F: sound/soc/sti/
++
++STI CEC DRIVER
++M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
++S: Maintained
++F: Documentation/devicetree/bindings/media/stih-cec.txt
++F: drivers/media/cec/platform/sti/
++
++STK1160 USB VIDEO CAPTURE DRIVER
++M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
++L: linux-media@vger.kernel.org
++S: Maintained
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/stk1160/
++
++STM32 AUDIO (ASoC) DRIVERS
++M: Olivier Moysan <olivier.moysan@foss.st.com>
++M: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
++F: Documentation/devicetree/bindings/sound/st,stm32-*.yaml
++F: sound/soc/stm/
++
++STM32 TIMER/LPTIMER DRIVERS
++M: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
++S: Maintained
++F: Documentation/ABI/testing/*timer-stm32
++F: Documentation/devicetree/bindings/*/*stm32-*timer*
++F: drivers/*/stm32-*timer*
++F: drivers/pwm/pwm-stm32*
++F: include/linux/*/stm32-*tim*
++
++STMMAC ETHERNET DRIVER
++M: Giuseppe Cavallaro <peppe.cavallaro@st.com>
++M: Alexandre Torgue <alexandre.torgue@foss.st.com>
++M: Jose Abreu <joabreu@synopsys.com>
++L: netdev@vger.kernel.org
++S: Supported
++W: http://www.stlinux.com
++F: Documentation/networking/device_drivers/ethernet/stmicro/
++F: drivers/net/ethernet/stmicro/stmmac/
++
++SUN3/3X
++M: Sam Creasey <sammy@sammy.net>
++S: Maintained
++W: http://sammy.net/sun3/
++F: arch/m68k/include/asm/sun3*
++F: arch/m68k/kernel/*sun3*
++F: arch/m68k/sun3*/
++F: drivers/net/ethernet/i825xx/sun3*
++
++SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml
++F: drivers/input/keyboard/sun4i-lradc-keys.c
++
++SUNDANCE NETWORK DRIVER
++M: Denis Kirjanov <kda@linux-powerpc.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/dlink/sundance.c
++
++SUPERH
++M: Yoshinori Sato <ysato@users.sourceforge.jp>
++M: Rich Felker <dalias@libc.org>
++L: linux-sh@vger.kernel.org
++S: Maintained
++Q: http://patchwork.kernel.org/project/linux-sh/list/
++F: Documentation/sh/
++F: arch/sh/
++F: drivers/sh/
++
++SUSPEND TO RAM
++M: "Rafael J. Wysocki" <rafael@kernel.org>
++M: Len Brown <len.brown@intel.com>
++M: Pavel Machek <pavel@ucw.cz>
++L: linux-pm@vger.kernel.org
++S: Supported
++B: https://bugzilla.kernel.org
++F: Documentation/power/
++F: arch/x86/kernel/acpi/
++F: drivers/base/power/
++F: include/linux/freezer.h
++F: include/linux/pm.h
++F: include/linux/suspend.h
++F: kernel/power/
++
++SVGA HANDLING
++M: Martin Mares <mj@ucw.cz>
++L: linux-video@atrey.karlin.mff.cuni.cz
++S: Maintained
++F: Documentation/admin-guide/svga.rst
++F: arch/x86/boot/video*
++
++SWIOTLB SUBSYSTEM
++M: Christoph Hellwig <hch@infradead.org>
++L: iommu@lists.linux-foundation.org
++S: Supported
++W: http://git.infradead.org/users/hch/dma-mapping.git
++T: git git://git.infradead.org/users/hch/dma-mapping.git
++F: arch/*/kernel/pci-swiotlb.c
++F: include/linux/swiotlb.h
++F: kernel/dma/swiotlb.c
++
++SWITCHDEV
++M: Jiri Pirko <jiri@resnulli.us>
++M: Ivan Vecera <ivecera@redhat.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: include/net/switchdev.h
++F: net/switchdev/
++
++SY8106A REGULATOR DRIVER
++M: Icenowy Zheng <icenowy@aosc.io>
++S: Maintained
++F: Documentation/devicetree/bindings/regulator/silergy,sy8106a.yaml
++F: drivers/regulator/sy8106a-regulator.c
++
++SYNC FILE FRAMEWORK
++M: Sumit Semwal <sumit.semwal@linaro.org>
++R: Gustavo Padovan <gustavo@padovan.org>
++L: linux-media@vger.kernel.org
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/driver-api/sync_file.rst
++F: drivers/dma-buf/dma-fence*
++F: drivers/dma-buf/sw_sync.c
++F: drivers/dma-buf/sync_*
++F: include/linux/sync_file.h
++F: include/uapi/linux/sync_file.h
++
++SYNOPSYS ARC ARCHITECTURE
++M: Vineet Gupta <vgupta@kernel.org>
++L: linux-snps-arc@lists.infradead.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
++F: Documentation/devicetree/bindings/arc/*
++F: Documentation/devicetree/bindings/interrupt-controller/snps,arc*
++F: arch/arc/
++F: drivers/clocksource/arc_timer.c
++F: drivers/tty/serial/arc_uart.c
++
++SYNOPSYS ARC HSDK SDP pll clock driver
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
++F: drivers/clk/clk-hsdk-pll.c
++
++SYNOPSYS ARC SDP clock driver
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
++F: drivers/clk/axs10x/*
++
++SYNOPSYS ARC SDP platform support
++M: Alexey Brodkin <abrodkin@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/arc/axs10*
++F: arch/arc/boot/dts/ax*
++F: arch/arc/plat-axs10x
++
++SYNOPSYS AXS10x RESET CONTROLLER DRIVER
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt
++F: drivers/reset/reset-axs10x.c
++
++SYNOPSYS CREG GPIO DRIVER
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt
++F: drivers/gpio/gpio-creg-snps.c
++
++SYNOPSYS DESIGNWARE 8250 UART DRIVER
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++S: Maintained
++F: drivers/tty/serial/8250/8250_dw.c
++F: drivers/tty/serial/8250/8250_dwlib.*
++F: drivers/tty/serial/8250/8250_lpss.c
++
++SYNOPSYS DESIGNWARE APB GPIO DRIVER
++M: Hoan Tran <hoan@os.amperecomputing.com>
++M: Serge Semin <fancer.lancer@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
++F: drivers/gpio/gpio-dwapb.c
++
++SYNOPSYS DESIGNWARE APB SSI DRIVER
++M: Serge Semin <fancer.lancer@gmail.com>
++L: linux-spi@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
++F: drivers/spi/spi-dw*
++
++SYNOPSYS DESIGNWARE AXI DMAC DRIVER
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Maintained
++F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
++F: drivers/dma/dw-axi-dmac/
++
++SYNOPSYS DESIGNWARE DMAC DRIVER
++M: Viresh Kumar <vireshk@kernel.org>
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++S: Maintained
++F: Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml
++F: drivers/dma/dw/
++F: include/dt-bindings/dma/dw-dmac.h
++F: include/linux/dma/dw.h
++F: include/linux/platform_data/dma-dw.h
++
++SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
++M: Jose Abreu <Jose.Abreu@synopsys.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/synopsys/
++
++SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
++M: Jose Abreu <Jose.Abreu@synopsys.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/pcs/pcs-xpcs.c
++F: drivers/net/pcs/pcs-xpcs.h
++F: include/linux/pcs/pcs-xpcs.h
++
++SYNOPSYS DESIGNWARE I2C DRIVER
++M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++R: Mika Westerberg <mika.westerberg@linux.intel.com>
++L: linux-i2c@vger.kernel.org
++S: Maintained
++F: drivers/i2c/busses/i2c-designware-*
++
++SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
++M: Jaehoon Chung <jh80.chung@samsung.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/dw_mmc*
++
++SYNOPSYS HSDK RESET CONTROLLER DRIVER
++M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
++S: Supported
++F: Documentation/devicetree/bindings/reset/snps,hsdk-reset.txt
++F: drivers/reset/reset-hsdk.c
++F: include/dt-bindings/reset/snps,hsdk-reset.h
++
++SYNOPSYS SDHCI COMPLIANT DWC MSHC DRIVER
++M: Prabu Thangamuthu <prabu.t@synopsys.com>
++M: Manjunath M B <manjumb@synopsys.com>
++L: linux-mmc@vger.kernel.org
++S: Maintained
++F: drivers/mmc/host/sdhci-pci-dwc-mshc.c
++
++SYSTEM CONFIGURATION (SYSCON)
++M: Lee Jones <lee.jones@linaro.org>
++M: Arnd Bergmann <arnd@arndb.de>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
++F: drivers/mfd/syscon.c
++
++SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers
++M: Sudeep Holla <sudeep.holla@arm.com>
++R: Cristian Marussi <cristian.marussi@arm.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/firmware/arm,sc[mp]i.yaml
++F: drivers/clk/clk-sc[mp]i.c
++F: drivers/cpufreq/sc[mp]i-cpufreq.c
++F: drivers/firmware/arm_scmi/
++F: drivers/firmware/arm_scpi.c
++F: drivers/regulator/scmi-regulator.c
++F: drivers/reset/reset-scmi.c
++F: include/linux/sc[mp]i_protocol.h
++F: include/trace/events/scmi.h
++F: include/uapi/linux/virtio_scmi.h
++
++SYSTEM RESET/SHUTDOWN DRIVERS
++M: Sebastian Reichel <sre@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
++F: Documentation/devicetree/bindings/power/reset/
++F: drivers/power/reset/
++
++SYSTEM TRACE MODULE CLASS
++M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
++F: Documentation/trace/stm.rst
++F: drivers/hwtracing/stm/
++F: include/linux/stm.h
++F: include/uapi/linux/stm.h
++
++SYSTEM76 ACPI DRIVER
++M: Jeremy Soller <jeremy@system76.com>
++M: System76 Product Development <productdev@system76.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/system76_acpi.c
++
++SYSV FILESYSTEM
++M: Christoph Hellwig <hch@infradead.org>
++S: Maintained
++F: Documentation/filesystems/sysv-fs.rst
++F: fs/sysv/
++F: include/linux/sysv_fs.h
++
++TASKSTATS STATISTICS INTERFACE
++M: Balbir Singh <bsingharora@gmail.com>
++S: Maintained
++F: Documentation/accounting/taskstats*
++F: include/linux/taskstats*
++F: kernel/taskstats.c
++
++TC subsystem
++M: Jamal Hadi Salim <jhs@mojatatu.com>
++M: Cong Wang <xiyou.wangcong@gmail.com>
++M: Jiri Pirko <jiri@resnulli.us>
++L: netdev@vger.kernel.org
++S: Maintained
++F: include/net/pkt_cls.h
++F: include/net/pkt_sched.h
++F: include/net/tc_act/
++F: include/uapi/linux/pkt_cls.h
++F: include/uapi/linux/pkt_sched.h
++F: include/uapi/linux/tc_act/
++F: include/uapi/linux/tc_ematch/
++F: net/sched/
++
++TC90522 MEDIA DRIVER
++M: Akihiro Tsukada <tskd08@gmail.com>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++F: drivers/media/dvb-frontends/tc90522*
++
++TCP LOW PRIORITY MODULE
++M: "Wong Hoi Sing, Edison" <hswong3i@gmail.com>
++M: "Hung Hing Lun, Mike" <hlhung3i@gmail.com>
++S: Maintained
++W: http://tcp-lp-mod.sourceforge.net/
++F: net/ipv4/tcp_lp.c
++
++TDA10071 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/dvb-frontends/tda10071*
++
++TDA18212 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/tda18212*
++
++TDA18218 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/tda18218*
++
++TDA18250 MEDIA DRIVER
++M: Olli Salonen <olli.salonen@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/tuners/tda18250*
++
++TDA18271 MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/tuners/tda18271*
++
++TDA1997x MEDIA DRIVER
++M: Tim Harvey <tharvey@gateworks.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/i2c/tda1997x.*
++
++TDA827x MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/tuners/tda8290.*
++
++TDA8290 MEDIA DRIVER
++M: Michael Krufky <mkrufky@linuxtv.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://github.com/mkrufky
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mkrufky/tuners.git
++F: drivers/media/tuners/tda8290.*
++
++TDA9840 MEDIA DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/tda9840*
++
++TEA5761 TUNER DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/tuners/tea5761.*
++
++TEA5767 TUNER DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/tuners/tea5767.*
++
++TEA6415C MEDIA DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/tea6415c*
++
++TEA6420 MEDIA DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/i2c/tea6420*
++
++TEAM DRIVER
++M: Jiri Pirko <jiri@resnulli.us>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/team/
++F: include/linux/if_team.h
++F: include/uapi/linux/if_team.h
++
++TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
++M: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
++S: Maintained
++F: arch/x86/platform/ts5500/
++
++TECHNOTREND USB IR RECEIVER
++M: Sean Young <sean@mess.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/rc/ttusbir.c
++
++TECHWELL TW9910 VIDEO DECODER
++L: linux-media@vger.kernel.org
++S: Orphan
++F: drivers/media/i2c/tw9910.c
++F: include/media/i2c/tw9910.h
++
++TEE SUBSYSTEM
++M: Jens Wiklander <jens.wiklander@linaro.org>
++R: Sumit Garg <sumit.garg@linaro.org>
++L: op-tee@lists.trustedfirmware.org
++S: Maintained
++F: Documentation/staging/tee.rst
++F: drivers/tee/
++F: include/linux/tee_drv.h
++F: include/uapi/linux/tee.h
++
++TEGRA ARCHITECTURE SUPPORT
++M: Thierry Reding <thierry.reding@gmail.com>
++M: Jonathan Hunter <jonathanh@nvidia.com>
++L: linux-tegra@vger.kernel.org
++S: Supported
++Q: http://patchwork.ozlabs.org/project/linux-tegra/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git
++N: [^a-z]tegra
++
++TEGRA CLOCK DRIVER
++M: Peter De Schrijver <pdeschrijver@nvidia.com>
++M: Prashant Gaikwad <pgaikwad@nvidia.com>
++S: Supported
++F: drivers/clk/tegra/
++
++TEGRA DMA DRIVERS
++M: Laxman Dewangan <ldewangan@nvidia.com>
++M: Jon Hunter <jonathanh@nvidia.com>
++S: Supported
++F: drivers/dma/tegra*
++
++TEGRA I2C DRIVER
++M: Laxman Dewangan <ldewangan@nvidia.com>
++R: Dmitry Osipenko <digetx@gmail.com>
++S: Supported
++F: drivers/i2c/busses/i2c-tegra.c
++
++TEGRA IOMMU DRIVERS
++M: Thierry Reding <thierry.reding@gmail.com>
++R: Krishna Reddy <vdumpa@nvidia.com>
++L: linux-tegra@vger.kernel.org
++S: Supported
++F: drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c
++F: drivers/iommu/tegra*
++
++TEGRA KBC DRIVER
++M: Laxman Dewangan <ldewangan@nvidia.com>
++S: Supported
++F: drivers/input/keyboard/tegra-kbc.c
++
++TEGRA NAND DRIVER
++M: Stefan Agner <stefan@agner.ch>
++M: Lucas Stach <dev@lynxeye.de>
++S: Maintained
++F: Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt
++F: drivers/mtd/nand/raw/tegra_nand.c
++
++TEGRA PWM DRIVER
++M: Thierry Reding <thierry.reding@gmail.com>
++S: Supported
++F: drivers/pwm/pwm-tegra.c
++
++TEGRA SERIAL DRIVER
++M: Laxman Dewangan <ldewangan@nvidia.com>
++S: Supported
++F: drivers/tty/serial/serial-tegra.c
++
++TEGRA SPI DRIVER
++M: Laxman Dewangan <ldewangan@nvidia.com>
++S: Supported
++F: drivers/spi/spi-tegra*
++
++TEGRA QUAD SPI DRIVER
++M: Thierry Reding <thierry.reding@gmail.com>
++M: Jonathan Hunter <jonathanh@nvidia.com>
++M: Sowjanya Komatineni <skomatineni@nvidia.com>
++L: linux-tegra@vger.kernel.org
++S: Maintained
++F: drivers/spi/spi-tegra210-quad.c
++
++TEGRA VIDEO DRIVER
++M: Thierry Reding <thierry.reding@gmail.com>
++M: Jonathan Hunter <jonathanh@nvidia.com>
++M: Sowjanya Komatineni <skomatineni@nvidia.com>
++L: linux-media@vger.kernel.org
++L: linux-tegra@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
++F: drivers/staging/media/tegra-video/
++
++TEGRA XUSB PADCTL DRIVER
++M: JC Kuo <jckuo@nvidia.com>
++S: Supported
++F: drivers/phy/tegra/xusb*
++
++TEHUTI ETHERNET DRIVER
++M: Andy Gospodarek <andy@greyhouse.net>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/ethernet/tehuti/*
++
++TELECOM CLOCK DRIVER FOR MCPL0010
++M: Mark Gross <mark.gross@intel.com>
++S: Supported
++F: drivers/char/tlclk.c
++
++TEMPO SEMICONDUCTOR DRIVERS
++M: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
++S: Maintained
++F: Documentation/devicetree/bindings/sound/tscs*.txt
++F: sound/soc/codecs/tscs*.c
++F: sound/soc/codecs/tscs*.h
++
++TENSILICA XTENSA PORT (xtensa)
++M: Chris Zankel <chris@zankel.net>
++M: Max Filippov <jcmvbkbc@gmail.com>
++L: linux-xtensa@linux-xtensa.org
++S: Maintained
++T: git git://github.com/czankel/xtensa-linux.git
++F: arch/xtensa/
++F: drivers/irqchip/irq-xtensa-*
++
++TEXAS INSTRUMENTS ASoC DRIVERS
++M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: sound/soc/ti/
++
++TEXAS INSTRUMENTS' DAC7612 DAC DRIVER
++M: Ricardo Ribalda <ribalda@kernel.org>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml
++F: drivers/iio/dac/ti-dac7612.c
++
++TEXAS INSTRUMENTS DMA DRIVERS
++M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
++L: dmaengine@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
++F: Documentation/devicetree/bindings/dma/ti-edma.txt
++F: Documentation/devicetree/bindings/dma/ti/
++F: drivers/dma/ti/
++X: drivers/dma/ti/cppi41.c
++F: include/linux/dma/k3-udma-glue.h
++F: include/linux/dma/ti-cppi5.h
++F: include/linux/dma/k3-psil.h
++
++TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER
++M: Nishanth Menon <nm@ti.com>
++M: Tero Kristo <kristo@kernel.org>
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml
++F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
++F: Documentation/devicetree/bindings/clock/ti,sci-clk.yaml
++F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml
++F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml
++F: Documentation/devicetree/bindings/reset/ti,sci-reset.yaml
++F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.yaml
++F: drivers/clk/keystone/sci-clk.c
++F: drivers/firmware/ti_sci*
++F: drivers/irqchip/irq-ti-sci-inta.c
++F: drivers/irqchip/irq-ti-sci-intr.c
++F: drivers/reset/reset-ti-sci.c
++F: drivers/soc/ti/ti_sci_inta_msi.c
++F: drivers/soc/ti/ti_sci_pm_domains.c
++F: include/dt-bindings/soc/ti,sci_pm_domain.h
++F: include/linux/soc/ti/ti_sci_inta_msi.h
++F: include/linux/soc/ti/ti_sci_protocol.h
++
++TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER
++M: Robert Marko <robert.marko@sartura.hr>
++M: Luka Perkov <luka.perkov@sartura.hr>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml
++F: Documentation/hwmon/tps23861.rst
++F: drivers/hwmon/tps23861.c
++
++TEXAS INSTRUMENTS' TMP117 TEMPERATURE SENSOR DRIVER
++M: Puranjay Mohan <puranjay12@gmail.com>
++L: linux-iio@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
++F: drivers/iio/temperature/tmp117.c
++
++THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/radio/radio-raremono.c
++
++THERMAL
++M: Rafael J. Wysocki <rafael@kernel.org>
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++R: Amit Kucheria <amitk@kernel.org>
++R: Zhang Rui <rui.zhang@intel.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-pm/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git thermal
++F: Documentation/devicetree/bindings/thermal/
++F: drivers/thermal/
++F: include/linux/cpu_cooling.h
++F: include/linux/thermal.h
++F: include/uapi/linux/thermal.h
++F: tools/thermal/
++
++THERMAL DRIVER FOR AMLOGIC SOCS
++M: Guillaume La Roque <glaroque@baylibre.com>
++L: linux-pm@vger.kernel.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++W: http://linux-meson.com/
++F: Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
++F: drivers/thermal/amlogic_thermal.c
++
++THERMAL/CPU_COOLING
++M: Amit Daniel Kachhap <amit.kachhap@gmail.com>
++M: Daniel Lezcano <daniel.lezcano@linaro.org>
++M: Viresh Kumar <viresh.kumar@linaro.org>
++R: Lukasz Luba <lukasz.luba@arm.com>
++L: linux-pm@vger.kernel.org
++S: Supported
++F: Documentation/driver-api/thermal/cpu-cooling-api.rst
++F: Documentation/driver-api/thermal/cpu-idle-cooling.rst
++F: drivers/thermal/cpufreq_cooling.c
++F: drivers/thermal/cpuidle_cooling.c
++F: include/linux/cpu_cooling.h
++
++THERMAL/POWER_ALLOCATOR
++M: Lukasz Luba <lukasz.luba@arm.com>
++L: linux-pm@vger.kernel.org
++S: Maintained
++F: Documentation/driver-api/thermal/power_allocator.rst
++F: drivers/thermal/gov_power_allocator.c
++F: include/trace/events/thermal_power_allocator.h
++
++THINKPAD ACPI EXTRAS DRIVER
++M: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
++L: ibm-acpi-devel@lists.sourceforge.net
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++W: http://ibm-acpi.sourceforge.net
++W: http://thinkwiki.org/wiki/Ibm-acpi
++T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
++F: drivers/platform/x86/thinkpad_acpi.c
++
++THINKPAD LMI DRIVER
++M: Mark Pearson <markpearson@lenovo.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-firmware-attributes
++F: drivers/platform/x86/think-lmi.?
++
++THUNDERBOLT DMA TRAFFIC TEST DRIVER
++M: Isaac Hazan <isaac.hazan@intel.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/thunderbolt/dma_test.c
++
++THUNDERBOLT DRIVER
++M: Andreas Noever <andreas.noever@gmail.com>
++M: Michael Jamet <michael.jamet@intel.com>
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++M: Yehezkel Bernat <YehezkelShB@gmail.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git
++F: Documentation/admin-guide/thunderbolt.rst
++F: drivers/thunderbolt/
++F: include/linux/thunderbolt.h
++
++THUNDERBOLT NETWORK DRIVER
++M: Michael Jamet <michael.jamet@intel.com>
++M: Mika Westerberg <mika.westerberg@linux.intel.com>
++M: Yehezkel Bernat <YehezkelShB@gmail.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/thunderbolt.c
++
++THUNDERX GPIO DRIVER
++M: Robert Richter <rric@kernel.org>
++S: Odd Fixes
++F: drivers/gpio/gpio-thunderx.c
++
++TI ADS131E0X ADC SERIES DRIVER
++M: Tomislav Denis <tomislav.denis@avl.com>
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml
++F: drivers/iio/adc/ti-ads131e08.c
++
++TI AM437X VPFE DRIVER
++M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
++F: drivers/media/platform/am437x/
++
++TI BANDGAP AND THERMAL DRIVER
++M: Eduardo Valentin <edubezval@gmail.com>
++M: Keerthy <j-keerthy@ti.com>
++L: linux-pm@vger.kernel.org
++L: linux-omap@vger.kernel.org
++S: Maintained
++F: drivers/thermal/ti-soc-thermal/
++
++TI BQ27XXX POWER SUPPLY DRIVER
++F: drivers/power/supply/bq27xxx_battery.c
++F: drivers/power/supply/bq27xxx_battery_i2c.c
++F: include/linux/power/bq27xxx_battery.h
++
++TI CDCE706 CLOCK DRIVER
++M: Max Filippov <jcmvbkbc@gmail.com>
++S: Maintained
++F: drivers/clk/clk-cdce706.c
++
++TI CLOCK DRIVER
++M: Tero Kristo <kristo@kernel.org>
++L: linux-omap@vger.kernel.org
++S: Odd Fixes
++F: drivers/clk/ti/
++F: include/linux/clk/ti.h
++
++TI DAVINCI MACHINE SUPPORT
++M: Sekhar Nori <nsekhar@ti.com>
++R: Bartosz Golaszewski <brgl@bgdev.pl>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
++F: Documentation/devicetree/bindings/i2c/i2c-davinci.txt
++F: arch/arm/boot/dts/da850*
++F: arch/arm/mach-davinci/
++F: drivers/i2c/busses/i2c-davinci.c
++
++TI DAVINCI SERIES CLOCK DRIVER
++M: David Lechner <david@lechnology.com>
++R: Sekhar Nori <nsekhar@ti.com>
++S: Maintained
++F: Documentation/devicetree/bindings/clock/ti/davinci/
++F: drivers/clk/davinci/
++
++TI DAVINCI SERIES GPIO DRIVER
++M: Keerthy <j-keerthy@ti.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/gpio-davinci.yaml
++F: drivers/gpio/gpio-davinci.c
++
++TI DAVINCI SERIES MEDIA DRIVER
++M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
++F: drivers/media/platform/davinci/
++F: include/media/davinci/
++
++TI ENHANCED QUADRATURE ENCODER PULSE (eQEP) DRIVER
++R: David Lechner <david@lechnology.com>
++L: linux-iio@vger.kernel.org
++F: Documentation/devicetree/bindings/counter/ti-eqep.yaml
++F: drivers/counter/ti-eqep.c
++
++TI ETHERNET SWITCH DRIVER (CPSW)
++R: Grygorii Strashko <grygorii.strashko@ti.com>
++L: linux-omap@vger.kernel.org
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/ti/cpsw*
++F: drivers/net/ethernet/ti/davinci*
++
++TI FLASH MEDIA MEMORYSTICK/MMC DRIVERS
++M: Alex Dubov <oakad@yahoo.com>
++S: Maintained
++W: http://tifmxx.berlios.de/
++F: drivers/memstick/host/tifm_ms.c
++F: drivers/misc/tifm*
++F: drivers/mmc/host/tifm_sd.c
++F: include/linux/tifm.h
++
++TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
++M: Santosh Shilimkar <ssantosh@kernel.org>
++L: linux-kernel@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
++F: drivers/soc/ti/*
++
++TI LM49xxx FAMILY ASoC CODEC DRIVERS
++M: M R Swami Reddy <mr.swami.reddy@ti.com>
++M: Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: sound/soc/codecs/isabelle*
++F: sound/soc/codecs/lm49453*
++
++TI PCM3060 ASoC CODEC DRIVER
++M: Kirill Marinushkin <kmarinushkin@birdec.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: Documentation/devicetree/bindings/sound/pcm3060.txt
++F: sound/soc/codecs/pcm3060*
++
++TI TAS571X FAMILY ASoC CODEC DRIVER
++M: Kevin Cernekee <cernekee@chromium.org>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Odd Fixes
++F: sound/soc/codecs/tas571x*
++
++TI TRF7970A NFC DRIVER
++M: Mark Greer <mgreer@animalcreek.com>
++L: linux-wireless@vger.kernel.org
++L: linux-nfc@lists.01.org (subscribers-only)
++S: Supported
++F: Documentation/devicetree/bindings/net/nfc/trf7970a.txt
++F: drivers/nfc/trf7970a.c
++
++TI TSC2046 ADC DRIVER
++M: Oleksij Rempel <o.rempel@pengutronix.de>
++R: kernel@pengutronix.de
++L: linux-iio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml
++F: drivers/iio/adc/ti-tsc2046.c
++
++TI TWL4030 SERIES SOC CODEC DRIVER
++M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: sound/soc/codecs/twl4030*
++
++TI VPE/CAL DRIVERS
++M: Benoit Parrot <bparrot@ti.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://linuxtv.org/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++F: Documentation/devicetree/bindings/media/ti,cal.yaml
++F: Documentation/devicetree/bindings/media/ti,vpe.yaml
++F: drivers/media/platform/ti-vpe/
++
++TI WILINK WIRELESS DRIVERS
++L: linux-wireless@vger.kernel.org
++S: Orphan
++W: https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx
++W: https://wireless.wiki.kernel.org/en/users/Drivers/wl1251
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
++F: drivers/net/wireless/ti/
++F: include/linux/wl12xx.h
++
++TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
++M: John Stultz <john.stultz@linaro.org>
++M: Thomas Gleixner <tglx@linutronix.de>
++R: Stephen Boyd <sboyd@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
++F: include/linux/clocksource.h
++F: include/linux/time.h
++F: include/linux/timex.h
++F: include/uapi/linux/time.h
++F: include/uapi/linux/timex.h
++F: kernel/time/alarmtimer.c
++F: kernel/time/clocksource.c
++F: kernel/time/ntp.c
++F: kernel/time/time*.c
++F: tools/testing/selftests/timers/
++
++TIPC NETWORK LAYER
++M: Jon Maloy <jmaloy@redhat.com>
++M: Ying Xue <ying.xue@windriver.com>
++L: netdev@vger.kernel.org (core kernel code)
++L: tipc-discussion@lists.sourceforge.net (user apps, general discussion)
++S: Maintained
++W: http://tipc.sourceforge.net/
++F: include/uapi/linux/tipc*.h
++F: net/tipc/
++
++TLAN NETWORK DRIVER
++M: Samuel Chessman <chessman@tux.org>
++L: tlan-devel@lists.sourceforge.net (subscribers-only)
++S: Maintained
++W: http://sourceforge.net/projects/tlan/
++F: Documentation/networking/device_drivers/ethernet/ti/tlan.rst
++F: drivers/net/ethernet/ti/tlan.*
++
++TM6000 VIDEO4LINUX DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Odd fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/tm6000*
++F: drivers/media/usb/tm6000/
++
++TMIO/SDHI MMC DRIVER
++M: Wolfram Sang <wsa+renesas@sang-engineering.com>
++L: linux-mmc@vger.kernel.org
++S: Supported
++F: drivers/mmc/host/renesas_sdhi*
++F: drivers/mmc/host/tmio_mmc*
++F: include/linux/mfd/tmio.h
++
++TMP401 HARDWARE MONITOR DRIVER
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/tmp401.rst
++F: drivers/hwmon/tmp401.c
++
++TMP513 HARDWARE MONITOR DRIVER
++M: Eric Tremblay <etremblay@distech-controls.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/tmp513.rst
++F: drivers/hwmon/tmp513.c
++
++TMPFS (SHMEM FILESYSTEM)
++M: Hugh Dickins <hughd@google.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: include/linux/shmem_fs.h
++F: mm/shmem.c
++
++TOMOYO SECURITY MODULE
++M: Kentaro Takeda <takedakn@nttdata.co.jp>
++M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
++L: tomoyo-dev-en@lists.osdn.me (subscribers-only, for developers in English)
++L: tomoyo-users-en@lists.osdn.me (subscribers-only, for users in English)
++L: tomoyo-dev@lists.osdn.me (subscribers-only, for developers in Japanese)
++L: tomoyo-users@lists.osdn.me (subscribers-only, for users in Japanese)
++S: Maintained
++W: https://tomoyo.osdn.jp/
++F: security/tomoyo/
++
++TOPSTAR LAPTOP EXTRAS DRIVER
++M: Herton Ronaldo Krzesinski <herton@canonical.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/topstar-laptop.c
++
++TORTURE-TEST MODULES
++M: Davidlohr Bueso <dave@stgolabs.net>
++M: "Paul E. McKenney" <paulmck@kernel.org>
++M: Josh Triplett <josh@joshtriplett.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
++F: Documentation/RCU/torture.rst
++F: kernel/locking/locktorture.c
++F: kernel/rcu/rcuscale.c
++F: kernel/rcu/rcutorture.c
++F: kernel/rcu/refscale.c
++F: kernel/torture.c
++
++TOSHIBA ACPI EXTRAS DRIVER
++M: Azael Avalos <coproscefalo@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/toshiba_acpi.c
++
++TOSHIBA BLUETOOTH DRIVER
++M: Azael Avalos <coproscefalo@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/toshiba_bluetooth.c
++
++TOSHIBA HDD ACTIVE PROTECTION SENSOR DRIVER
++M: Azael Avalos <coproscefalo@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/toshiba_haps.c
++
++TOSHIBA SMM DRIVER
++M: Jonathan Buzzard <jonathan@buzzard.org.uk>
++S: Maintained
++W: http://www.buzzard.org.uk/toshiba/
++F: drivers/char/toshiba.c
++F: include/linux/toshiba.h
++F: include/uapi/linux/toshiba.h
++
++TOSHIBA TC358743 DRIVER
++M: Mats Randgaard <matrandg@cisco.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/tc358743*
++F: include/media/i2c/tc358743.h
++
++TOSHIBA WMI HOTKEYS DRIVER
++M: Azael Avalos <coproscefalo@gmail.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/toshiba-wmi.c
++
++TPM DEVICE DRIVER
++M: Peter Huewe <peterhuewe@gmx.de>
++M: Jarkko Sakkinen <jarkko@kernel.org>
++R: Jason Gunthorpe <jgg@ziepe.ca>
++L: linux-integrity@vger.kernel.org
++S: Maintained
++W: https://kernsec.org/wiki/index.php/Linux_Kernel_Integrity
++Q: https://patchwork.kernel.org/project/linux-integrity/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git
++F: drivers/char/tpm/
++
++TRACING
++M: Steven Rostedt <rostedt@goodmis.org>
++M: Ingo Molnar <mingo@redhat.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
++F: Documentation/trace/ftrace.rst
++F: arch/*/*/*/ftrace.h
++F: arch/*/kernel/ftrace.c
++F: fs/tracefs/
++F: include/*/ftrace.h
++F: include/linux/trace*.h
++F: include/trace/
++F: kernel/trace/
++F: tools/testing/selftests/ftrace/
++
++TRACING MMIO ACCESSES (MMIOTRACE)
++M: Steven Rostedt <rostedt@goodmis.org>
++M: Ingo Molnar <mingo@kernel.org>
++R: Karol Herbst <karolherbst@gmail.com>
++R: Pekka Paalanen <ppaalanen@gmail.com>
++L: linux-kernel@vger.kernel.org
++L: nouveau@lists.freedesktop.org
++S: Maintained
++F: arch/x86/mm/kmmio.c
++F: arch/x86/mm/mmio-mod.c
++F: arch/x86/mm/testmmiotrace.c
++F: include/linux/mmiotrace.h
++F: kernel/trace/trace_mmiotrace.c
++
++TRACING OS NOISE / LATENCY TRACERS
++M: Steven Rostedt <rostedt@goodmis.org>
++M: Daniel Bristot de Oliveira <bristot@kernel.org>
++S: Maintained
++F: kernel/trace/trace_osnoise.c
++F: include/trace/events/osnoise.h
++F: kernel/trace/trace_hwlat.c
++F: kernel/trace/trace_irqsoff.c
++F: kernel/trace/trace_sched_wakeup.c
++F: Documentation/trace/osnoise-tracer.rst
++F: Documentation/trace/timerlat-tracer.rst
++F: Documentation/trace/hwlat_detector.rst
++F: arch/*/kernel/trace.c
++
++TRADITIONAL CHINESE DOCUMENTATION
++M: Hu Haowen <src.res@email.cn>
++L: linux-doc-tw-discuss@lists.sourceforge.net
++S: Maintained
++W: https://github.com/srcres258/linux-doc
++T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
++F: Documentation/translations/zh_TW/
++
++TRIVIAL PATCHES
++M: Jiri Kosina <trivial@kernel.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
++K: ^Subject:.*(?i)trivial
++
++TTY LAYER
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++M: Jiri Slaby <jirislaby@kernel.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
++F: Documentation/driver-api/serial/
++F: drivers/tty/
++F: drivers/tty/serial/serial_core.c
++F: include/linux/selection.h
++F: include/linux/serial.h
++F: include/linux/serial_core.h
++F: include/linux/sysrq.h
++F: include/linux/tty*.h
++F: include/linux/vt.h
++F: include/linux/vt_*.h
++F: include/uapi/linux/serial.h
++F: include/uapi/linux/serial_core.h
++F: include/uapi/linux/tty.h
++
++TUA9001 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++W: http://palosaari.fi/linux/
++Q: http://patchwork.linuxtv.org/project/linux-media/list/
++T: git git://linuxtv.org/anttip/media_tree.git
++F: drivers/media/tuners/tua9001*
++
++TULIP NETWORK DRIVERS
++L: netdev@vger.kernel.org
++L: linux-parisc@vger.kernel.org
++S: Orphan
++F: drivers/net/ethernet/dec/tulip/
++
++TUN/TAP driver
++M: Maxim Krasnyansky <maxk@qti.qualcomm.com>
++S: Maintained
++W: http://vtun.sourceforge.net/tun
++F: Documentation/networking/tuntap.rst
++F: arch/um/os-Linux/drivers/
++
++TURBOCHANNEL SUBSYSTEM
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++M: Ralf Baechle <ralf@linux-mips.org>
++L: linux-mips@vger.kernel.org
++S: Maintained
++Q: http://patchwork.linux-mips.org/project/linux-mips/list/
++F: drivers/tc/
++F: include/linux/tc.h
++
++TURBOSTAT UTILITY
++M: "Len Brown" <lenb@kernel.org>
++L: linux-pm@vger.kernel.org
++S: Supported
++Q: https://patchwork.kernel.org/project/linux-pm/list/
++B: https://bugzilla.kernel.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git turbostat
++F: tools/power/x86/turbostat/
++
++TW5864 VIDEO4LINUX DRIVER
++M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
++M: Anton Sviridenko <anton@corp.bluecherry.net>
++M: Andrey Utkin <andrey.utkin@corp.bluecherry.net>
++M: Andrey Utkin <andrey_utkin@fastmail.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/pci/tw5864/
++
++TW68 VIDEO4LINUX DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Odd Fixes
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/tw68/
++
++TW686X VIDEO4LINUX DRIVER
++M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/pci/tw686x/
++
++UACCE ACCELERATOR FRAMEWORK
++M: Zhangfei Gao <zhangfei.gao@linaro.org>
++M: Zhou Wang <wangzhou1@hisilicon.com>
++L: linux-accelerators@lists.ozlabs.org
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-driver-uacce
++F: Documentation/misc-devices/uacce.rst
++F: drivers/misc/uacce/
++F: include/linux/uacce.h
++F: include/uapi/misc/uacce/
++
++UBI FILE SYSTEM (UBIFS)
++M: Richard Weinberger <richard@nod.at>
++L: linux-mtd@lists.infradead.org
++S: Supported
++W: http://www.linux-mtd.infradead.org/doc/ubifs.html
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
++F: Documentation/filesystems/ubifs-authentication.rst
++F: Documentation/filesystems/ubifs.rst
++F: fs/ubifs/
++
++UCLINUX (M68KNOMMU AND COLDFIRE)
++M: Greg Ungerer <gerg@linux-m68k.org>
++L: linux-m68k@lists.linux-m68k.org
++L: uclinux-dev@uclinux.org (subscribers-only)
++S: Maintained
++W: http://www.linux-m68k.org/
++W: http://www.uclinux.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git
++F: arch/m68k/*/*_no.*
++F: arch/m68k/68*/
++F: arch/m68k/coldfire/
++F: arch/m68k/include/asm/*_no.*
++
++UDF FILESYSTEM
++M: Jan Kara <jack@suse.com>
++S: Maintained
++F: Documentation/filesystems/udf.rst
++F: fs/udf/
++
++UDRAW TABLET
++M: Bastien Nocera <hadess@hadess.net>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-udraw-ps3.c
++
++UFS FILESYSTEM
++M: Evgeniy Dushistov <dushistov@mail.ru>
++S: Maintained
++F: Documentation/admin-guide/ufs.rst
++F: fs/ufs/
++
++UHID USERSPACE HID IO DRIVER
++M: David Rheinsberg <david.rheinsberg@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/uhid.c
++F: include/uapi/linux/uhid.h
++
++ULPI BUS
++M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/common/ulpi.c
++F: include/linux/ulpi/
++
++UNICODE SUBSYSTEM
++M: Gabriel Krisman Bertazi <krisman@collabora.com>
++L: linux-fsdevel@vger.kernel.org
++S: Supported
++F: fs/unicode/
++
++UNIFDEF
++M: Tony Finch <dot@dotat.at>
++S: Maintained
++W: http://dotat.at/prog/unifdef
++F: scripts/unifdef.c
++
++UNIFORM CDROM DRIVER
++M: Phillip Potter <phil@philpotter.co.uk>
++S: Maintained
++F: Documentation/cdrom/
++F: drivers/cdrom/cdrom.c
++F: include/linux/cdrom.h
++F: include/uapi/linux/cdrom.h
++
++UNISYS S-PAR DRIVERS
++M: David Kershner <david.kershner@unisys.com>
++L: sparmaintainer@unisys.com (Unisys internal)
++S: Supported
++F: drivers/staging/unisys/
++F: drivers/visorbus/
++F: include/linux/visorbus.h
++
++UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
++R: Alim Akhtar <alim.akhtar@samsung.com>
++R: Avri Altman <avri.altman@wdc.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: Documentation/scsi/ufs.rst
++F: drivers/scsi/ufs/
++
++UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS
++M: Pedro Sousa <pedrom.sousa@synopsys.com>
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/ufs/*dwc*
++
++UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER MEDIATEK HOOKS
++M: Stanley Chu <stanley.chu@mediatek.com>
++L: linux-scsi@vger.kernel.org
++L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/scsi/ufs/ufs-mediatek*
++
++UNSORTED BLOCK IMAGES (UBI)
++M: Richard Weinberger <richard@nod.at>
++L: linux-mtd@lists.infradead.org
++S: Supported
++W: http://www.linux-mtd.infradead.org/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
++F: drivers/mtd/ubi/
++F: include/linux/mtd/ubi.h
++F: include/uapi/mtd/ubi-user.h
++
++USB "USBNET" DRIVER FRAMEWORK
++M: Oliver Neukum <oneukum@suse.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.linux-usb.org/usbnet
++F: drivers/net/usb/usbnet.c
++F: include/linux/usb/usbnet.h
++
++USB ACM DRIVER
++M: Oliver Neukum <oneukum@suse.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/usb/acm.rst
++F: drivers/usb/class/cdc-acm.*
++
++USB APPLE MFI FASTCHARGE DRIVER
++M: Bastien Nocera <hadess@hadess.net>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/misc/apple-mfi-fastcharge.c
++
++USB AR5523 WIRELESS DRIVER
++M: Pontus Fuchs <pontus.fuchs@gmail.com>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/ath/ar5523/
++
++USB ATTACHED SCSI
++M: Oliver Neukum <oneukum@suse.com>
++L: linux-usb@vger.kernel.org
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/usb/storage/uas.c
++
++USB CDC ETHERNET DRIVER
++M: Oliver Neukum <oliver@neukum.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/net/usb/cdc_*.c
++F: include/uapi/linux/usb/cdc.h
++
++USB CHAOSKEY DRIVER
++M: Keith Packard <keithp@keithp.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/misc/chaoskey.c
++
++USB CYPRESS C67X00 DRIVER
++L: linux-usb@vger.kernel.org
++S: Orphan
++F: drivers/usb/c67x00/
++
++USB DAVICOM DM9601 DRIVER
++M: Peter Korsgaard <peter@korsgaard.com>
++L: netdev@vger.kernel.org
++S: Maintained
++W: http://www.linux-usb.org/usbnet
++F: drivers/net/usb/dm9601.c
++
++USB EHCI DRIVER
++M: Alan Stern <stern@rowland.harvard.edu>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/usb/ehci.rst
++F: drivers/usb/host/ehci*
++
++USB GADGET/PERIPHERAL SUBSYSTEM
++M: Felipe Balbi <balbi@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++W: http://www.linux-usb.org/gadget
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
++F: drivers/usb/gadget/
++F: include/linux/usb/gadget*
++
++USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
++M: Jiri Kosina <jikos@kernel.org>
++M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
++F: Documentation/hid/hiddev.rst
++F: drivers/hid/usbhid/
++
++USB INTEL XHCI ROLE MUX DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/roles/intel-xhci-usb-role-switch.c
++
++USB IP DRIVER FOR HISILICON KIRIN 960
++M: Yu Chen <chenyu56@huawei.com>
++M: Binghui Wang <wangbinghui@hisilicon.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
++F: drivers/phy/hisilicon/phy-hi3660-usb3.c
++
++USB IP DRIVER FOR HISILICON KIRIN 970
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml
++F: drivers/phy/hisilicon/phy-hi3670-usb3.c
++
++USB ISP116X DRIVER
++M: Olav Kongas <ok@artecdesign.ee>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/host/isp116x*
++F: include/linux/usb/isp116x.h
++
++USB ISP1760 DRIVER
++M: Rui Miguel Silva <rui.silva@linaro.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/isp1760/*
++F: Documentation/devicetree/bindings/usb/nxp,isp1760.yaml
++
++USB LAN78XX ETHERNET DRIVER
++M: Woojung Huh <woojung.huh@microchip.com>
++M: UNGLinuxDriver@microchip.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/microchip,lan78xx.txt
++F: drivers/net/usb/lan78xx.*
++F: include/dt-bindings/net/microchip-lan78xx.h
++
++USB MASS STORAGE DRIVER
++M: Alan Stern <stern@rowland.harvard.edu>
++L: linux-usb@vger.kernel.org
++L: usb-storage@lists.one-eyed-alien.net
++S: Maintained
++F: drivers/usb/storage/
++
++USB MIDI DRIVER
++M: Clemens Ladisch <clemens@ladisch.de>
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
++F: sound/usb/midi.*
++
++USB NETWORKING DRIVERS
++L: linux-usb@vger.kernel.org
++S: Odd Fixes
++F: drivers/net/usb/
++
++USB OHCI DRIVER
++M: Alan Stern <stern@rowland.harvard.edu>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/usb/ohci.rst
++F: drivers/usb/host/ohci*
++
++USB OTG FSM (Finite State Machine)
++M: Peter Chen <peter.chen@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
++F: drivers/usb/common/usb-otg-fsm.c
++
++USB OVER IP DRIVER
++M: Valentina Manea <valentina.manea.m@gmail.com>
++M: Shuah Khan <shuah@kernel.org>
++M: Shuah Khan <skhan@linuxfoundation.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/usb/usbip_protocol.rst
++F: drivers/usb/usbip/
++F: tools/testing/selftests/drivers/usb/usbip/
++F: tools/usb/usbip/
++
++USB PEGASUS DRIVER
++M: Petko Manolov <petkan@nucleusys.com>
++L: linux-usb@vger.kernel.org
++L: netdev@vger.kernel.org
++S: Maintained
++W: https://github.com/petkan/pegasus
++T: git git://github.com/petkan/pegasus.git
++F: drivers/net/usb/pegasus.*
++
++USB PHY LAYER
++M: Felipe Balbi <balbi@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
++F: drivers/usb/phy/
++
++USB PRINTER DRIVER (usblp)
++M: Pete Zaitcev <zaitcev@redhat.com>
++L: linux-usb@vger.kernel.org
++S: Supported
++F: drivers/usb/class/usblp.c
++
++USB RAW GADGET DRIVER
++R: Andrey Konovalov <andreyknvl@gmail.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/usb/raw-gadget.rst
++F: drivers/usb/gadget/legacy/raw_gadget.c
++F: include/uapi/linux/usb/raw_gadget.h
++
++USB QMI WWAN NETWORK DRIVER
++M: Bjørn Mork <bjorn@mork.no>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-net-qmi
++F: drivers/net/usb/qmi_wwan.c
++
++USB RTL8150 DRIVER
++M: Petko Manolov <petkan@nucleusys.com>
++L: linux-usb@vger.kernel.org
++L: netdev@vger.kernel.org
++S: Maintained
++W: https://github.com/petkan/rtl8150
++T: git git://github.com/petkan/rtl8150.git
++F: drivers/net/usb/rtl8150.c
++
++USB SERIAL SUBSYSTEM
++M: Johan Hovold <johan@kernel.org>
++L: linux-usb@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
++F: Documentation/usb/usb-serial.rst
++F: drivers/usb/serial/
++F: include/linux/usb/serial.h
++
++USB SMSC75XX ETHERNET DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/usb/smsc75xx.*
++
++USB SMSC95XX ETHERNET DRIVER
++M: Steve Glendinning <steve.glendinning@shawell.net>
++M: UNGLinuxDriver@microchip.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/usb/smsc95xx.*
++
++USB SUBSYSTEM
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-usb@vger.kernel.org
++S: Supported
++W: http://www.linux-usb.org
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
++F: Documentation/devicetree/bindings/usb/
++F: Documentation/usb/
++F: drivers/usb/
++F: include/linux/usb.h
++F: include/linux/usb/
++
++USB TYPEC BUS FOR ALTERNATE MODES
++M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-bus-typec
++F: Documentation/driver-api/usb/typec_bus.rst
++F: drivers/usb/typec/altmodes/
++F: include/linux/usb/typec_altmode.h
++
++USB TYPEC CLASS
++M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/ABI/testing/sysfs-class-typec
++F: Documentation/driver-api/usb/typec.rst
++F: drivers/usb/typec/
++F: include/linux/usb/typec.h
++
++USB TYPEC INTEL PMC MUX DRIVER
++M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: Documentation/firmware-guide/acpi/intel-pmc-mux.rst
++F: drivers/usb/typec/mux/intel_pmc_mux.c
++
++USB TYPEC PI3USB30532 MUX DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/typec/mux/pi3usb30532.c
++
++USB TYPEC PORT CONTROLLER DRIVERS
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/typec/tcpm/
++
++USB UHCI DRIVER
++M: Alan Stern <stern@rowland.harvard.edu>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/host/uhci*
++
++USB VIDEO CLASS
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-uvc-devel@lists.sourceforge.net (subscribers-only)
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://www.ideasonboard.org/uvc/
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/usb/uvc/
++F: include/uapi/linux/uvcvideo.h
++
++USB WEBCAM GADGET
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-usb@vger.kernel.org
++S: Maintained
++F: drivers/usb/gadget/function/*uvc*
++F: drivers/usb/gadget/legacy/webcam.c
++F: include/uapi/linux/usb/g_uvc.h
++
++USB WIRELESS RNDIS DRIVER (rndis_wlan)
++M: Jussi Kivilinna <jussi.kivilinna@iki.fi>
++L: linux-wireless@vger.kernel.org
++S: Maintained
++F: drivers/net/wireless/rndis_wlan.c
++
++USB XHCI DRIVER
++M: Mathias Nyman <mathias.nyman@intel.com>
++L: linux-usb@vger.kernel.org
++S: Supported
++F: drivers/usb/host/pci-quirks*
++F: drivers/usb/host/xhci*
++
++USB ZD1201 DRIVER
++L: linux-wireless@vger.kernel.org
++S: Orphan
++W: http://linux-lc100020.sourceforge.net
++F: drivers/net/wireless/zydas/zd1201.*
++
++USB ZR364XX DRIVER
++M: Antoine Jacquet <royale@zerezo.com>
++L: linux-usb@vger.kernel.org
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://royale.zerezo.com/zr364xx/
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/admin-guide/media/zr364xx*
++F: drivers/media/usb/zr364xx/
++
++USER-MODE LINUX (UML)
++M: Jeff Dike <jdike@addtoit.com>
++M: Richard Weinberger <richard@nod.at>
++M: Anton Ivanov <anton.ivanov@cambridgegreys.com>
++L: linux-um@lists.infradead.org
++S: Maintained
++W: http://user-mode-linux.sourceforge.net
++Q: https://patchwork.ozlabs.org/project/linux-um/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git
++F: Documentation/virt/uml/
++F: arch/um/
++F: arch/x86/um/
++F: fs/hostfs/
++
++USERSPACE COPYIN/COPYOUT (UIOVEC)
++M: Alexander Viro <viro@zeniv.linux.org.uk>
++S: Maintained
++F: include/linux/uio.h
++F: lib/iov_iter.c
++
++USERSPACE DMA BUFFER DRIVER
++M: Gerd Hoffmann <kraxel@redhat.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/dma-buf/udmabuf.c
++F: include/uapi/linux/udmabuf.h
++
++USERSPACE I/O (UIO)
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
++F: Documentation/driver-api/uio-howto.rst
++F: drivers/uio/
++F: include/linux/uio_driver.h
++
++UTIL-LINUX PACKAGE
++M: Karel Zak <kzak@redhat.com>
++L: util-linux@vger.kernel.org
++S: Maintained
++W: http://en.wikipedia.org/wiki/Util-linux
++T: git git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git
++
++UUID HELPERS
++M: Christoph Hellwig <hch@lst.de>
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.infradead.org/users/hch/uuid.git
++F: include/linux/uuid.h
++F: include/uapi/linux/uuid.h
++F: lib/test_uuid.c
++F: lib/uuid.c
++
++UV SYSFS DRIVER
++M: Justin Ernst <justin.ernst@hpe.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++F: drivers/platform/x86/uv_sysfs.c
++
++UVESAFB DRIVER
++M: Michal Januszewski <spock@gentoo.org>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++W: https://github.com/mjanusz/v86d
++F: Documentation/fb/uvesafb.rst
++F: drivers/video/fbdev/uvesafb.*
++
++Ux500 CLOCK DRIVERS
++M: Ulf Hansson <ulf.hansson@linaro.org>
++L: linux-clk@vger.kernel.org
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/clk/ux500/
++
++VF610 NAND DRIVER
++M: Stefan Agner <stefan@agner.ch>
++L: linux-mtd@lists.infradead.org
++S: Supported
++F: drivers/mtd/nand/raw/vf610_nfc.c
++
++VFAT/FAT/MSDOS FILESYSTEM
++M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
++S: Maintained
++F: Documentation/filesystems/vfat.rst
++F: fs/fat/
++
++VFIO DRIVER
++M: Alex Williamson <alex.williamson@redhat.com>
++R: Cornelia Huck <cohuck@redhat.com>
++L: kvm@vger.kernel.org
++S: Maintained
++T: git git://github.com/awilliam/linux-vfio.git
++F: Documentation/driver-api/vfio.rst
++F: drivers/vfio/
++F: include/linux/vfio.h
++F: include/linux/vfio_pci_core.h
++F: include/uapi/linux/vfio.h
++
++VFIO FSL-MC DRIVER
++M: Diana Craciun <diana.craciun@oss.nxp.com>
++L: kvm@vger.kernel.org
++S: Maintained
++F: drivers/vfio/fsl-mc/
++
++VFIO MEDIATED DEVICE DRIVERS
++M: Kirti Wankhede <kwankhede@nvidia.com>
++L: kvm@vger.kernel.org
++S: Maintained
++F: Documentation/driver-api/vfio-mediated-device.rst
++F: drivers/vfio/mdev/
++F: include/linux/mdev.h
++F: samples/vfio-mdev/
++
++VFIO PLATFORM DRIVER
++M: Eric Auger <eric.auger@redhat.com>
++L: kvm@vger.kernel.org
++S: Maintained
++F: drivers/vfio/platform/
++
++VGA_SWITCHEROO
++R: Lukas Wunner <lukas@wunner.de>
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: Documentation/gpu/vga-switcheroo.rst
++F: drivers/gpu/vga/vga_switcheroo.c
++F: include/linux/vga_switcheroo.h
++
++VIA RHINE NETWORK DRIVER
++S: Maintained
++M: Kevin Brace <kevinbrace@bracecomputerlab.com>
++F: drivers/net/ethernet/via/via-rhine.c
++
++VIA SD/MMC CARD CONTROLLER DRIVER
++M: Bruce Chang <brucechang@via.com.tw>
++M: Harald Welte <HaraldWelte@viatech.com>
++S: Maintained
++F: drivers/mmc/host/via-sdmmc.c
++
++VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
++M: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
++L: linux-fbdev@vger.kernel.org
++S: Maintained
++F: drivers/video/fbdev/via/
++F: include/linux/via-core.h
++F: include/linux/via-gpio.h
++F: include/linux/via_i2c.h
++
++VIA VELOCITY NETWORK DRIVER
++M: Francois Romieu <romieu@fr.zoreil.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/ethernet/via/via-velocity.*
++
++VICODEC VIRTUAL CODEC DRIVER
++M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/test-drivers/vicodec/*
++
++VIDEO I2C POLLING DRIVER
++M: Matt Ranostay <matt.ranostay@konsulko.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/i2c/video-i2c.c
++
++VIDEO MULTIPLEXER DRIVER
++M: Philipp Zabel <p.zabel@pengutronix.de>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/platform/video-mux.c
++
++VIDEOBUF2 FRAMEWORK
++M: Tomasz Figa <tfiga@chromium.org>
++M: Marek Szyprowski <m.szyprowski@samsung.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++F: drivers/media/common/videobuf2/*
++F: include/media/videobuf2-*
++
++VIMC VIRTUAL MEDIA CONTROLLER DRIVER
++M: Helen Koike <helen.koike@collabora.com>
++R: Shuah Khan <skhan@linuxfoundation.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/test-drivers/vimc/*
++
++VIRT LIB
++M: Alex Williamson <alex.williamson@redhat.com>
++M: Paolo Bonzini <pbonzini@redhat.com>
++L: kvm@vger.kernel.org
++S: Supported
++F: virt/lib/
++
++VIRTIO AND VHOST VSOCK DRIVER
++M: Stefan Hajnoczi <stefanha@redhat.com>
++M: Stefano Garzarella <sgarzare@redhat.com>
++L: kvm@vger.kernel.org
++L: virtualization@lists.linux-foundation.org
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/vhost/vsock.c
++F: include/linux/virtio_vsock.h
++F: include/uapi/linux/virtio_vsock.h
++F: net/vmw_vsock/virtio_transport.c
++F: net/vmw_vsock/virtio_transport_common.c
++
++VIRTIO BLOCK AND SCSI DRIVERS
++M: "Michael S. Tsirkin" <mst@redhat.com>
++M: Jason Wang <jasowang@redhat.com>
++R: Paolo Bonzini <pbonzini@redhat.com>
++R: Stefan Hajnoczi <stefanha@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/block/virtio_blk.c
++F: drivers/scsi/virtio_scsi.c
++F: drivers/vhost/scsi.c
++F: include/uapi/linux/virtio_blk.h
++F: include/uapi/linux/virtio_scsi.h
++
++VIRTIO CONSOLE DRIVER
++M: Amit Shah <amit@kernel.org>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/char/virtio_console.c
++F: include/linux/virtio_console.h
++F: include/uapi/linux/virtio_console.h
++
++VIRTIO CORE AND NET DRIVERS
++M: "Michael S. Tsirkin" <mst@redhat.com>
++M: Jason Wang <jasowang@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: Documentation/devicetree/bindings/virtio/
++F: drivers/block/virtio_blk.c
++F: drivers/crypto/virtio/
++F: drivers/net/virtio_net.c
++F: drivers/vdpa/
++F: drivers/virtio/
++F: include/linux/vdpa.h
++F: include/linux/virtio*.h
++F: include/uapi/linux/virtio_*.h
++F: tools/virtio/
++
++VIRTIO BALLOON
++M: "Michael S. Tsirkin" <mst@redhat.com>
++M: David Hildenbrand <david@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/virtio/virtio_balloon.c
++F: include/uapi/linux/virtio_balloon.h
++F: include/linux/balloon_compaction.h
++F: mm/balloon_compaction.c
++
++VIRTIO CRYPTO DRIVER
++M: Gonglei <arei.gonglei@huawei.com>
++L: virtualization@lists.linux-foundation.org
++L: linux-crypto@vger.kernel.org
++S: Maintained
++F: drivers/crypto/virtio/
++F: include/uapi/linux/virtio_crypto.h
++
++VIRTIO DRIVERS FOR S390
++M: Cornelia Huck <cohuck@redhat.com>
++M: Halil Pasic <pasic@linux.ibm.com>
++L: linux-s390@vger.kernel.org
++L: virtualization@lists.linux-foundation.org
++L: kvm@vger.kernel.org
++S: Supported
++F: arch/s390/include/uapi/asm/virtio-ccw.h
++F: drivers/s390/virtio/
++
++VIRTIO FILE SYSTEM
++M: Vivek Goyal <vgoyal@redhat.com>
++M: Stefan Hajnoczi <stefanha@redhat.com>
++M: Miklos Szeredi <miklos@szeredi.hu>
++L: virtualization@lists.linux-foundation.org
++L: linux-fsdevel@vger.kernel.org
++S: Supported
++W: https://virtio-fs.gitlab.io/
++F: Documentation/filesystems/virtiofs.rst
++F: fs/fuse/virtio_fs.c
++F: include/uapi/linux/virtio_fs.h
++
++VIRTIO GPIO DRIVER
++M: Enrico Weigelt, metux IT consult <info@metux.net>
++M: Viresh Kumar <vireshk@kernel.org>
++L: linux-gpio@vger.kernel.org
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/gpio/gpio-virtio.c
++F: include/uapi/linux/virtio_gpio.h
++
++VIRTIO GPU DRIVER
++M: David Airlie <airlied@linux.ie>
++M: Gerd Hoffmann <kraxel@redhat.com>
++L: dri-devel@lists.freedesktop.org
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++T: git git://anongit.freedesktop.org/drm/drm-misc
++F: drivers/gpu/drm/virtio/
++F: include/uapi/linux/virtio_gpu.h
++
++VIRTIO HOST (VHOST)
++M: "Michael S. Tsirkin" <mst@redhat.com>
++M: Jason Wang <jasowang@redhat.com>
++L: kvm@vger.kernel.org
++L: virtualization@lists.linux-foundation.org
++L: netdev@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git
++F: drivers/vhost/
++F: include/linux/vhost_iotlb.h
++F: include/uapi/linux/vhost.h
++
++VIRTIO INPUT DRIVER
++M: Gerd Hoffmann <kraxel@redhat.com>
++S: Maintained
++F: drivers/virtio/virtio_input.c
++F: include/uapi/linux/virtio_input.h
++
++VIRTIO IOMMU DRIVER
++M: Jean-Philippe Brucker <jean-philippe@linaro.org>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/iommu/virtio-iommu.c
++F: include/uapi/linux/virtio_iommu.h
++
++VIRTIO MEM DRIVER
++M: David Hildenbrand <david@redhat.com>
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++W: https://virtio-mem.gitlab.io/
++F: drivers/virtio/virtio_mem.c
++F: include/uapi/linux/virtio_mem.h
++
++VIRTIO SOUND DRIVER
++M: Anton Yakovlev <anton.yakovlev@opensynergy.com>
++M: "Michael S. Tsirkin" <mst@redhat.com>
++L: virtualization@lists.linux-foundation.org
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Maintained
++F: include/uapi/linux/virtio_snd.h
++F: sound/virtio/*
++
++VIRTIO I2C DRIVER
++M: Jie Deng <jie.deng@intel.com>
++M: Viresh Kumar <viresh.kumar@linaro.org>
++L: linux-i2c@vger.kernel.org
++L: virtualization@lists.linux-foundation.org
++S: Maintained
++F: drivers/i2c/busses/i2c-virtio.c
++F: include/uapi/linux/virtio_i2c.h
++
++VIRTUAL BOX GUEST DEVICE DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++M: Arnd Bergmann <arnd@arndb.de>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++S: Maintained
++F: drivers/virt/vboxguest/
++F: include/linux/vbox_utils.h
++F: include/uapi/linux/vbox*.h
++
++VIRTUAL BOX SHARED FOLDER VFS DRIVER
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++F: fs/vboxsf/*
++
++VIRTUAL SERIO DEVICE DRIVER
++M: Stephen Chandler Paul <thatslyude@gmail.com>
++S: Maintained
++F: drivers/input/serio/userio.c
++F: include/uapi/linux/userio.h
++
++VIVID VIRTUAL VIDEO DRIVER
++M: Hans Verkuil <hverkuil@xs4all.nl>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/test-drivers/vivid/*
++
++VIDTV VIRTUAL DIGITAL TV DRIVER
++M: Daniel W. S. Almeida <dwlsalmeida@gmail.com>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/test-drivers/vidtv/*
++
++VLYNQ BUS
++M: Florian Fainelli <f.fainelli@gmail.com>
++L: openwrt-devel@lists.openwrt.org (subscribers-only)
++S: Maintained
++F: drivers/vlynq/vlynq.c
++F: include/linux/vlynq.h
++
++VME SUBSYSTEM
++M: Martyn Welch <martyn@welchs.me.uk>
++M: Manohar Vanga <manohar.vanga@gmail.com>
++M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
++F: Documentation/driver-api/vme.rst
++F: drivers/staging/vme/
++F: drivers/vme/
++F: include/linux/vme*
++
++VM SOCKETS (AF_VSOCK)
++M: Stefano Garzarella <sgarzare@redhat.com>
++L: virtualization@lists.linux-foundation.org
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/vsockmon.c
++F: include/net/af_vsock.h
++F: include/uapi/linux/vm_sockets.h
++F: include/uapi/linux/vm_sockets_diag.h
++F: include/uapi/linux/vsockmon.h
++F: net/vmw_vsock/
++F: tools/testing/vsock/
++
++VMWARE BALLOON DRIVER
++M: Nadav Amit <namit@vmware.com>
++M: "VMware, Inc." <pv-drivers@vmware.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: drivers/misc/vmw_balloon.c
++
++VMWARE HYPERVISOR INTERFACE
++M: Deep Shah <sdeep@vmware.com>
++M: "VMware, Inc." <pv-drivers@vmware.com>
++L: virtualization@lists.linux-foundation.org
++S: Supported
++F: arch/x86/include/asm/vmware.h
++F: arch/x86/kernel/cpu/vmware.c
++
++VMWARE PVRDMA DRIVER
++M: Adit Ranadive <aditr@vmware.com>
++M: VMware PV-Drivers <pv-drivers@vmware.com>
++L: linux-rdma@vger.kernel.org
++S: Maintained
++F: drivers/infiniband/hw/vmw_pvrdma/
++
++VMware PVSCSI driver
++M: Vishal Bhakta <vbhakta@vmware.com>
++M: VMware PV-Drivers <pv-drivers@vmware.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/vmw_pvscsi.c
++F: drivers/scsi/vmw_pvscsi.h
++
++VMWARE VIRTUAL PTP CLOCK DRIVER
++M: Vivek Thampi <vithampi@vmware.com>
++M: "VMware, Inc." <pv-drivers@vmware.com>
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/ptp/ptp_vmw.c
++
++VMWARE VMCI DRIVER
++M: Jorgen Hansen <jhansen@vmware.com>
++M: Vishnu Dasa <vdasa@vmware.com>
++L: linux-kernel@vger.kernel.org
++L: pv-drivers@vmware.com (private)
++S: Maintained
++F: drivers/misc/vmw_vmci/
++
++VMWARE VMMOUSE SUBDRIVER
++M: "VMware Graphics" <linux-graphics-maintainer@vmware.com>
++M: "VMware, Inc." <pv-drivers@vmware.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/mouse/vmmouse.c
++F: drivers/input/mouse/vmmouse.h
++
++VMWARE VMXNET3 ETHERNET DRIVER
++M: Ronak Doshi <doshir@vmware.com>
++M: pv-drivers@vmware.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/vmxnet3/
++
++VOCORE VOCORE2 BOARD
++M: Harvey Hunt <harveyhuntnexus@gmail.com>
++L: linux-mips@vger.kernel.org
++S: Maintained
++F: arch/mips/boot/dts/ralink/vocore2.dts
++
++VOLTAGE AND CURRENT REGULATOR FRAMEWORK
++M: Liam Girdwood <lgirdwood@gmail.com>
++M: Mark Brown <broonie@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Supported
++W: http://www.slimlogic.co.uk/?p=48
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
++F: Documentation/devicetree/bindings/regulator/
++F: Documentation/power/regulator/
++F: drivers/regulator/
++F: include/dt-bindings/regulator/
++F: include/linux/regulator/
++K: regulator_get_optional
++
++VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
++R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
++F: drivers/regulator/irq_helpers.c
++
++VRF
++M: David Ahern <dsahern@kernel.org>
++L: netdev@vger.kernel.org
++S: Maintained
++F: Documentation/networking/vrf.rst
++F: drivers/net/vrf.c
++
++VSPRINTF
++M: Petr Mladek <pmladek@suse.com>
++M: Steven Rostedt <rostedt@goodmis.org>
++M: Sergey Senozhatsky <senozhatsky@chromium.org>
++R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
++R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
++F: Documentation/core-api/printk-formats.rst
++F: lib/test_printf.c
++F: lib/test_scanf.c
++F: lib/vsprintf.c
++
++VT1211 HARDWARE MONITOR DRIVER
++M: Juerg Haefliger <juergh@gmail.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/vt1211.rst
++F: drivers/hwmon/vt1211.c
++
++VT8231 HARDWARE MONITOR DRIVER
++M: Roger Lucas <vt8231@hiddenengine.co.uk>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/vt8231.c
++
++VUB300 USB to SDIO/SD/MMC bridge chip
++L: linux-mmc@vger.kernel.org
++S: Orphan
++F: drivers/mmc/host/vub300.c
++
++W1 DALLAS'S 1-WIRE BUS
++M: Evgeniy Polyakov <zbr@ioremap.net>
++S: Maintained
++F: Documentation/devicetree/bindings/w1/
++F: Documentation/w1/
++F: drivers/w1/
++F: include/linux/w1.h
++
++W83791D HARDWARE MONITORING DRIVER
++M: Marc Hulsman <m.hulsman@tudelft.nl>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/w83791d.rst
++F: drivers/hwmon/w83791d.c
++
++W83793 HARDWARE MONITORING DRIVER
++M: Rudolf Marek <r.marek@assembler.cz>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: Documentation/hwmon/w83793.rst
++F: drivers/hwmon/w83793.c
++
++W83795 HARDWARE MONITORING DRIVER
++M: Jean Delvare <jdelvare@suse.com>
++L: linux-hwmon@vger.kernel.org
++S: Maintained
++F: drivers/hwmon/w83795.c
++
++W83L51xD SD/MMC CARD INTERFACE DRIVER
++M: Pierre Ossman <pierre@ossman.eu>
++S: Maintained
++F: drivers/mmc/host/wbsd.*
++
++WACOM PROTOCOL 4 SERIAL TABLETS
++M: Julian Squires <julian@cipht.net>
++M: Hans de Goede <hdegoede@redhat.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/input/tablet/wacom_serial4.c
++
++WATCHDOG DEVICE DRIVERS
++M: Wim Van Sebroeck <wim@linux-watchdog.org>
++M: Guenter Roeck <linux@roeck-us.net>
++L: linux-watchdog@vger.kernel.org
++S: Maintained
++W: http://www.linux-watchdog.org/
++T: git git://www.linux-watchdog.org/linux-watchdog.git
++F: Documentation/devicetree/bindings/watchdog/
++F: Documentation/watchdog/
++F: drivers/watchdog/
++F: include/linux/watchdog.h
++F: include/uapi/linux/watchdog.h
++
++WHISKEYCOVE PMIC GPIO DRIVER
++M: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-wcove.c
++
++WHWAVE RTC DRIVER
++M: Dianlong Li <long17.cool@163.com>
++L: linux-rtc@vger.kernel.org
++S: Maintained
++F: drivers/rtc/rtc-sd3078.c
++
++WIIMOTE HID DRIVER
++M: David Rheinsberg <david.rheinsberg@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-wiimote*
++
++WILOCITY WIL6210 WIRELESS DRIVER
++M: Maya Erez <merez@codeaurora.org>
++L: linux-wireless@vger.kernel.org
++L: wil6210@qti.qualcomm.com
++S: Supported
++W: https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
++F: drivers/net/wireless/ath/wil6210/
++
++WINBOND CIR DRIVER
++M: David Härdeman <david@hardeman.nu>
++S: Maintained
++F: drivers/media/rc/winbond-cir.c
++
++WINSYSTEMS EBC-C384 WATCHDOG DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-watchdog@vger.kernel.org
++S: Maintained
++F: drivers/watchdog/ebc-c384_wdt.c
++
++WINSYSTEMS WS16C48 GPIO DRIVER
++M: William Breathitt Gray <vilhelm.gray@gmail.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: drivers/gpio/gpio-ws16c48.c
++
++WIREGUARD SECURE NETWORK TUNNEL
++M: Jason A. Donenfeld <Jason@zx2c4.com>
++L: wireguard@lists.zx2c4.com
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/wireguard/
++F: tools/testing/selftests/wireguard/
++
++WISTRON LAPTOP BUTTON DRIVER
++M: Miloslav Trmac <mitr@volny.cz>
++S: Maintained
++F: drivers/input/misc/wistron_btns.c
++
++WL3501 WIRELESS PCMCIA CARD DRIVER
++L: linux-wireless@vger.kernel.org
++S: Odd fixes
++F: drivers/net/wireless/wl3501*
++
++WOLFSON MICROELECTRONICS DRIVERS
++L: patches@opensource.cirrus.com
++S: Supported
++W: https://github.com/CirrusLogic/linux-drivers/wiki
++T: git https://github.com/CirrusLogic/linux-drivers.git
++F: Documentation/devicetree/bindings/extcon/wlf,arizona.yaml
++F: Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
++F: Documentation/devicetree/bindings/mfd/wm831x.txt
++F: Documentation/devicetree/bindings/regulator/wlf,arizona.yaml
++F: Documentation/devicetree/bindings/sound/wlf,*.yaml
++F: Documentation/devicetree/bindings/sound/wm*
++F: Documentation/hwmon/wm83??.rst
++F: arch/arm/mach-s3c/mach-crag6410*
++F: drivers/clk/clk-wm83*.c
++F: drivers/gpio/gpio-*wm*.c
++F: drivers/gpio/gpio-arizona.c
++F: drivers/hwmon/wm83??-hwmon.c
++F: drivers/input/misc/wm831x-on.c
++F: drivers/input/touchscreen/wm831x-ts.c
++F: drivers/input/touchscreen/wm97*.c
++F: drivers/leds/leds-wm83*.c
++F: drivers/mfd/arizona*
++F: drivers/mfd/cs47l24*
++F: drivers/mfd/wm*.c
++F: drivers/power/supply/wm83*.c
++F: drivers/regulator/arizona*
++F: drivers/regulator/wm8*.c
++F: drivers/rtc/rtc-wm83*.c
++F: drivers/video/backlight/wm83*_bl.c
++F: drivers/watchdog/wm83*_wdt.c
++F: include/linux/mfd/arizona/
++F: include/linux/mfd/wm831x/
++F: include/linux/mfd/wm8350/
++F: include/linux/mfd/wm8400*
++F: include/linux/regulator/arizona*
++F: include/linux/wm97xx.h
++F: include/sound/wm????.h
++F: sound/soc/codecs/arizona*
++F: sound/soc/codecs/cs47l24*
++F: sound/soc/codecs/wm*
++
++WORKQUEUE
++M: Tejun Heo <tj@kernel.org>
++R: Lai Jiangshan <jiangshanlai@gmail.com>
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git
++F: Documentation/core-api/workqueue.rst
++F: include/linux/workqueue.h
++F: kernel/workqueue.c
++
++WWAN DRIVERS
++M: Loic Poulain <loic.poulain@linaro.org>
++M: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++R: Johannes Berg <johannes@sipsolutions.net>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/wwan/
++F: include/linux/wwan.h
++F: include/uapi/linux/wwan.h
++
++X-POWERS AXP288 PMIC DRIVERS
++M: Hans de Goede <hdegoede@redhat.com>
++S: Maintained
++F: drivers/acpi/pmic/intel_pmic_xpower.c
++N: axp288
++
++X-POWERS MULTIFUNCTION PMIC DEVICE DRIVERS
++M: Chen-Yu Tsai <wens@csie.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++N: axp[128]
++
++X.25 STACK
++M: Martin Schiller <ms@dev.tdt.de>
++L: linux-x25@vger.kernel.org
++S: Maintained
++F: Documentation/networking/lapb-module.rst
++F: Documentation/networking/x25*
++F: drivers/net/wan/hdlc_x25.c
++F: drivers/net/wan/lapbether.c
++F: include/*/lapb.h
++F: include/net/x25*
++F: include/uapi/linux/x25.h
++F: net/lapb/
++F: net/x25/
++
++X86 ARCHITECTURE (32-BIT AND 64-BIT)
++M: Thomas Gleixner <tglx@linutronix.de>
++M: Ingo Molnar <mingo@redhat.com>
++M: Borislav Petkov <bp@alien8.de>
++M: Dave Hansen <dave.hansen@linux.intel.com>
++M: x86@kernel.org
++R: "H. Peter Anvin" <hpa@zytor.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
++F: Documentation/devicetree/bindings/x86/
++F: Documentation/x86/
++F: arch/x86/
++
++X86 ENTRY CODE
++M: Andy Lutomirski <luto@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/asm
++F: arch/x86/entry/
++
++X86 MCE INFRASTRUCTURE
++M: Tony Luck <tony.luck@intel.com>
++M: Borislav Petkov <bp@alien8.de>
++L: linux-edac@vger.kernel.org
++S: Maintained
++F: arch/x86/kernel/cpu/mce/*
++
++X86 MICROCODE UPDATE SUPPORT
++M: Borislav Petkov <bp@alien8.de>
++S: Maintained
++F: arch/x86/kernel/cpu/microcode/*
++
++X86 MM
++M: Dave Hansen <dave.hansen@linux.intel.com>
++M: Andy Lutomirski <luto@kernel.org>
++M: Peter Zijlstra <peterz@infradead.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm
++F: arch/x86/mm/
++
++X86 PLATFORM DRIVERS
++M: Hans de Goede <hdegoede@redhat.com>
++M: Mark Gross <mgross@linux.intel.com>
++L: platform-driver-x86@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
++F: drivers/platform/olpc/
++F: drivers/platform/x86/
++
++X86 PLATFORM DRIVERS - ARCH
++R: Darren Hart <dvhart@infradead.org>
++R: Andy Shevchenko <andy@infradead.org>
++L: platform-driver-x86@vger.kernel.org
++L: x86@kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
++F: arch/x86/platform
++
++X86 PLATFORM UV HPE SUPERDOME FLEX
++M: Steve Wahl <steve.wahl@hpe.com>
++R: Mike Travis <mike.travis@hpe.com>
++R: Dimitri Sivanich <dimitri.sivanich@hpe.com>
++R: Russ Anderson <russ.anderson@hpe.com>
++S: Supported
++F: arch/x86/include/asm/uv/
++F: arch/x86/kernel/apic/x2apic_uv_x.c
++F: arch/x86/platform/uv/
++
++X86 VDSO
++M: Andy Lutomirski <luto@kernel.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
++F: arch/x86/entry/vdso/
++
++XARRAY
++M: Matthew Wilcox <willy@infradead.org>
++L: linux-fsdevel@vger.kernel.org
++S: Supported
++F: Documentation/core-api/xarray.rst
++F: include/linux/idr.h
++F: include/linux/xarray.h
++F: lib/idr.c
++F: lib/xarray.c
++F: tools/testing/radix-tree
++
++XBOX DVD IR REMOTE
++M: Benjamin Valentin <benpicco@googlemail.com>
++S: Maintained
++F: drivers/media/rc/keymaps/rc-xbox-dvd.c
++F: drivers/media/rc/xbox_remote.c
++
++XC2028/3028 TUNER DRIVER
++M: Mauro Carvalho Chehab <mchehab@kernel.org>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org
++T: git git://linuxtv.org/media_tree.git
++F: drivers/media/tuners/tuner-xc2028.*
++
++XDP (eXpress Data Path)
++M: Alexei Starovoitov <ast@kernel.org>
++M: Daniel Borkmann <daniel@iogearbox.net>
++M: David S. Miller <davem@davemloft.net>
++M: Jakub Kicinski <kuba@kernel.org>
++M: Jesper Dangaard Brouer <hawk@kernel.org>
++M: John Fastabend <john.fastabend@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Supported
++F: include/net/xdp.h
++F: include/net/xdp_priv.h
++F: include/trace/events/xdp.h
++F: kernel/bpf/cpumap.c
++F: kernel/bpf/devmap.c
++F: net/core/xdp.c
++F: samples/bpf/xdp*
++F: tools/testing/selftests/bpf/*xdp*
++F: tools/testing/selftests/bpf/*/*xdp*
++F: drivers/net/ethernet/*/*/*/*/*xdp*
++F: drivers/net/ethernet/*/*/*xdp*
++K: (?:\b|_)xdp(?:\b|_)
++
++XDP SOCKETS (AF_XDP)
++M: Björn Töpel <bjorn@kernel.org>
++M: Magnus Karlsson <magnus.karlsson@intel.com>
++R: Jonathan Lemon <jonathan.lemon@gmail.com>
++L: netdev@vger.kernel.org
++L: bpf@vger.kernel.org
++S: Maintained
++F: Documentation/networking/af_xdp.rst
++F: include/net/xdp_sock*
++F: include/net/xsk_buff_pool.h
++F: include/uapi/linux/if_xdp.h
++F: include/uapi/linux/xdp_diag.h
++F: include/net/netns/xdp.h
++F: net/xdp/
++F: samples/bpf/xdpsock*
++F: tools/lib/bpf/xsk*
++
++XEN BLOCK SUBSYSTEM
++M: Roger Pau Monné <roger.pau@citrix.com>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Supported
++F: drivers/block/xen*
++F: drivers/block/xen-blkback/*
++
++XEN HYPERVISOR ARM
++M: Stefano Stabellini <sstabellini@kernel.org>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm/include/asm/xen/
++F: arch/arm/xen/
++
++XEN HYPERVISOR ARM64
++M: Stefano Stabellini <sstabellini@kernel.org>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Maintained
++F: arch/arm64/include/asm/xen/
++F: arch/arm64/xen/
++
++XEN HYPERVISOR INTERFACE
++M: Boris Ostrovsky <boris.ostrovsky@oracle.com>
++M: Juergen Gross <jgross@suse.com>
++R: Stefano Stabellini <sstabellini@kernel.org>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
++F: Documentation/ABI/stable/sysfs-hypervisor-xen
++F: Documentation/ABI/testing/sysfs-hypervisor-xen
++F: arch/x86/include/asm/pvclock-abi.h
++F: arch/x86/include/asm/xen/
++F: arch/x86/platform/pvh/
++F: arch/x86/xen/
++F: drivers/*/xen-*front.c
++F: drivers/xen/
++F: include/uapi/xen/
++F: include/xen/
++
++XEN NETWORK BACKEND DRIVER
++M: Wei Liu <wei.liu@kernel.org>
++M: Paul Durrant <paul@xen.org>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++L: netdev@vger.kernel.org
++S: Supported
++F: drivers/net/xen-netback/*
++
++XEN PCI SUBSYSTEM
++M: Juergen Gross <jgross@suse.com>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++S: Supported
++F: arch/x86/pci/*xen*
++F: drivers/pci/*xen*
++
++XEN PVSCSI DRIVERS
++M: Juergen Gross <jgross@suse.com>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++L: linux-scsi@vger.kernel.org
++S: Supported
++F: drivers/scsi/xen-scsifront.c
++F: drivers/xen/xen-scsiback.c
++F: include/xen/interface/io/vscsiif.h
++
++XEN SOUND FRONTEND DRIVER
++M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++L: alsa-devel@alsa-project.org (moderated for non-subscribers)
++S: Supported
++F: sound/xen/*
++
++XEN SWIOTLB SUBSYSTEM
++M: Juergen Gross <jgross@suse.com>
++M: Stefano Stabellini <sstabellini@kernel.org>
++L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
++L: iommu@lists.linux-foundation.org
++S: Supported
++F: arch/x86/xen/*swiotlb*
++F: drivers/xen/*swiotlb*
++
++XFS FILESYSTEM
++C: irc://irc.oftc.net/xfs
++M: Darrick J. Wong <djwong@kernel.org>
++M: linux-xfs@vger.kernel.org
++L: linux-xfs@vger.kernel.org
++S: Supported
++W: http://xfs.org/
++T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
++F: Documentation/ABI/testing/sysfs-fs-xfs
++F: Documentation/admin-guide/xfs.rst
++F: Documentation/filesystems/xfs-delayed-logging-design.rst
++F: Documentation/filesystems/xfs-self-describing-metadata.rst
++F: fs/xfs/
++F: include/uapi/linux/dqblk_xfs.h
++F: include/uapi/linux/fsmap.h
++
++XILINX AXI ETHERNET DRIVER
++M: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
++S: Maintained
++F: drivers/net/ethernet/xilinx/xilinx_axienet*
++
++XILINX CAN DRIVER
++M: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>
++R: Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
++L: linux-can@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/net/can/xilinx_can.txt
++F: drivers/net/can/xilinx_can.c
++
++XILINX GPIO DRIVER
++M: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
++R: Srinivas Neeli <srinivas.neeli@xilinx.com>
++R: Michal Simek <michal.simek@xilinx.com>
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
++F: Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
++F: drivers/gpio/gpio-xilinx.c
++F: drivers/gpio/gpio-zynq.c
++
++XILINX SD-FEC IP CORES
++M: Derek Kiernan <derek.kiernan@xilinx.com>
++M: Dragan Cvetic <dragan.cvetic@xilinx.com>
++S: Maintained
++F: Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt
++F: Documentation/misc-devices/xilinx_sdfec.rst
++F: drivers/misc/Kconfig
++F: drivers/misc/Makefile
++F: drivers/misc/xilinx_sdfec.c
++F: include/uapi/misc/xilinx_sdfec.h
++
++XILINX UARTLITE SERIAL DRIVER
++M: Peter Korsgaard <jacmet@sunsite.dk>
++L: linux-serial@vger.kernel.org
++S: Maintained
++F: drivers/tty/serial/uartlite.c
++
++XILINX VIDEO IP CORES
++M: Hyun Kwon <hyun.kwon@xilinx.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-media@vger.kernel.org
++S: Supported
++T: git git://linuxtv.org/media_tree.git
++F: Documentation/devicetree/bindings/media/xilinx/
++F: drivers/media/platform/xilinx/
++F: include/uapi/linux/xilinx-v4l2-controls.h
++
++XILINX ZYNQMP DPDMA DRIVER
++M: Hyun Kwon <hyun.kwon@xilinx.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: dmaengine@vger.kernel.org
++S: Supported
++F: Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
++F: drivers/dma/xilinx/xilinx_dpdma.c
++F: include/dt-bindings/dma/xlnx-zynqmp-dpdma.h
++
++XILINX ZYNQMP PSGTR PHY DRIVER
++M: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
++M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++T: git https://github.com/Xilinx/linux-xlnx.git
++F: Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
++F: drivers/phy/xilinx/phy-zynqmp.c
++
++XILLYBUS DRIVER
++M: Eli Billauer <eli.billauer@gmail.com>
++L: linux-kernel@vger.kernel.org
++S: Supported
++F: drivers/char/xillybus/
++
++XLP9XX I2C DRIVER
++M: George Cherian <gcherian@marvell.com>
++L: linux-i2c@vger.kernel.org
++S: Supported
++W: http://www.marvell.com
++F: Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt
++F: drivers/i2c/busses/i2c-xlp9xx.c
++
++XRA1403 GPIO EXPANDER
++M: Nandor Han <nandor.han@ge.com>
++M: Semi Malinen <semi.malinen@ge.com>
++L: linux-gpio@vger.kernel.org
++S: Maintained
++F: Documentation/devicetree/bindings/gpio/gpio-xra1403.txt
++F: drivers/gpio/gpio-xra1403.c
++
++XTENSA XTFPGA PLATFORM SUPPORT
++M: Max Filippov <jcmvbkbc@gmail.com>
++L: linux-xtensa@linux-xtensa.org
++S: Maintained
++F: drivers/spi/spi-xtensa-xtfpga.c
++F: sound/soc/xtensa/xtfpga-i2s.c
++
++YAM DRIVER FOR AX.25
++M: Jean-Paul Roubelat <jpr@f6fbb.org>
++L: linux-hams@vger.kernel.org
++S: Maintained
++F: drivers/net/hamradio/yam*
++F: include/linux/yam.h
++
++YAMA SECURITY MODULE
++M: Kees Cook <keescook@chromium.org>
++S: Supported
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
++F: Documentation/admin-guide/LSM/Yama.rst
++F: security/yama/
++
++YEALINK PHONE DRIVER
++M: Henk Vergonet <Henk.Vergonet@gmail.com>
++L: usbb2k-api-dev@nongnu.org
++S: Maintained
++F: Documentation/input/devices/yealink.rst
++F: drivers/input/misc/yealink.*
++
++Z8530 DRIVER FOR AX.25
++M: Joerg Reuter <jreuter@yaina.de>
++L: linux-hams@vger.kernel.org
++S: Maintained
++W: http://yaina.de/jreuter/
++W: http://www.qsl.net/dl1bke/
++F: Documentation/networking/device_drivers/hamradio/z8530drv.rst
++F: drivers/net/hamradio/*scc.c
++F: drivers/net/hamradio/z8530.h
++
++ZBUD COMPRESSED PAGE ALLOCATOR
++M: Seth Jennings <sjenning@redhat.com>
++M: Dan Streetman <ddstreet@ieee.org>
++L: linux-mm@kvack.org
++S: Maintained
++F: mm/zbud.c
++
++ZD1211RW WIRELESS DRIVER
++M: Ulrich Kunitz <kune@deine-taler.de>
++L: linux-wireless@vger.kernel.org
++L: zd1211-devs@lists.sourceforge.net (subscribers-only)
++S: Maintained
++W: http://zd1211.ath.cx/wiki/DriverRewrite
++F: drivers/net/wireless/zydas/zd1211rw/
++
++ZD1301 MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org/
++W: http://palosaari.fi/linux/
++Q: https://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/usb/dvb-usb-v2/zd1301*
++
++ZD1301_DEMOD MEDIA DRIVER
++M: Antti Palosaari <crope@iki.fi>
++L: linux-media@vger.kernel.org
++S: Maintained
++W: https://linuxtv.org/
++W: http://palosaari.fi/linux/
++Q: https://patchwork.linuxtv.org/project/linux-media/list/
++F: drivers/media/dvb-frontends/zd1301_demod*
++
++ZHAOXIN PROCESSOR SUPPORT
++M: Tony W Wang-oc <TonyWWang-oc@zhaoxin.com>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: arch/x86/kernel/cpu/zhaoxin.c
++
++ZONEFS FILESYSTEM
++M: Damien Le Moal <damien.lemoal@wdc.com>
++M: Naohiro Aota <naohiro.aota@wdc.com>
++R: Johannes Thumshirn <jth@kernel.org>
++L: linux-fsdevel@vger.kernel.org
++S: Maintained
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git
++F: Documentation/filesystems/zonefs.rst
++F: fs/zonefs/
++
++ZPOOL COMPRESSED PAGE STORAGE API
++M: Dan Streetman <ddstreet@ieee.org>
++L: linux-mm@kvack.org
++S: Maintained
++F: include/linux/zpool.h
++F: mm/zpool.c
++
++ZR36067 VIDEO FOR LINUX DRIVER
++M: Corentin Labbe <clabbe@baylibre.com>
++L: mjpeg-users@lists.sourceforge.net
++L: linux-media@vger.kernel.org
++S: Maintained
++W: http://mjpeg.sourceforge.net/driver-zoran/
++Q: https://patchwork.linuxtv.org/project/linux-media/list/
++F: Documentation/driver-api/media/drivers/zoran.rst
++F: drivers/staging/media/zoran/
++
++ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
++M: Minchan Kim <minchan@kernel.org>
++M: Nitin Gupta <ngupta@vflare.org>
++R: Sergey Senozhatsky <senozhatsky@chromium.org>
++L: linux-kernel@vger.kernel.org
++S: Maintained
++F: Documentation/admin-guide/blockdev/zram.rst
++F: drivers/block/zram/
++
++ZS DECSTATION Z85C30 SERIAL DRIVER
++M: "Maciej W. Rozycki" <macro@orcam.me.uk>
++S: Maintained
++F: drivers/tty/serial/zs.*
++
++ZSMALLOC COMPRESSED SLAB MEMORY ALLOCATOR
++M: Minchan Kim <minchan@kernel.org>
++M: Nitin Gupta <ngupta@vflare.org>
++R: Sergey Senozhatsky <senozhatsky@chromium.org>
++L: linux-mm@kvack.org
++S: Maintained
++F: Documentation/vm/zsmalloc.rst
++F: include/linux/zsmalloc.h
++F: mm/zsmalloc.c
++
++ZSWAP COMPRESSED SWAP CACHING
++M: Seth Jennings <sjenning@redhat.com>
++M: Dan Streetman <ddstreet@ieee.org>
++M: Vitaly Wool <vitaly.wool@konsulko.com>
++L: linux-mm@kvack.org
++S: Maintained
++F: mm/zswap.c
++
++THE REST
++M: Linus Torvalds <torvalds@linux-foundation.org>
++L: linux-kernel@vger.kernel.org
++S: Buried alive in reporters
++Q: http://patchwork.kernel.org/project/LKML/list/
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
++F: *
++F: */
+diff -urN linux-5.15/crypto/drbg.c linux-5.15-lrng/crypto/drbg.c
+--- linux-5.15/crypto/drbg.c 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/crypto/drbg.c 2021-11-29 12:37:31.183279025 +1100
+@@ -114,7 +114,7 @@
+ * the SHA256 / AES 256 over other ciphers. Thus, the favored
+ * DRBGs are the latest entries in this array.
+ */
+-static const struct drbg_core drbg_cores[] = {
++const struct drbg_core drbg_cores[] = {
+ #ifdef CONFIG_CRYPTO_DRBG_CTR
+ {
+ .flags = DRBG_CTR | DRBG_STRENGTH128,
+@@ -191,6 +191,7 @@
+ },
+ #endif /* CONFIG_CRYPTO_DRBG_HMAC */
+ };
++EXPORT_SYMBOL(drbg_cores);
+
+ static int drbg_uninstantiate(struct drbg_state *drbg);
+
+@@ -206,7 +207,7 @@
+ * Return: normalized strength in *bytes* value or 32 as default
+ * to counter programming errors
+ */
+-static inline unsigned short drbg_sec_strength(drbg_flag_t flags)
++unsigned short drbg_sec_strength(drbg_flag_t flags)
+ {
+ switch (flags & DRBG_STRENGTH_MASK) {
+ case DRBG_STRENGTH128:
+@@ -219,6 +220,7 @@
+ return 32;
+ }
+ }
++EXPORT_SYMBOL(drbg_sec_strength);
+
+ /*
+ * FIPS 140-2 continuous self test for the noise source
+@@ -1215,7 +1217,7 @@
+ }
+
+ /* Free all substructures in a DRBG state without the DRBG state structure */
+-static inline void drbg_dealloc_state(struct drbg_state *drbg)
++void drbg_dealloc_state(struct drbg_state *drbg)
+ {
+ if (!drbg)
+ return;
+@@ -1236,12 +1238,13 @@
+ drbg->fips_primed = false;
+ }
+ }
++EXPORT_SYMBOL(drbg_dealloc_state);
+
+ /*
+ * Allocate all sub-structures for a DRBG state.
+ * The DRBG state structure must already be allocated.
+ */
+-static inline int drbg_alloc_state(struct drbg_state *drbg)
++int drbg_alloc_state(struct drbg_state *drbg)
+ {
+ int ret = -ENOMEM;
+ unsigned int sb_size = 0;
+@@ -1322,6 +1325,7 @@
+ drbg_dealloc_state(drbg);
+ return ret;
+ }
++EXPORT_SYMBOL(drbg_alloc_state);
+
+ /*************************************************************************
+ * DRBG interface functions
+@@ -1891,8 +1895,7 @@
+ *
+ * return: flags
+ */
+-static inline void drbg_convert_tfm_core(const char *cra_driver_name,
+- int *coreref, bool *pr)
++void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, bool *pr)
+ {
+ int i = 0;
+ size_t start = 0;
+@@ -1919,6 +1922,7 @@
+ }
+ }
+ }
++EXPORT_SYMBOL(drbg_convert_tfm_core);
+
+ static int drbg_kcapi_init(struct crypto_tfm *tfm)
+ {
+diff -urN linux-5.15/crypto/jitterentropy-kcapi.c linux-5.15-lrng/crypto/jitterentropy-kcapi.c
+--- linux-5.15/crypto/jitterentropy-kcapi.c 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/crypto/jitterentropy-kcapi.c 2021-11-29 12:37:52.903278942 +1100
+@@ -43,8 +43,7 @@
+ #include <linux/fips.h>
+ #include <linux/time.h>
+ #include <crypto/internal/rng.h>
+-
+-#include "jitterentropy.h"
++#include <crypto/internal/jitterentropy.h>
+
+ /***************************************************************************
+ * Helper function
+diff -urN linux-5.15/crypto/jitterentropy.c linux-5.15-lrng/crypto/jitterentropy.c
+--- linux-5.15/crypto/jitterentropy.c 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/crypto/jitterentropy.c 2021-11-29 12:37:52.903278942 +1100
+@@ -117,7 +117,7 @@
+ #define JENT_EHEALTH 9 /* Health test failed during initialization */
+ #define JENT_ERCT 10 /* RCT failed during initialization */
+
+-#include "jitterentropy.h"
++#include <crypto/internal/jitterentropy.h>
+
+ /***************************************************************************
+ * Adaptive Proportion Test
+diff -urN linux-5.15/crypto/jitterentropy.h linux-5.15-lrng/crypto/jitterentropy.h
+--- linux-5.15/crypto/jitterentropy.h 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/crypto/jitterentropy.h 1970-01-01 10:00:00.000000000 +1000
+@@ -1,17 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-
+-extern void *jent_zalloc(unsigned int len);
+-extern void jent_zfree(void *ptr);
+-extern int jent_fips_enabled(void);
+-extern void jent_panic(char *s);
+-extern void jent_memcpy(void *dest, const void *src, unsigned int n);
+-extern void jent_get_nstime(__u64 *out);
+-
+-struct rand_data;
+-extern int jent_entropy_init(void);
+-extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+- unsigned int len);
+-
+-extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+- unsigned int flags);
+-extern void jent_entropy_collector_free(struct rand_data *entropy_collector);
+diff -urN linux-5.15/drivers/char/Kconfig linux-5.15-lrng/drivers/char/Kconfig
+--- linux-5.15/drivers/char/Kconfig 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/drivers/char/Kconfig 2021-11-29 12:36:52.113279174 +1100
+@@ -451,4 +451,6 @@
+ pool. Otherwise, say N here so it will be regarded as device input that
+ only mixes the entropy pool.
+
++source "drivers/char/lrng/Kconfig"
++
+ endmenu
+diff -urN linux-5.15/drivers/char/Makefile linux-5.15-lrng/drivers/char/Makefile
+--- linux-5.15/drivers/char/Makefile 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/drivers/char/Makefile 2021-11-29 12:36:52.113279174 +1100
+@@ -3,7 +3,14 @@
+ # Makefile for the kernel character device drivers.
+ #
+
+-obj-y += mem.o random.o
++obj-y += mem.o
++
++ifeq ($(CONFIG_LRNG),y)
++ obj-y += lrng/
++else
++ obj-y += random.o
++endif
++
+ obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
+ obj-y += misc.o
+ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+diff -urN linux-5.15/drivers/char/lrng/Kconfig linux-5.15-lrng/drivers/char/lrng/Kconfig
+--- linux-5.15/drivers/char/lrng/Kconfig 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/Kconfig 2021-11-29 12:38:26.593278813 +1100
+@@ -0,0 +1,589 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# Linux Random Number Generator configuration
++#
++
++menuconfig LRNG
++ bool "Linux Random Number Generator"
++ select CRYPTO_LIB_SHA256 if CRYPTO
++ help
++ The Linux Random Number Generator (LRNG) is the replacement
++ of the existing /dev/random provided with drivers/char/random.c.
++ It generates entropy from different noise sources and
++ delivers significant entropy during boot.
++
++if LRNG
++
++menu "Specific DRNG seeding strategies"
++
++config LRNG_OVERSAMPLE_ENTROPY_SOURCES
++ bool "Oversample entropy sources"
++ default n
++ help
++ When enabling this option, the entropy sources are
++ over-sampled with the following approach: First, the
++ the entropy sources are requested to provide 64 bits more
++ entropy than the size of the entropy buffer. For example,
++ if the entropy buffer is 256 bits, 320 bits of entropy
++ is requested to fill that buffer.
++
++ Second, the seed operation of the deterministic RNG
++ requests 128 bits more data from each entropy source than
++ the security strength of the DRNG during initialization.
++ A prerequisite for this operation is that the digest size
++ of the used hash must be at least equally large to generate
++ that buffer. If the prerequisite is not met, this
++ oversampling is not applied.
++
++ This strategy is intended to offset the asymptotic entropy
++ increase to reach full entropy in a buffer.
++
++ The strategy is consistent with the requirements in
++ NIST SP800-90C and is only enforced with fips=1.
++
++ If unsure, say N.
++
++config LRNG_OVERSAMPLE_ES_BITS
++ int
++ default 0 if !LRNG_OVERSAMPLE_ENTROPY_SOURCES
++ default 64 if LRNG_OVERSAMPLE_ENTROPY_SOURCES
++
++config LRNG_SEED_BUFFER_INIT_ADD_BITS
++ int
++ default 0 if !LRNG_OVERSAMPLE_ENTROPY_SOURCES
++ default 128 if LRNG_OVERSAMPLE_ENTROPY_SOURCES
++
++endmenu # "Specific DRNG seeding strategies"
++
++menu "Entropy Source Configuration"
++
++comment "Interrupt Entropy Source"
++
++config LRNG_IRQ
++ bool "Enable Interrupt Entropy Source as LRNG Seed Source"
++ default y
++ help
++ The LRNG models an entropy source based on the timing of the
++ occurrence of interrupts. Enable this option to enable this
++ IRQ entropy source.
++
++ The IRQ entropy source is triggered every time an interrupt
++ arrives and thus causes the interrupt handler to execute
++ slightly longer. Disabling the IRQ entropy source implies
++ that the performance penalty on the interrupt handler added
++ by the LRNG is eliminated. Yet, this entropy source is
++ considered to be the internal entropy source of the LRNG.
++ Thus, only disable it if you ensured that other entropy
++ sources are available that supply the LRNG with entropy.
++
++ If you disable the IRQ entropy source, you MUST ensure
++ one or more entropy sources collectively have the
++ capability to deliver sufficient entropy with one invocation
++ at a rate compliant to the security strength of the DRNG
++ (usually 256 bits of entropy). In addition, if those
++ entropy sources do not deliver sufficient entropy during
++ first request, the reseed must be triggered from user
++ space or kernel space when sufficient entropy is considered
++ to be present.
++
++ If unsure, say Y.
++
++choice
++ prompt "Continuous entropy compression boot time setting"
++ default LRNG_CONTINUOUS_COMPRESSION_ENABLED
++ depends on LRNG_IRQ
++ help
++ Select the default behavior of the interrupt entropy source
++ continuous compression operation.
++
++ The Linux RNG collects entropy data during each interrupt.
++ For performance reasons, a amount of entropy data defined by
++ the LRNG entropy collection pool size is concatenated into
++ an array. When that array is filled up, a hash is calculated
++ to compress the entropy. That hash is calculated in
++ interrupt context.
++
++ In case such hash calculation in interrupt context is deemed
++ too time-consuming, the continuous compression operation
++ can be disabled. If disabled, the collection of entropy will
++ not trigger a hash compression operation in interrupt context.
++ The compression happens only when the DRNG is reseeded which is
++ in process context. This implies that old entropy data
++ collected after the last DRNG-reseed is overwritten with newer
++ entropy data once the collection pool is full instead of
++ retaining its entropy with the compression operation.
++
++ config LRNG_CONTINUOUS_COMPRESSION_ENABLED
++ bool "Enable continuous compression (default)"
++
++ config LRNG_CONTINUOUS_COMPRESSION_DISABLED
++ bool "Disable continuous compression"
++endchoice
++
++config LRNG_ENABLE_CONTINUOUS_COMPRESSION
++ bool
++ default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED
++ default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED
++
++config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION
++ bool "Runtime-switchable continuous entropy compression"
++ depends on LRNG_IRQ
++ help
++ Per default, the interrupt entropy source continuous
++ compression operation behavior is hard-wired into the kernel.
++ Enable this option to allow it to be configurable at boot time.
++
++ To modify the default behavior of the continuous
++ compression operation, use the kernel command line option
++ of lrng_sw_noise.lrng_pcpu_continuous_compression.
++
++ If unsure, say N.
++
++choice
++ prompt "LRNG Entropy Collection Pool Size"
++ default LRNG_COLLECTION_SIZE_1024
++ depends on LRNG_IRQ
++ help
++ Select the size of the LRNG entropy collection pool
++ storing data for the interrupt entropy source without
++ performing a compression operation. The larger the
++ collection size is, the faster the average interrupt
++ handling will be. The collection size represents the
++ number of bytes of the per-CPU memory used to batch
++ up entropy event data.
++
++ The default value is good for regular operations. Choose
++ larger sizes for servers that have no memory limitations.
++ If runtime memory is precious, choose a smaller size.
++
++ The collection size is unrelated to the entropy rate
++ or the amount of entropy the LRNG can process.
++
++ config LRNG_COLLECTION_SIZE_32
++ depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED
++ depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION
++ depends on !LRNG_OVERSAMPLE_ENTROPY_SOURCES
++ bool "32 interrupt events"
++
++ config LRNG_COLLECTION_SIZE_256
++ depends on !LRNG_OVERSAMPLE_ENTROPY_SOURCES
++ bool "256 interrupt events"
++
++ config LRNG_COLLECTION_SIZE_512
++ bool "512 interrupt events"
++
++ config LRNG_COLLECTION_SIZE_1024
++ bool "1024 interrupt events (default)"
++
++ config LRNG_COLLECTION_SIZE_2048
++ bool "2048 interrupt events"
++
++ config LRNG_COLLECTION_SIZE_4096
++ bool "4096 interrupt events"
++
++ config LRNG_COLLECTION_SIZE_8192
++ bool "8192 interrupt events"
++
++endchoice
++
++config LRNG_COLLECTION_SIZE
++ int
++ default 32 if LRNG_COLLECTION_SIZE_32
++ default 256 if LRNG_COLLECTION_SIZE_256
++ default 512 if LRNG_COLLECTION_SIZE_512
++ default 1024 if LRNG_COLLECTION_SIZE_1024
++ default 2048 if LRNG_COLLECTION_SIZE_2048
++ default 4096 if LRNG_COLLECTION_SIZE_4096
++ default 8192 if LRNG_COLLECTION_SIZE_8192
++
++config LRNG_HEALTH_TESTS
++ bool "Enable interrupt entropy source online health tests"
++ depends on LRNG_IRQ
++ help
++ The online health tests applied to the interrupt entropy
++ source validate the noise source at runtime for fatal
++ errors. These tests include SP800-90B compliant tests
++ which are invoked if the system is booted with fips=1.
++ In case of fatal errors during active SP800-90B tests,
++ the issue is logged and the noise data is discarded.
++ These tests are required for full compliance of the
++ interrupt entropy source with SP800-90B.
++
++ If unsure, say Y.
++
++config LRNG_RCT_BROKEN
++ bool "SP800-90B RCT with dangerous low cutoff value"
++ depends on LRNG_HEALTH_TESTS
++ depends on BROKEN
++ default n
++ help
++ This option enables a dangerously low SP800-90B repetitive
++ count test (RCT) cutoff value which makes it very likely
++ that the RCT is triggered to raise a self test failure.
++
++ This option is ONLY intended for developers wanting to
++ test the effectiveness of the SP800-90B RCT health test.
++
++ If unsure, say N.
++
++config LRNG_APT_BROKEN
++ bool "SP800-90B APT with dangerous low cutoff value"
++ depends on LRNG_HEALTH_TESTS
++ depends on BROKEN
++ default n
++ help
++ This option enables a dangerously low SP800-90B adaptive
++ proportion test (APT) cutoff value which makes it very
++ likely that the APT is triggered to raise a self test
++ failure.
++
++ This option is ONLY intended for developers wanting to
++ test the effectiveness of the SP800-90B APT health test.
++
++ If unsure, say N.
++
++# Default taken from SP800-90B sec 4.4.1 - significance level 2^-30
++config LRNG_RCT_CUTOFF
++ int
++ default 31 if !LRNG_RCT_BROKEN
++ default 1 if LRNG_RCT_BROKEN
++
++# Default taken from SP800-90B sec 4.4.2 - significance level 2^-30
++config LRNG_APT_CUTOFF
++ int
++ default 325 if !LRNG_APT_BROKEN
++ default 32 if LRNG_APT_BROKEN
++
++config LRNG_IRQ_ENTROPY_RATE
++ int "Interrupt Entropy Source Entropy Rate"
++ depends on LRNG_IRQ
++ range 256 4294967295
++ default 256
++ help
++ The LRNG will collect the configured number of interrupts to
++ obtain 256 bits of entropy. This value can be set to any between
++ 256 and 4294967295. The LRNG guarantees that this value is not
++ lower than 256. This lower limit implies that one interrupt event
++ is credited with one bit of entropy. This value is subject to the
++ increase by the oversampling factor, if no high-resolution timer
++ is found.
++
++ In order to effectively disable the interrupt entropy source,
++ the option has to be set to 4294967295. In this case, the
++ interrupt entropy source will still deliver data but without
++ being credited with entropy.
++
++comment "Jitter RNG Entropy Source"
++
++config LRNG_JENT
++ bool "Enable Jitter RNG as LRNG Seed Source"
++ depends on CRYPTO
++ select CRYPTO_JITTERENTROPY
++ help
++ The Linux RNG may use the Jitter RNG as noise source. Enabling
++ this option enables the use of the Jitter RNG. Its default
++ entropy level is 16 bits of entropy per 256 data bits delivered
++ by the Jitter RNG. This entropy level can be changed at boot
++ time or at runtime with the lrng_base.jitterrng configuration
++ variable.
++
++config LRNG_JENT_ENTROPY_RATE
++ int "Jitter RNG Entropy Source Entropy Rate"
++ depends on LRNG_JENT
++ range 0 256
++ default 16
++ help
++ The option defines the amount of entropy the LRNG applies to 256
++ bits of data obtained from the Jitter RNG entropy source. The
++ LRNG enforces the limit that this value must be in the range
++ between 0 and 256.
++
++ When configuring this value to 0, the Jitter RNG entropy source
++ will provide 256 bits of data without being credited to contain
++ entropy.
++
++comment "CPU Entropy Source"
++
++config LRNG_CPU
++ bool "Enable CPU Entropy Source as LRNG Seed Source"
++ default y
++ help
++ Current CPUs commonly contain entropy sources which can be
++ used to seed the LRNG. For example, the Intel RDSEED
++ instruction, or the POWER DARN instruction will be sourced
++ to seed the LRNG if this option is enabled.
++
++ Note, if this option is enabled and the underlying CPU
++ does not offer such entropy source, the LRNG will automatically
++ detect this and ignore the hardware.
++
++config LRNG_CPU_FULL_ENT_MULTIPLIER
++ int
++ default 1 if !LRNG_TEST_CPU_ES_COMPRESSION
++ default 123 if LRNG_TEST_CPU_ES_COMPRESSION
++
++config LRNG_CPU_ENTROPY_RATE
++ int "CPU Entropy Source Entropy Rate"
++ depends on LRNG_CPU
++ range 0 256
++ default 8
++ help
++ The option defines the amount of entropy the LRNG applies to 256
++ bits of data obtained from the CPU entropy source. The LRNG
++ enforces the limit that this value must be in the range between
++ 0 and 256.
++
++ When configuring this value to 0, the CPU entropy source will
++ provide 256 bits of data without being credited to contain
++ entropy.
++
++ Note, this option is overwritten when the option
++ CONFIG_RANDOM_TRUST_CPU is set.
++
++endmenu # "Entropy Source Configuration"
++
++menuconfig LRNG_DRNG_SWITCH
++ bool "Support DRNG runtime switching"
++ help
++ The Linux RNG per default uses a ChaCha20 DRNG that is
++ accessible via the external interfaces. With this configuration
++ option other DRNGs can be selected and loaded at runtime.
++
++if LRNG_DRNG_SWITCH
++
++config LRNG_KCAPI_HASH
++ bool
++ select CRYPTO_HASH
++
++config LRNG_DRBG
++ tristate "SP800-90A support for the LRNG"
++ depends on CRYPTO
++ select CRYPTO_DRBG_MENU
++ select CRYPTO_SHA512
++ select LRNG_KCAPI_HASH
++ help
++ Enable the SP800-90A DRBG support for the LRNG. Once the
++ module is loaded, output from /dev/random, /dev/urandom,
++ getrandom(2), or get_random_bytes_full is provided by a DRBG.
++
++config LRNG_KCAPI
++ tristate "Kernel Crypto API support for the LRNG"
++ depends on CRYPTO
++ depends on !LRNG_DRBG
++ select CRYPTO_RNG
++ select LRNG_KCAPI_HASH
++ help
++ Enable the support for generic pseudo-random number
++ generators offered by the kernel crypto API with the
++ LRNG. Once the module is loaded, output from /dev/random,
++ /dev/urandom, getrandom(2), or get_random_bytes is
++ provided by the selected kernel crypto API RNG.
++endif # LRNG_DRNG_SWITCH
++
++menuconfig LRNG_TESTING_MENU
++ bool "LRNG testing interfaces"
++ depends on DEBUG_FS
++ help
++ Enable one or more of the following test interfaces.
++
++ If unsure, say N.
++
++if LRNG_TESTING_MENU
++
++config LRNG_RAW_HIRES_ENTROPY
++ bool "Enable entropy test interface to hires timer noise source"
++ default y
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned high resolution time stamp noise that
++ is collected by the LRNG for statistical analysis. Extracted
++ noise data is not used to seed the LRNG.
++
++ The raw noise data can be obtained using the lrng_raw_hires
++ debugfs file. Using the option lrng_testing.boot_raw_hires_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_JIFFIES_ENTROPY
++ bool "Enable entropy test interface to Jiffies noise source"
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned Jiffies that is collected by
++ the LRNG for statistical analysis. This data is used for
++ seeding the LRNG if a high-resolution time stamp is not
++ available. If a high-resolution time stamp is detected,
++ the Jiffies value is not collected by the LRNG and no
++ data is provided via the test interface. Extracted noise
++ data is not used to seed the random number generator.
++
++ The raw noise data can be obtained using the lrng_raw_jiffies
++ debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_IRQ_ENTROPY
++ bool "Enable entropy test interface to IRQ number noise source"
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned interrupt number that is collected by
++ the LRNG for statistical analysis. This data is used for
++ seeding the random32 PRNG external to the LRNG if a
++ high-resolution time stamp is available or it will be used to
++ seed the LRNG otherwise. Extracted noise data is not used to
++ seed the random number generator.
++
++ The raw noise data can be obtained using the lrng_raw_irq
++ debugfs file. Using the option lrng_testing.boot_raw_irq_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_IRQFLAGS_ENTROPY
++ bool "Enable entropy test interface to IRQ flags noise source"
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned interrupt flags that is collected by
++ the LRNG for statistical analysis. This data is used for
++ seeding the random32 PRNG external to the LRNG if a
++ high-resolution time stamp is available or it will be used to
++ seed the LRNG otherwise. Extracted noise data is not used to
++ seed the random number generator.
++
++ The raw noise data can be obtained using the lrng_raw_irqflags
++ debugfs file. Using the option lrng_testing.boot_raw_irqflags_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_RETIP_ENTROPY
++ bool "Enable entropy test interface to RETIP value noise source"
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned return instruction pointer value
++ that is collected by the LRNG for statistical analysis.
++ This data is used for seeding the random32 PRNG external
++ to the LRNG if a high-resolution time stamp is available or
++ it will be used to seed the LRNG otherwise. Extracted noise
++ data is not used to seed the random number generator.
++
++ The raw noise data can be obtained using the lrng_raw_retip
++ debugfs file. Using the option lrng_testing.boot_raw_retip_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_REGS_ENTROPY
++ bool "Enable entropy test interface to IRQ register value noise source"
++ help
++ The test interface allows a privileged process to capture
++ the raw unconditioned interrupt register value that is
++ collected by the LRNG for statistical analysis. Extracted noise
++ data is not used to seed the random number generator.
++
++ The raw noise data can be obtained using the lrng_raw_regs
++ debugfs file. Using the option lrng_testing.boot_raw_regs_test=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_RAW_ARRAY
++ bool "Enable test interface to LRNG raw entropy storage array"
++ help
++ The test interface allows a privileged process to capture
++ the raw noise data that is collected by the LRNG
++ in the per-CPU array for statistical analysis. The purpose
++ of this interface is to verify that the array handling code
++ truly only concatenates data and provides the same entropy
++ rate as the raw unconditioned noise source when assessing
++ the collected data byte-wise.
++
++ The data can be obtained using the lrng_raw_array debugfs
++ file. Using the option lrng_testing.boot_raw_array=1
++ the raw noise of the first 1000 entropy events since boot
++ can be sampled.
++
++config LRNG_IRQ_PERF
++ bool "Enable LRNG interrupt performance monitor"
++ help
++ With this option, the performance monitor of the LRNG
++ interrupt handling code is enabled. The file provides
++ the execution time of the interrupt handler in
++ cycles.
++
++ The interrupt performance data can be obtained using
++ the lrng_irq_perf debugfs file. Using the option
++ lrng_testing.boot_irq_perf=1 the performance data of
++ the first 1000 entropy events since boot can be sampled.
++
++config LRNG_ACVT_HASH
++ bool "Enable LRNG ACVT Hash interface"
++ help
++ With this option, the LRNG built-in hash function used for
++ auxiliary pool management and prior to switching the
++ cryptographic backends is made available for ACVT. The
++ interface allows writing of the data to be hashed
++ into the interface. The read operation triggers the hash
++ operation to generate message digest.
++
++ The ACVT interface is available with the lrng_acvt_hash
++ debugfs file.
++
++config LRNG_RUNTIME_ES_CONFIG
++ bool "Enable runtime configuration of entropy sources"
++ help
++ When enabling this option, the LRNG provides the mechanism
++ allowing to alter the entropy rate of each entropy source
++ during boot time and runtime.
++
++ The following interfaces are available:
++ lrng_archrandom.archrandom for the CPU entropy source,
++ lrng_jent.jitterrng for the Jitter RNG entropy source, and
++ lrng_sw_noise.irq_entropy for the interrupt entropy source.
++
++config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG
++ bool "Enable runtime configuration of max reseed threshold"
++ help
++ When enabling this option, the LRNG provides an interface
++ allowing the setting of the maximum number of DRNG generate
++ operations without a reseed that has full entropy. The
++ interface is lrng_drng.max_wo_reseed.
++
++config LRNG_TEST_CPU_ES_COMPRESSION
++ bool "Force CPU ES compression operation"
++ help
++ When enabling this option, the CPU ES compression operation
++ is forced by setting an arbitrary value > 1 for the data
++ multiplier even when the CPU ES would deliver full entropy.
++ This allows testing of the compression operation. It
++ therefore forces to pull more data from the CPU ES
++ than what may be required.
++
++config LRNG_TESTING
++ bool
++ default y if (LRNG_RAW_HIRES_ENTROPY || LRNG_RAW_JIFFIES_ENTROPY ||LRNG_RAW_IRQ_ENTROPY || LRNG_RAW_IRQFLAGS_ENTROPY || LRNG_RAW_RETIP_ENTROPY || LRNG_RAW_REGS_ENTROPY || LRNG_RAW_ARRAY || LRNG_IRQ_PERF || LRNG_ACVT_HASH)
++
++endif #LRNG_TESTING_MENU
++
++config LRNG_SELFTEST
++ bool "Enable power-on and on-demand self-tests"
++ help
++ The power-on self-tests are executed during boot time
++ covering the ChaCha20 DRNG, the hash operation used for
++ processing the entropy pools and the auxiliary pool, and
++ the time stamp management of the LRNG.
++
++ The on-demand self-tests are triggered by writing any
++ value into the SysFS file selftest_status. At the same
++ time, when reading this file, the test status is
++ returned. A zero indicates that all tests were executed
++ successfully.
++
++ If unsure, say Y.
++
++if LRNG_SELFTEST
++
++config LRNG_SELFTEST_PANIC
++ bool "Panic the kernel upon self-test failure"
++ help
++ If the option is enabled, the kernel is terminated if an
++ LRNG power-on self-test failure is detected.
++
++endif # LRNG_SELFTEST
++
++endif # LRNG
+diff -urN linux-5.15/drivers/char/lrng/Makefile linux-5.15-lrng/drivers/char/lrng/Makefile
+--- linux-5.15/drivers/char/lrng/Makefile 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/Makefile 2021-11-29 12:38:26.593278813 +1100
+@@ -0,0 +1,21 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# Makefile for the Linux Random Number Generator.
++#
++
++obj-y += lrng_es_mgr.o lrng_aux.o \
++ lrng_drng.o lrng_chacha20.o \
++ lrng_interfaces.o lrng_es_aux.o
++
++obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o
++obj-$(CONFIG_SYSCTL) += lrng_proc.o
++obj-$(CONFIG_NUMA) += lrng_numa.o
++obj-$(CONFIG_LRNG_CPU) += lrng_es_archrandom.o
++obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o
++obj-$(CONFIG_LRNG_KCAPI_HASH) += lrng_kcapi_hash.o
++obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o
++obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o
++obj-$(CONFIG_LRNG_JENT) += lrng_es_jent.o
++obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o
++obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o
++obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o
+diff -urN linux-5.15/drivers/char/lrng/lrng_aux.c linux-5.15-lrng/drivers/char/lrng/lrng_aux.c
+--- linux-5.15/drivers/char/lrng/lrng_aux.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_aux.c 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,136 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG auxiliary interfaces
++ *
++ * Copyright (C) 2019 - 2021 Stephan Mueller <smueller@chronox.de>
++ * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All
++ * Rights Reserved.
++ * Copyright (C) 2016 Jason Cooper <jason@lakedaemon.net>
++ */
++
++#include <linux/mm.h>
++#include <linux/random.h>
++
++#include "lrng_internal.h"
++
++struct batched_entropy {
++ union {
++ u64 entropy_u64[LRNG_DRNG_BLOCKSIZE / sizeof(u64)];
++ u32 entropy_u32[LRNG_DRNG_BLOCKSIZE / 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 as good as /dev/urandom, but there is no backtrack protection,
++ * with the goal of being quite fast and not depleting entropy.
++ */
++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;
++
++ lrng_debug_report_seedlevel("get_random_u64");
++
++ batch = raw_cpu_ptr(&batched_entropy_u64);
++ spin_lock_irqsave(&batch->batch_lock, flags);
++ if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
++ lrng_drng_get_atomic((u8 *)batch->entropy_u64,
++ LRNG_DRNG_BLOCKSIZE);
++ 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;
++
++ lrng_debug_report_seedlevel("get_random_u32");
++
++ batch = raw_cpu_ptr(&batched_entropy_u32);
++ spin_lock_irqsave(&batch->batch_lock, flags);
++ if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
++ lrng_drng_get_atomic((u8 *)batch->entropy_u32,
++ LRNG_DRNG_BLOCKSIZE);
++ 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.
++ */
++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);
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_chacha20.c linux-5.15-lrng/drivers/char/lrng/lrng_chacha20.c
+--- linux-5.15/drivers/char/lrng/lrng_chacha20.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_chacha20.c 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,321 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Backend for the LRNG providing the cryptographic primitives using
++ * ChaCha20 cipher implementations.
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <crypto/chacha.h>
++#include <linux/lrng.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++
++#include "lrng_chacha20.h"
++#include "lrng_internal.h"
++
++/******************************* ChaCha20 DRNG *******************************/
++
++#define CHACHA_BLOCK_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32))
++
++struct chacha20_state {
++ struct chacha20_block block;
++};
++
++/*
++ * Have a static memory blocks for the ChaCha20 DRNG instance to avoid calling
++ * kmalloc too early in the boot cycle. For subsequent allocation requests,
++ * such as per-NUMA-node DRNG instances, kmalloc will be used.
++ */
++struct chacha20_state chacha20 __latent_entropy;
++
++/*
++ * Update of the ChaCha20 state by either using an unused buffer part or by
++ * generating one ChaCha20 block which is half of the state of the ChaCha20.
++ * The block is XORed into the key part of the state. This shall ensure
++ * backtracking resistance as well as a proper mix of the ChaCha20 state once
++ * the key is injected.
++ */
++static void lrng_chacha20_update(struct chacha20_state *chacha20_state,
++ __le32 *buf, u32 used_words)
++{
++ struct chacha20_block *chacha20 = &chacha20_state->block;
++ u32 i;
++ __le32 tmp[CHACHA_BLOCK_WORDS];
++
++ BUILD_BUG_ON(sizeof(struct chacha20_block) != CHACHA_BLOCK_SIZE);
++ BUILD_BUG_ON(CHACHA_BLOCK_SIZE != 2 * CHACHA_KEY_SIZE);
++
++ if (used_words > CHACHA_KEY_SIZE_WORDS) {
++ chacha20_block(&chacha20->constants[0], (u8 *)tmp);
++ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++)
++ chacha20->key.u[i] ^= le32_to_cpu(tmp[i]);
++ memzero_explicit(tmp, sizeof(tmp));
++ } else {
++ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++)
++ chacha20->key.u[i] ^= le32_to_cpu(buf[i + used_words]);
++ }
++
++ /* Deterministic increment of nonce as required in RFC 7539 chapter 4 */
++ chacha20->nonce[0]++;
++ if (chacha20->nonce[0] == 0) {
++ chacha20->nonce[1]++;
++ if (chacha20->nonce[1] == 0)
++ chacha20->nonce[2]++;
++ }
++
++ /* Leave counter untouched as it is start value is undefined in RFC */
++}
++
++/*
++ * Seed the ChaCha20 DRNG by injecting the input data into the key part of
++ * the ChaCha20 state. If the input data is longer than the ChaCha20 key size,
++ * perform a ChaCha20 operation after processing of key size input data.
++ * This operation shall spread out the entropy into the ChaCha20 state before
++ * new entropy is injected into the key part.
++ */
++static int lrng_cc20_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen)
++{
++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
++ struct chacha20_block *chacha20 = &chacha20_state->block;
++
++ while (inbuflen) {
++ u32 i, todo = min_t(u32, inbuflen, CHACHA_KEY_SIZE);
++
++ for (i = 0; i < todo; i++)
++ chacha20->key.b[i] ^= inbuf[i];
++
++ /* Break potential dependencies between the inbuf key blocks */
++ lrng_chacha20_update(chacha20_state, NULL,
++ CHACHA_BLOCK_WORDS);
++ inbuf += todo;
++ inbuflen -= todo;
++ }
++
++ return 0;
++}
++
++/*
++ * Chacha20 DRNG generation of random numbers: the stream output of ChaCha20
++ * is the random number. After the completion of the generation of the
++ * stream, the entire ChaCha20 state is updated.
++ *
++ * Note, as the ChaCha20 implements a 32 bit counter, we must ensure
++ * that this function is only invoked for at most 2^32 - 1 ChaCha20 blocks
++ * before a reseed or an update happens. This is ensured by the variable
++ * outbuflen which is a 32 bit integer defining the number of bytes to be
++ * generated by the ChaCha20 DRNG. At the end of this function, an update
++ * operation is invoked which implies that the 32 bit counter will never be
++ * overflown in this implementation.
++ */
++static int lrng_cc20_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen)
++{
++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
++ struct chacha20_block *chacha20 = &chacha20_state->block;
++ __le32 aligned_buf[CHACHA_BLOCK_WORDS];
++ u32 ret = outbuflen, used = CHACHA_BLOCK_WORDS;
++ int zeroize_buf = 0;
++
++ while (outbuflen >= CHACHA_BLOCK_SIZE) {
++ chacha20_block(&chacha20->constants[0], outbuf);
++ outbuf += CHACHA_BLOCK_SIZE;
++ outbuflen -= CHACHA_BLOCK_SIZE;
++ }
++
++ if (outbuflen) {
++ chacha20_block(&chacha20->constants[0], (u8 *)aligned_buf);
++ memcpy(outbuf, aligned_buf, outbuflen);
++ used = ((outbuflen + sizeof(aligned_buf[0]) - 1) /
++ sizeof(aligned_buf[0]));
++ zeroize_buf = 1;
++ }
++
++ lrng_chacha20_update(chacha20_state, aligned_buf, used);
++
++ if (zeroize_buf)
++ memzero_explicit(aligned_buf, sizeof(aligned_buf));
++
++ return ret;
++}
++
++void lrng_cc20_init_state(struct chacha20_state *state)
++{
++ lrng_cc20_init_rfc7539(&state->block);
++}
++
++/*
++ * Allocation of the DRNG state
++ */
++static void *lrng_cc20_drng_alloc(u32 sec_strength)
++{
++ struct chacha20_state *state = NULL;
++
++ if (sec_strength > CHACHA_KEY_SIZE) {
++ pr_err("Security strength of ChaCha20 DRNG (%u bits) lower than requested by LRNG (%u bits)\n",
++ CHACHA_KEY_SIZE * 8, sec_strength * 8);
++ return ERR_PTR(-EINVAL);
++ }
++ if (sec_strength < CHACHA_KEY_SIZE)
++ pr_warn("Security strength of ChaCha20 DRNG (%u bits) higher than requested by LRNG (%u bits)\n",
++ CHACHA_KEY_SIZE * 8, sec_strength * 8);
++
++ state = kmalloc(sizeof(struct chacha20_state), GFP_KERNEL);
++ if (!state)
++ return ERR_PTR(-ENOMEM);
++ pr_debug("memory for ChaCha20 core allocated\n");
++
++ lrng_cc20_init_state(state);
++
++ return state;
++}
++
++static void lrng_cc20_drng_dealloc(void *drng)
++{
++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng;
++
++ if (drng == &chacha20) {
++ memzero_explicit(chacha20_state, sizeof(*chacha20_state));
++ pr_debug("static ChaCha20 core zeroized\n");
++ return;
++ }
++
++ pr_debug("ChaCha20 core zeroized and freed\n");
++ kfree_sensitive(chacha20_state);
++}
++
++/******************************* Hash Operation *******************************/
++
++#ifdef CONFIG_CRYPTO_LIB_SHA256
++
++#include <crypto/sha2.h>
++
++static u32 lrng_cc20_hash_digestsize(void *hash)
++{
++ return SHA256_DIGEST_SIZE;
++}
++
++static int lrng_cc20_hash_init(struct shash_desc *shash, void *hash)
++{
++ /*
++ * We do not need a TFM - we only need sufficient space for
++ * struct sha256_state on the stack.
++ */
++ sha256_init(shash_desc_ctx(shash));
++ return 0;
++}
++
++static int lrng_cc20_hash_update(struct shash_desc *shash,
++ const u8 *inbuf, u32 inbuflen)
++{
++ sha256_update(shash_desc_ctx(shash), inbuf, inbuflen);
++ return 0;
++}
++
++static int lrng_cc20_hash_final(struct shash_desc *shash, u8 *digest)
++{
++ sha256_final(shash_desc_ctx(shash), digest);
++ return 0;
++}
++
++static const char *lrng_cc20_hash_name(void)
++{
++ return "SHA-256";
++}
++
++static void lrng_cc20_hash_desc_zero(struct shash_desc *shash)
++{
++ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha256_state));
++}
++
++#else /* CONFIG_CRYPTO_LIB_SHA256 */
++
++#include <crypto/sha1.h>
++#include <crypto/sha1_base.h>
++
++/*
++ * If the SHA-256 support is not compiled, we fall back to SHA-1 that is always
++ * compiled and present in the kernel.
++ */
++static u32 lrng_cc20_hash_digestsize(void *hash)
++{
++ return SHA1_DIGEST_SIZE;
++}
++
++static void lrng_sha1_block_fn(struct sha1_state *sctx, const u8 *src,
++ int blocks)
++{
++ u32 temp[SHA1_WORKSPACE_WORDS];
++
++ while (blocks--) {
++ sha1_transform(sctx->state, src, temp);
++ src += SHA1_BLOCK_SIZE;
++ }
++ memzero_explicit(temp, sizeof(temp));
++}
++
++static int lrng_cc20_hash_init(struct shash_desc *shash, void *hash)
++{
++ /*
++ * We do not need a TFM - we only need sufficient space for
++ * struct sha1_state on the stack.
++ */
++ sha1_base_init(shash);
++ return 0;
++}
++
++static int lrng_cc20_hash_update(struct shash_desc *shash,
++ const u8 *inbuf, u32 inbuflen)
++{
++ return sha1_base_do_update(shash, inbuf, inbuflen, lrng_sha1_block_fn);
++}
++
++static int lrng_cc20_hash_final(struct shash_desc *shash, u8 *digest)
++{
++ return sha1_base_do_finalize(shash, lrng_sha1_block_fn) ?:
++ sha1_base_finish(shash, digest);
++}
++
++static const char *lrng_cc20_hash_name(void)
++{
++ return "SHA-1";
++}
++
++static void lrng_cc20_hash_desc_zero(struct shash_desc *shash)
++{
++ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha1_state));
++}
++
++#endif /* CONFIG_CRYPTO_LIB_SHA256 */
++
++static void *lrng_cc20_hash_alloc(void)
++{
++ pr_info("Hash %s allocated\n", lrng_cc20_hash_name());
++ return NULL;
++}
++
++static void lrng_cc20_hash_dealloc(void *hash)
++{
++}
++
++static const char *lrng_cc20_drng_name(void)
++{
++ return "ChaCha20 DRNG";
++}
++
++const struct lrng_crypto_cb lrng_cc20_crypto_cb = {
++ .lrng_drng_name = lrng_cc20_drng_name,
++ .lrng_hash_name = lrng_cc20_hash_name,
++ .lrng_drng_alloc = lrng_cc20_drng_alloc,
++ .lrng_drng_dealloc = lrng_cc20_drng_dealloc,
++ .lrng_drng_seed_helper = lrng_cc20_drng_seed_helper,
++ .lrng_drng_generate_helper = lrng_cc20_drng_generate_helper,
++ .lrng_hash_alloc = lrng_cc20_hash_alloc,
++ .lrng_hash_dealloc = lrng_cc20_hash_dealloc,
++ .lrng_hash_digestsize = lrng_cc20_hash_digestsize,
++ .lrng_hash_init = lrng_cc20_hash_init,
++ .lrng_hash_update = lrng_cc20_hash_update,
++ .lrng_hash_final = lrng_cc20_hash_final,
++ .lrng_hash_desc_zero = lrng_cc20_hash_desc_zero,
++};
+diff -urN linux-5.15/drivers/char/lrng/lrng_chacha20.h linux-5.15-lrng/drivers/char/lrng/lrng_chacha20.h
+--- linux-5.15/drivers/char/lrng/lrng_chacha20.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_chacha20.h 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,25 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++/*
++ * LRNG ChaCha20 definitions
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#include <crypto/chacha.h>
++
++/* State according to RFC 7539 section 2.3 */
++struct chacha20_block {
++ u32 constants[4];
++ union {
++#define CHACHA_KEY_SIZE_WORDS (CHACHA_KEY_SIZE / sizeof(u32))
++ u32 u[CHACHA_KEY_SIZE_WORDS];
++ u8 b[CHACHA_KEY_SIZE];
++ } key;
++ u32 counter;
++ u32 nonce[3];
++};
++
++static inline void lrng_cc20_init_rfc7539(struct chacha20_block *chacha20)
++{
++ chacha_init_consts(chacha20->constants);
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_drbg.c linux-5.15-lrng/drivers/char/lrng/lrng_drbg.c
+--- linux-5.15/drivers/char/lrng/lrng_drbg.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_drbg.c 2021-11-29 12:37:37.193279002 +1100
+@@ -0,0 +1,198 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Backend for the LRNG providing the cryptographic primitives using the
++ * kernel crypto API and its DRBG.
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <crypto/drbg.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/lrng.h>
++
++#include "lrng_kcapi_hash.h"
++
++/*
++ * Define a DRBG plus a hash / MAC used to extract data from the entropy pool.
++ * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice
++ * (Note, you should use the suggested selections below -- using SHA-1 or MD5
++ * is not wise). The idea is that the used cipher primitive can be selected to
++ * be the same as used for the DRBG. I.e. the LRNG only uses one cipher
++ * primitive using the same cipher implementation with the options offered in
++ * the following. This means, if the CTR DRBG is selected and AES-NI is present,
++ * both the CTR DRBG and the selected cmac(aes) use AES-NI.
++ *
++ * The security strengths of the DRBGs are all 256 bits according to
++ * SP800-57 section 5.6.1.
++ *
++ * This definition is allowed to be changed.
++ */
++#ifdef CONFIG_CRYPTO_DRBG_CTR
++static unsigned int lrng_drbg_type = 0;
++#elif defined CONFIG_CRYPTO_DRBG_HMAC
++static unsigned int lrng_drbg_type = 1;
++#elif defined CONFIG_CRYPTO_DRBG_HASH
++static unsigned int lrng_drbg_type = 2;
++#else
++#error "Unknown DRBG in use"
++#endif
++
++/* The parameter must be r/o in sysfs as otherwise races appear. */
++module_param(lrng_drbg_type, uint, 0444);
++MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, 1->HMAC_DRBG, 2->Hash_DRBG)");
++
++struct lrng_drbg {
++ const char *hash_name;
++ const char *drbg_core;
++};
++
++static const struct lrng_drbg lrng_drbg_types[] = {
++ { /* CTR_DRBG with AES-256 using derivation function */
++ .hash_name = "sha512",
++ .drbg_core = "drbg_nopr_ctr_aes256",
++ }, { /* HMAC_DRBG with SHA-512 */
++ .hash_name = "sha512",
++ .drbg_core = "drbg_nopr_hmac_sha512",
++ }, { /* Hash_DRBG with SHA-512 using derivation function */
++ .hash_name = "sha512",
++ .drbg_core = "drbg_nopr_sha512"
++ }
++};
++
++static int lrng_drbg_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen)
++{
++ struct drbg_state *drbg = (struct drbg_state *)drng;
++ LIST_HEAD(seedlist);
++ struct drbg_string data;
++ int ret;
++
++ drbg_string_fill(&data, inbuf, inbuflen);
++ list_add_tail(&data.list, &seedlist);
++ ret = drbg->d_ops->update(drbg, &seedlist, drbg->seeded);
++
++ if (ret >= 0)
++ drbg->seeded = true;
++
++ return ret;
++}
++
++static int lrng_drbg_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen)
++{
++ struct drbg_state *drbg = (struct drbg_state *)drng;
++
++ return drbg->d_ops->generate(drbg, outbuf, outbuflen, NULL);
++}
++
++static void *lrng_drbg_drng_alloc(u32 sec_strength)
++{
++ struct drbg_state *drbg;
++ int coreref = -1;
++ bool pr = false;
++ int ret;
++
++ drbg_convert_tfm_core(lrng_drbg_types[lrng_drbg_type].drbg_core,
++ &coreref, &pr);
++ if (coreref < 0)
++ return ERR_PTR(-EFAULT);
++
++ drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL);
++ if (!drbg)
++ return ERR_PTR(-ENOMEM);
++
++ drbg->core = &drbg_cores[coreref];
++ drbg->seeded = false;
++ ret = drbg_alloc_state(drbg);
++ if (ret)
++ goto err;
++
++ if (sec_strength > drbg_sec_strength(drbg->core->flags)) {
++ pr_err("Security strength of DRBG (%u bits) lower than requested by LRNG (%u bits)\n",
++ drbg_sec_strength(drbg->core->flags) * 8,
++ sec_strength * 8);
++ goto dealloc;
++ }
++
++ if (sec_strength < drbg_sec_strength(drbg->core->flags))
++ pr_warn("Security strength of DRBG (%u bits) higher than requested by LRNG (%u bits)\n",
++ drbg_sec_strength(drbg->core->flags) * 8,
++ sec_strength * 8);
++
++ pr_info("DRBG with %s core allocated\n", drbg->core->backend_cra_name);
++
++ return drbg;
++
++dealloc:
++ if (drbg->d_ops)
++ drbg->d_ops->crypto_fini(drbg);
++ drbg_dealloc_state(drbg);
++err:
++ kfree(drbg);
++ return ERR_PTR(-EINVAL);
++}
++
++static void lrng_drbg_drng_dealloc(void *drng)
++{
++ struct drbg_state *drbg = (struct drbg_state *)drng;
++
++ if (drbg && drbg->d_ops)
++ drbg->d_ops->crypto_fini(drbg);
++ drbg_dealloc_state(drbg);
++ kfree_sensitive(drbg);
++ pr_info("DRBG deallocated\n");
++}
++
++static void *lrng_drbg_hash_alloc(void)
++{
++ return lrng_kcapi_hash_alloc(lrng_drbg_types[lrng_drbg_type].hash_name);
++}
++
++static const char *lrng_drbg_name(void)
++{
++ return lrng_drbg_types[lrng_drbg_type].drbg_core;
++}
++
++static const char *lrng_hash_name(void)
++{
++ return lrng_drbg_types[lrng_drbg_type].hash_name;
++}
++
++static const struct lrng_crypto_cb lrng_drbg_crypto_cb = {
++ .lrng_drng_name = lrng_drbg_name,
++ .lrng_hash_name = lrng_hash_name,
++ .lrng_drng_alloc = lrng_drbg_drng_alloc,
++ .lrng_drng_dealloc = lrng_drbg_drng_dealloc,
++ .lrng_drng_seed_helper = lrng_drbg_drng_seed_helper,
++ .lrng_drng_generate_helper = lrng_drbg_drng_generate_helper,
++ .lrng_hash_alloc = lrng_drbg_hash_alloc,
++ .lrng_hash_dealloc = lrng_kcapi_hash_dealloc,
++ .lrng_hash_digestsize = lrng_kcapi_hash_digestsize,
++ .lrng_hash_init = lrng_kcapi_hash_init,
++ .lrng_hash_update = lrng_kcapi_hash_update,
++ .lrng_hash_final = lrng_kcapi_hash_final,
++ .lrng_hash_desc_zero = lrng_kcapi_hash_zero,
++};
++
++static int __init lrng_drbg_init(void)
++{
++ if (lrng_drbg_type >= ARRAY_SIZE(lrng_drbg_types)) {
++ pr_err("lrng_drbg_type parameter too large (given %u - max: %lu)",
++ lrng_drbg_type,
++ (unsigned long)ARRAY_SIZE(lrng_drbg_types) - 1);
++ return -EAGAIN;
++ }
++ return lrng_set_drng_cb(&lrng_drbg_crypto_cb);
++}
++
++static void __exit lrng_drbg_exit(void)
++{
++ lrng_set_drng_cb(NULL);
++}
++
++late_initcall(lrng_drbg_init);
++module_exit(lrng_drbg_exit);
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
++MODULE_DESCRIPTION("Linux Random Number Generator - SP800-90A DRBG backend");
+diff -urN linux-5.15/drivers/char/lrng/lrng_drng.c linux-5.15-lrng/drivers/char/lrng/lrng_drng.c
+--- linux-5.15/drivers/char/lrng/lrng_drng.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_drng.c 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,451 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG DRNG processing
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/fips.h>
++#include <linux/lrng.h>
++
++#include "lrng_internal.h"
++
++/*
++ * Maximum number of seconds between DRNG reseed intervals of the DRNG. Note,
++ * this is enforced with the next request of random numbers from the
++ * DRNG. Setting this value to zero implies a reseeding attempt before every
++ * generated random number.
++ */
++int lrng_drng_reseed_max_time = 600;
++
++static atomic_t lrng_avail = ATOMIC_INIT(0);
++
++DEFINE_MUTEX(lrng_crypto_cb_update);
++
++/* DRNG for /dev/urandom, getrandom(2), get_random_bytes */
++static struct lrng_drng lrng_drng_init = {
++ .drng = &chacha20,
++ .crypto_cb = &lrng_cc20_crypto_cb,
++ .lock = __MUTEX_INITIALIZER(lrng_drng_init.lock),
++ .spin_lock = __SPIN_LOCK_UNLOCKED(lrng_drng_init.spin_lock),
++ .hash_lock = __RW_LOCK_UNLOCKED(lrng_drng_init.hash_lock)
++};
++
++/*
++ * DRNG for get_random_bytes when called in atomic context. This
++ * DRNG will always use the ChaCha20 DRNG. It will never benefit from a
++ * DRNG switch like the "regular" DRNG. If there was no DRNG switch, the atomic
++ * DRNG is identical to the "regular" DRNG.
++ *
++ * The reason for having this is due to the fact that DRNGs other than
++ * the ChaCha20 DRNG may sleep.
++ */
++static struct lrng_drng lrng_drng_atomic = {
++ .drng = &chacha20,
++ .crypto_cb = &lrng_cc20_crypto_cb,
++ .spin_lock = __SPIN_LOCK_UNLOCKED(lrng_drng_atomic.spin_lock),
++ .hash_lock = __RW_LOCK_UNLOCKED(lrng_drng_atomic.hash_lock)
++};
++
++static u32 max_wo_reseed = LRNG_DRNG_MAX_WITHOUT_RESEED;
++#ifdef CONFIG_LRNG_RUNTIME_MAX_WO_RESEED_CONFIG
++module_param(max_wo_reseed, uint, 0444);
++MODULE_PARM_DESC(max_wo_reseed,
++ "Maximum number of DRNG generate operation without full reseed\n");
++#endif
++
++/********************************** Helper ************************************/
++
++bool lrng_get_available(void)
++{
++ return likely(atomic_read(&lrng_avail));
++}
++
++void lrng_set_available(void)
++{
++ atomic_set(&lrng_avail, 1);
++}
++
++struct lrng_drng *lrng_drng_init_instance(void)
++{
++ return &lrng_drng_init;
++}
++
++struct lrng_drng *lrng_drng_atomic_instance(void)
++{
++ return &lrng_drng_atomic;
++}
++
++void lrng_drng_reset(struct lrng_drng *drng)
++{
++ atomic_set(&drng->requests, LRNG_DRNG_RESEED_THRESH);
++ atomic_set(&drng->requests_since_fully_seeded, 0);
++ drng->last_seeded = jiffies;
++ drng->fully_seeded = false;
++ drng->force_reseed = true;
++ pr_debug("reset DRNG\n");
++}
++
++/* Initialize the default DRNG during boot */
++static void lrng_drng_seed(struct lrng_drng *drng);
++void lrng_drngs_init_cc20(bool force_seed)
++{
++ unsigned long flags = 0;
++
++ if (lrng_get_available())
++ return;
++
++ lrng_drng_lock(&lrng_drng_init, &flags);
++ if (lrng_get_available()) {
++ lrng_drng_unlock(&lrng_drng_init, &flags);
++ if (force_seed)
++ goto seed;
++ return;
++ }
++
++ lrng_drng_reset(&lrng_drng_init);
++ lrng_cc20_init_state(&chacha20);
++ lrng_drng_unlock(&lrng_drng_init, &flags);
++
++ lrng_drng_lock(&lrng_drng_atomic, &flags);
++ lrng_drng_reset(&lrng_drng_atomic);
++ /*
++ * We do not initialize the state of the atomic DRNG as it is identical
++ * to the DRNG at this point.
++ */
++ lrng_drng_unlock(&lrng_drng_atomic, &flags);
++
++ lrng_set_available();
++
++seed:
++ /* Seed the DRNG with any entropy available */
++ if (!lrng_pool_trylock()) {
++ lrng_drng_seed(&lrng_drng_init);
++ pr_info("ChaCha20 core initialized with first seeding\n");
++ lrng_pool_unlock();
++ } else {
++ pr_info("ChaCha20 core initialized without seeding\n");
++ }
++}
++
++bool lrng_sp80090c_compliant(void)
++{
++ if (!IS_ENABLED(CONFIG_LRNG_OVERSAMPLE_ENTROPY_SOURCES))
++ return false;
++
++ /* Entropy source hash must be capable of transporting enough entropy */
++ if (lrng_get_digestsize() <
++ (lrng_security_strength() + CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS))
++ return false;
++
++ /* SP800-90C only requested in FIPS mode */
++ return fips_enabled;
++}
++
++/************************* Random Number Generation ***************************/
++
++/* Inject a data buffer into the DRNG */
++static void lrng_drng_inject(struct lrng_drng *drng,
++ const u8 *inbuf, u32 inbuflen, bool fully_seeded)
++{
++ const char *drng_type = unlikely(drng == &lrng_drng_atomic) ?
++ "atomic" : "regular";
++ unsigned long flags = 0;
++
++ BUILD_BUG_ON(LRNG_DRNG_RESEED_THRESH > INT_MAX);
++ pr_debug("seeding %s DRNG with %u bytes\n", drng_type, inbuflen);
++ lrng_drng_lock(drng, &flags);
++ if (drng->crypto_cb->lrng_drng_seed_helper(drng->drng,
++ inbuf, inbuflen) < 0) {
++ pr_warn("seeding of %s DRNG failed\n", drng_type);
++ drng->force_reseed = true;
++ } else {
++ int gc = LRNG_DRNG_RESEED_THRESH - atomic_read(&drng->requests);
++
++ pr_debug("%s DRNG stats since last seeding: %lu secs; generate calls: %d\n",
++ drng_type,
++ (time_after(jiffies, drng->last_seeded) ?
++ (jiffies - drng->last_seeded) : 0) / HZ, gc);
++
++ /* Count the numbers of generate ops since last fully seeded */
++ if (fully_seeded)
++ atomic_set(&drng->requests_since_fully_seeded, 0);
++ else
++ atomic_add(gc, &drng->requests_since_fully_seeded);
++
++ drng->last_seeded = jiffies;
++ atomic_set(&drng->requests, LRNG_DRNG_RESEED_THRESH);
++ drng->force_reseed = false;
++
++ if (!drng->fully_seeded) {
++ drng->fully_seeded = fully_seeded;
++ if (drng->fully_seeded)
++ pr_debug("DRNG fully seeded\n");
++ }
++
++ if (drng->drng == lrng_drng_atomic.drng) {
++ lrng_drng_atomic.last_seeded = jiffies;
++ atomic_set(&lrng_drng_atomic.requests,
++ LRNG_DRNG_RESEED_THRESH);
++ lrng_drng_atomic.force_reseed = false;
++ }
++ }
++ lrng_drng_unlock(drng, &flags);
++}
++
++/*
++ * Perform the seeding of the DRNG with data from noise source
++ */
++static inline void _lrng_drng_seed(struct lrng_drng *drng)
++{
++ struct entropy_buf seedbuf __aligned(LRNG_KCAPI_ALIGN);
++
++ lrng_fill_seed_buffer(&seedbuf,
++ lrng_get_seed_entropy_osr(drng->fully_seeded));
++ lrng_init_ops(&seedbuf);
++ lrng_drng_inject(drng, (u8 *)&seedbuf, sizeof(seedbuf),
++ lrng_fully_seeded(drng->fully_seeded, &seedbuf));
++ memzero_explicit(&seedbuf, sizeof(seedbuf));
++}
++
++static int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen);
++static void lrng_drng_seed(struct lrng_drng *drng)
++{
++ _lrng_drng_seed(drng);
++
++ BUILD_BUG_ON(LRNG_MIN_SEED_ENTROPY_BITS >
++ LRNG_DRNG_SECURITY_STRENGTH_BITS);
++
++ /*
++ * Reseed atomic DRNG from current DRNG,
++ *
++ * We can obtain random numbers from DRNG as the lock type
++ * chosen by lrng_drng_get is usable with the current caller.
++ */
++ if ((drng->drng != lrng_drng_atomic.drng) &&
++ (lrng_drng_atomic.force_reseed ||
++ atomic_read(&lrng_drng_atomic.requests) <= 0 ||
++ time_after(jiffies, lrng_drng_atomic.last_seeded +
++ lrng_drng_reseed_max_time * HZ))) {
++ u8 seedbuf[LRNG_DRNG_SECURITY_STRENGTH_BYTES]
++ __aligned(LRNG_KCAPI_ALIGN);
++ int ret = lrng_drng_get(drng, seedbuf, sizeof(seedbuf));
++
++ if (ret < 0) {
++ pr_warn("Error generating random numbers for atomic DRNG: %d\n",
++ ret);
++ } else {
++ lrng_drng_inject(&lrng_drng_atomic, seedbuf, ret, true);
++ }
++ memzero_explicit(&seedbuf, sizeof(seedbuf));
++ }
++}
++
++static inline void _lrng_drng_seed_work(struct lrng_drng *drng, u32 node)
++{
++ pr_debug("reseed triggered by interrupt noise source for DRNG on NUMA node %d\n",
++ node);
++ lrng_drng_seed(drng);
++ if (drng->fully_seeded) {
++ /* Prevent reseed storm */
++ drng->last_seeded += node * 100 * HZ;
++ /* Prevent draining of pool on idle systems */
++ lrng_drng_reseed_max_time += 100;
++ }
++}
++
++/*
++ * DRNG reseed trigger: Kernel thread handler triggered by the schedule_work()
++ */
++void lrng_drng_seed_work(struct work_struct *dummy)
++{
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ u32 node;
++
++ if (lrng_drng) {
++ for_each_online_node(node) {
++ struct lrng_drng *drng = lrng_drng[node];
++
++ if (drng && !drng->fully_seeded) {
++ _lrng_drng_seed_work(drng, node);
++ goto out;
++ }
++ }
++ } else {
++ if (!lrng_drng_init.fully_seeded) {
++ _lrng_drng_seed_work(&lrng_drng_init, 0);
++ goto out;
++ }
++ }
++
++ lrng_pool_all_numa_nodes_seeded(true);
++
++out:
++ /* Allow the seeding operation to be called again */
++ lrng_pool_unlock();
++}
++
++/* Force all DRNGs to reseed before next generation */
++void lrng_drng_force_reseed(void)
++{
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ u32 node;
++
++ /*
++ * If the initial DRNG is over the reseed threshold, allow a forced
++ * reseed only for the initial DRNG as this is the fallback for all. It
++ * must be kept seeded before all others to keep the LRNG operational.
++ */
++ if (!lrng_drng ||
++ (atomic_read_u32(&lrng_drng_init.requests_since_fully_seeded) >
++ LRNG_DRNG_RESEED_THRESH)) {
++ lrng_drng_init.force_reseed = lrng_drng_init.fully_seeded;
++ pr_debug("force reseed of initial DRNG\n");
++ return;
++ }
++ for_each_online_node(node) {
++ struct lrng_drng *drng = lrng_drng[node];
++
++ if (!drng)
++ continue;
++
++ drng->force_reseed = drng->fully_seeded;
++ pr_debug("force reseed of DRNG on node %u\n", node);
++ }
++ lrng_drng_atomic.force_reseed = lrng_drng_atomic.fully_seeded;
++}
++
++/*
++ * lrng_drng_get() - Get random data out of the DRNG which is reseeded
++ * frequently.
++ *
++ * @outbuf: buffer for storing random data
++ * @outbuflen: length of outbuf
++ *
++ * Return:
++ * * < 0 in error case (DRNG generation or update failed)
++ * * >=0 returning the returned number of bytes
++ */
++static int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen)
++{
++ unsigned long flags = 0;
++ u32 processed = 0;
++
++ if (!outbuf || !outbuflen)
++ return 0;
++
++ outbuflen = min_t(size_t, outbuflen, INT_MAX);
++
++ lrng_drngs_init_cc20(false);
++
++ /* If DRNG operated without proper reseed for too long, block LRNG */
++ BUILD_BUG_ON(LRNG_DRNG_MAX_WITHOUT_RESEED < LRNG_DRNG_RESEED_THRESH);
++ if (atomic_read_u32(&drng->requests_since_fully_seeded) > max_wo_reseed)
++ lrng_unset_fully_seeded(drng);
++
++ while (outbuflen) {
++ u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE);
++ int ret;
++
++ /* All but the atomic DRNG are seeded during generation */
++ if (atomic_dec_and_test(&drng->requests) ||
++ drng->force_reseed ||
++ time_after(jiffies, drng->last_seeded +
++ lrng_drng_reseed_max_time * HZ)) {
++ if (likely(drng != &lrng_drng_atomic)) {
++ if (lrng_pool_trylock()) {
++ drng->force_reseed = true;
++ } else {
++ lrng_drng_seed(drng);
++ lrng_pool_unlock();
++ }
++ }
++ }
++
++ lrng_drng_lock(drng, &flags);
++ ret = drng->crypto_cb->lrng_drng_generate_helper(
++ drng->drng, outbuf + processed, todo);
++ lrng_drng_unlock(drng, &flags);
++ if (ret <= 0) {
++ pr_warn("getting random data from DRNG failed (%d)\n",
++ ret);
++ return -EFAULT;
++ }
++ processed += ret;
++ outbuflen -= ret;
++ }
++
++ return processed;
++}
++
++int lrng_drng_get_atomic(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_drng_get(&lrng_drng_atomic, outbuf, outbuflen);
++}
++
++int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen)
++{
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ struct lrng_drng *drng = &lrng_drng_init;
++ int node = numa_node_id();
++
++ might_sleep();
++
++ if (lrng_drng && lrng_drng[node] && lrng_drng[node]->fully_seeded)
++ drng = lrng_drng[node];
++
++ return lrng_drng_get(drng, outbuf, outbuflen);
++}
++
++/* Reset LRNG such that all existing entropy is gone */
++static void _lrng_reset(struct work_struct *work)
++{
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ unsigned long flags = 0;
++
++ if (!lrng_drng) {
++ lrng_drng_lock(&lrng_drng_init, &flags);
++ lrng_drng_reset(&lrng_drng_init);
++ lrng_drng_unlock(&lrng_drng_init, &flags);
++ } else {
++ u32 node;
++
++ for_each_online_node(node) {
++ struct lrng_drng *drng = lrng_drng[node];
++
++ if (!drng)
++ continue;
++ lrng_drng_lock(drng, &flags);
++ lrng_drng_reset(drng);
++ lrng_drng_unlock(drng, &flags);
++ }
++ }
++ lrng_set_entropy_thresh(LRNG_INIT_ENTROPY_BITS);
++
++ lrng_reset_state();
++}
++
++static DECLARE_WORK(lrng_reset_work, _lrng_reset);
++
++void lrng_reset(void)
++{
++ schedule_work(&lrng_reset_work);
++}
++
++/***************************** Initialize LRNG *******************************/
++
++static int __init lrng_init(void)
++{
++ lrng_drngs_init_cc20(false);
++
++ lrng_drngs_numa_alloc();
++ return 0;
++}
++
++late_initcall(lrng_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
++MODULE_DESCRIPTION("Linux Random Number Generator");
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_archrandom.c linux-5.15-lrng/drivers/char/lrng/lrng_es_archrandom.c
+--- linux-5.15/drivers/char/lrng/lrng_es_archrandom.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_archrandom.c 2021-11-29 12:37:14.483279088 +1100
+@@ -0,0 +1,226 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG Fast Entropy Source: CPU-based entropy source
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <crypto/hash.h>
++#include <linux/lrng.h>
++#include <linux/random.h>
++
++#include "lrng_internal.h"
++
++/*
++ * Estimated entropy of data is a 32th of LRNG_DRNG_SECURITY_STRENGTH_BITS.
++ * As we have no ability to review the implementation of those noise sources,
++ * it is prudent to have a conservative estimate here.
++ */
++#define LRNG_ARCHRANDOM_DEFAULT_STRENGTH CONFIG_LRNG_CPU_ENTROPY_RATE
++#define LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH LRNG_DRNG_SECURITY_STRENGTH_BITS
++#ifdef CONFIG_RANDOM_TRUST_CPU
++static u32 archrandom = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH;
++#else
++static u32 archrandom = LRNG_ARCHRANDOM_DEFAULT_STRENGTH;
++#endif
++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG
++module_param(archrandom, uint, 0644);
++MODULE_PARM_DESC(archrandom, "Entropy in bits of 256 data bits from CPU noise source (e.g. RDSEED)");
++#endif
++
++static int __init lrng_parse_trust_cpu(char *arg)
++{
++ int ret;
++ bool trust_cpu = false;
++
++ ret = kstrtobool(arg, &trust_cpu);
++ if (ret)
++ return ret;
++
++ if (trust_cpu) {
++ archrandom = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH;
++ lrng_pool_add_entropy();
++ } else {
++ archrandom = LRNG_ARCHRANDOM_DEFAULT_STRENGTH;
++ }
++
++ return 0;
++}
++early_param("random.trust_cpu", lrng_parse_trust_cpu);
++
++u32 lrng_archrandom_entropylevel(u32 requested_bits)
++{
++ return lrng_fast_noise_entropylevel(archrandom, requested_bits);
++}
++
++static u32 lrng_get_arch_data(u8 *outbuf, u32 requested_bits)
++{
++ u32 i;
++
++ /* operate on full blocks */
++ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BYTES % sizeof(unsigned long));
++ BUILD_BUG_ON(CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS %
++ sizeof(unsigned long));
++ /* ensure we have aligned buffers */
++ BUILD_BUG_ON(LRNG_KCAPI_ALIGN % sizeof(unsigned long));
++
++ for (i = 0; i < (requested_bits >> 3);
++ i += sizeof(unsigned long)) {
++ if (!arch_get_random_seed_long((unsigned long *)(outbuf + i)) &&
++ !arch_get_random_long((unsigned long *)(outbuf + i))) {
++ archrandom = 0;
++ return 0;
++ }
++ }
++
++ return requested_bits;
++}
++
++static u32 inline lrng_get_arch_data_compress(u8 *outbuf, u32 requested_bits,
++ u32 data_multiplier)
++{
++ SHASH_DESC_ON_STACK(shash, NULL);
++ const struct lrng_crypto_cb *crypto_cb;
++ struct lrng_drng *drng = lrng_drng_init_instance();
++ unsigned long flags;
++ u32 ent_bits = 0, i, partial_bits = 0,
++ full_bits = requested_bits * data_multiplier;
++ void *hash;
++
++ /* Calculate oversampling for SP800-90C */
++ if (lrng_sp80090c_compliant()) {
++ /* Complete amount of bits to be pulled */
++ full_bits += CONFIG_LRNG_OVERSAMPLE_ES_BITS * data_multiplier;
++ /* Full blocks that will be pulled */
++ data_multiplier = full_bits / requested_bits;
++ /* Partial block in bits to be pulled */
++ partial_bits = full_bits - (data_multiplier * requested_bits);
++ }
++
++ lrng_hash_lock(drng, &flags);
++ crypto_cb = drng->crypto_cb;
++ hash = drng->hash;
++
++ if (crypto_cb->lrng_hash_init(shash, hash))
++ goto out;
++
++ /* Hash all data from the CPU entropy source */
++ for (i = 0; i < data_multiplier; i++) {
++ ent_bits = lrng_get_arch_data(outbuf, requested_bits);
++ if (!ent_bits)
++ goto out;
++
++ if (crypto_cb->lrng_hash_update(shash, outbuf, ent_bits >> 3))
++ goto err;
++ }
++
++ /* Hash partial block, if applicable */
++ ent_bits = lrng_get_arch_data(outbuf, partial_bits);
++ if (ent_bits &&
++ crypto_cb->lrng_hash_update(shash, outbuf, ent_bits >> 3))
++ goto err;
++
++ pr_debug("pulled %u bits from CPU RNG entropy source\n", full_bits);
++
++ /* Generate the compressed data to be returned to the caller */
++ ent_bits = crypto_cb->lrng_hash_digestsize(hash) << 3;
++ if (requested_bits < ent_bits) {
++ u8 digest[LRNG_MAX_DIGESTSIZE];
++
++ if (crypto_cb->lrng_hash_final(shash, digest))
++ goto err;
++
++ /* Truncate output data to requested size */
++ memcpy(outbuf, digest, requested_bits >> 3);
++ memzero_explicit(digest, crypto_cb->lrng_hash_digestsize(hash));
++ ent_bits = requested_bits;
++ } else {
++ if (crypto_cb->lrng_hash_final(shash, outbuf))
++ goto err;
++ }
++
++out:
++ crypto_cb->lrng_hash_desc_zero(shash);
++ lrng_hash_unlock(drng, flags);
++ return ent_bits;
++
++err:
++ ent_bits = 0;
++ goto out;
++}
++
++/*
++ * If CPU entropy source requires does not return full entropy, return the
++ * multiplier of how much data shall be sampled from it.
++ */
++static u32 lrng_arch_multiplier(void)
++{
++ static u32 data_multiplier = 0;
++
++ if (data_multiplier > 0) {
++ return data_multiplier;
++ } else {
++ unsigned long v;
++
++ if (IS_ENABLED(CONFIG_X86) && !arch_get_random_seed_long(&v)) {
++ /*
++ * Intel SPEC: pulling 512 blocks from RDRAND ensures
++ * one reseed making it logically equivalent to RDSEED.
++ */
++ data_multiplier = 512;
++ } else if (IS_ENABLED(CONFIG_PPC)) {
++ /*
++ * PowerISA defines DARN to deliver at least 0.5 bits of
++ * entropy per data bit.
++ */
++ data_multiplier = 2;
++ } else {
++ /* CPU provides full entropy */
++ data_multiplier = CONFIG_LRNG_CPU_FULL_ENT_MULTIPLIER;
++ }
++ }
++ return data_multiplier;
++}
++
++/*
++ * lrng_get_arch() - Get CPU entropy source entropy
++ *
++ * @outbuf: buffer to store entropy of size requested_bits
++ *
++ * Return:
++ * * > 0 on success where value provides the added entropy in bits
++ * * 0 if no fast source was available
++ */
++u32 lrng_get_arch(u8 *outbuf, u32 requested_bits)
++{
++ u32 ent_bits, data_multiplier = lrng_arch_multiplier();
++
++ if (data_multiplier <= 1) {
++ ent_bits = lrng_get_arch_data(outbuf, requested_bits);
++ } else {
++ ent_bits = lrng_get_arch_data_compress(outbuf, requested_bits,
++ data_multiplier);
++ }
++
++ ent_bits = lrng_archrandom_entropylevel(ent_bits);
++ pr_debug("obtained %u bits of entropy from CPU RNG entropy source\n",
++ ent_bits);
++ return ent_bits;
++}
++
++void lrng_arch_es_state(unsigned char *buf, size_t buflen)
++{
++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++ u32 data_multiplier = lrng_arch_multiplier();
++
++ /* Assume the lrng_drng_init lock is taken by caller */
++ snprintf(buf, buflen,
++ "CPU ES properties:\n"
++ " Hash for compressing data: %s\n"
++ " Data multiplier: %u\n",
++ (data_multiplier <= 1) ?
++ "N/A" : lrng_drng_init->crypto_cb->lrng_hash_name(),
++ data_multiplier);
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_aux.c linux-5.15-lrng/drivers/char/lrng/lrng_es_aux.c
+--- linux-5.15/drivers/char/lrng/lrng_es_aux.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_aux.c 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,294 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG Slow Entropy Source: Auxiliary entropy pool
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/lrng.h>
++
++#include "lrng_internal.h"
++
++/*
++ * This is the auxiliary pool
++ *
++ * The aux pool array is aligned to 8 bytes to comfort the kernel crypto API
++ * cipher implementations of the hash functions used to read the pool: for some
++ * accelerated implementations, we need an alignment to avoid a realignment
++ * which involves memcpy(). The alignment to 8 bytes should satisfy all crypto
++ * implementations.
++ */
++struct lrng_pool {
++ u8 aux_pool[LRNG_POOL_SIZE]; /* Aux pool: digest state */
++ atomic_t aux_entropy_bits;
++ atomic_t digestsize; /* Digest size of used hash */
++ bool initialized; /* Aux pool initialized? */
++
++ /* Serialize read of entropy pool and update of aux pool */
++ spinlock_t lock;
++};
++
++static struct lrng_pool lrng_pool __aligned(LRNG_KCAPI_ALIGN) = {
++ .aux_entropy_bits = ATOMIC_INIT(0),
++ .digestsize = ATOMIC_INIT(LRNG_ATOMIC_DIGEST_SIZE),
++ .initialized = false,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_pool.lock)
++};
++
++/********************************** Helper ***********************************/
++
++/* Entropy in bits present in aux pool */
++u32 lrng_avail_aux_entropy(void)
++{
++ /* Cap available entropy with max entropy */
++ u32 avail_bits = min_t(u32, lrng_get_digestsize(),
++ atomic_read_u32(&lrng_pool.aux_entropy_bits));
++
++ /* Consider oversampling rate due to aux pool conditioning */
++ return lrng_reduce_by_osr(avail_bits);
++}
++
++/* Set the digest size of the used hash in bytes */
++static inline void lrng_set_digestsize(u32 digestsize)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ u32 ent_bits = atomic_xchg_relaxed(&pool->aux_entropy_bits, 0),
++ old_digestsize = lrng_get_digestsize();
++
++ atomic_set(&lrng_pool.digestsize, digestsize);
++
++ /*
++ * Update the /proc/.../write_wakeup_threshold which must not be larger
++ * than the digest size of the curent conditioning hash.
++ */
++ digestsize <<= 3;
++ lrng_proc_update_max_write_thresh(digestsize);
++ if (lrng_write_wakeup_bits > digestsize)
++ lrng_write_wakeup_bits = digestsize;
++
++ /*
++ * In case the new digest is larger than the old one, cap the available
++ * entropy to the old message digest used to process the existing data.
++ */
++ ent_bits = min_t(u32, ent_bits, old_digestsize);
++ atomic_add(ent_bits, &pool->aux_entropy_bits);
++}
++
++/* Obtain the digest size provided by the used hash in bits */
++u32 lrng_get_digestsize(void)
++{
++ return atomic_read_u32(&lrng_pool.digestsize) << 3;
++}
++
++/* Set entropy content in user-space controllable aux pool */
++void lrng_pool_set_entropy(u32 entropy_bits)
++{
++ atomic_set(&lrng_pool.aux_entropy_bits, entropy_bits);
++}
++
++/*
++ * Replace old with new hash for auxiliary pool handling
++ *
++ * Assumption: the caller must guarantee that the new_cb is available during the
++ * entire operation (e.g. it must hold the write lock against pointer updating).
++ */
++int lrng_aux_switch_hash(const struct lrng_crypto_cb *new_cb, void *new_hash,
++ const struct lrng_crypto_cb *old_cb)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
++ u8 digest[LRNG_MAX_DIGESTSIZE];
++ int ret;
++
++ if (!IS_ENABLED(CONFIG_LRNG_DRNG_SWITCH))
++ return -EOPNOTSUPP;
++
++ if (unlikely(!pool->initialized))
++ return 0;
++
++ /* Get the aux pool hash with old digest ... */
++ ret = old_cb->lrng_hash_final(shash, digest) ?:
++ /* ... re-initialize the hash with the new digest ... */
++ new_cb->lrng_hash_init(shash, new_hash) ?:
++ /*
++ * ... feed the old hash into the new state. We may feed
++ * uninitialized memory into the new state, but this is
++ * considered no issue and even good as we have some more
++ * uncertainty here.
++ */
++ new_cb->lrng_hash_update(shash, digest, sizeof(digest));
++ if (!ret) {
++ lrng_set_digestsize(new_cb->lrng_hash_digestsize(new_hash));
++ pr_debug("Re-initialize aux entropy pool with hash %s\n",
++ new_cb->lrng_hash_name());
++ }
++
++ memzero_explicit(digest, sizeof(digest));
++ return ret;
++}
++
++/* Insert data into auxiliary pool by using the hash update function. */
++static int
++lrng_pool_insert_aux_locked(const u8 *inbuf, u32 inbuflen, u32 entropy_bits)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
++ struct lrng_drng *drng = lrng_drng_init_instance();
++ const struct lrng_crypto_cb *crypto_cb;
++ unsigned long flags;
++ void *hash;
++ int ret;
++
++ entropy_bits = min_t(u32, entropy_bits, inbuflen << 3);
++
++ lrng_hash_lock(drng, &flags);
++
++ crypto_cb = drng->crypto_cb;
++ hash = drng->hash;
++
++ if (unlikely(!pool->initialized)) {
++ ret = crypto_cb->lrng_hash_init(shash, hash);
++ if (ret)
++ goto out;
++ pool->initialized = true;
++ }
++
++ ret = crypto_cb->lrng_hash_update(shash, inbuf, inbuflen);
++ if (ret)
++ goto out;
++
++ /*
++ * Cap the available entropy to the hash output size compliant to
++ * SP800-90B section 3.1.5.1 table 1.
++ */
++ entropy_bits += atomic_read_u32(&pool->aux_entropy_bits);
++ atomic_set(&pool->aux_entropy_bits,
++ min_t(u32, entropy_bits,
++ crypto_cb->lrng_hash_digestsize(hash) << 3));
++
++out:
++ lrng_hash_unlock(drng, flags);
++ return ret;
++}
++
++int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&pool->lock, flags);
++ ret = lrng_pool_insert_aux_locked(inbuf, inbuflen, entropy_bits);
++ spin_unlock_irqrestore(&pool->lock, flags);
++
++ lrng_pool_add_entropy();
++
++ return ret;
++}
++
++/************************* Get data from entropy pool *************************/
++
++/*
++ * Get auxiliary entropy pool and its entropy content for seed buffer.
++ * Caller must hold lrng_pool.pool->lock.
++ * @outbuf: buffer to store data in with size requested_bits
++ * @requested_bits: Requested amount of entropy
++ * @return: amount of entropy in outbuf in bits.
++ */
++static inline u32 lrng_get_aux_pool(u8 *outbuf, u32 requested_bits)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool;
++ struct lrng_drng *drng = lrng_drng_init_instance();
++ const struct lrng_crypto_cb *crypto_cb;
++ unsigned long flags;
++ void *hash;
++ u32 collected_ent_bits, returned_ent_bits, unused_bits = 0,
++ digestsize;
++ u8 aux_output[LRNG_MAX_DIGESTSIZE];
++
++ if (unlikely(!pool->initialized))
++ return 0;
++
++ lrng_hash_lock(drng, &flags);
++
++ crypto_cb = drng->crypto_cb;
++ hash = drng->hash;
++ digestsize = crypto_cb->lrng_hash_digestsize(hash);
++
++ /* Ensure that no more than the size of aux_pool can be requested */
++ requested_bits = min_t(u32, requested_bits, (LRNG_MAX_DIGESTSIZE << 3));
++
++ /* Cap entropy with entropy counter from aux pool and the used digest */
++ collected_ent_bits = min_t(u32, digestsize << 3,
++ atomic_xchg_relaxed(&pool->aux_entropy_bits, 0));
++
++ /* We collected too much entropy and put the overflow back */
++ if (collected_ent_bits > (requested_bits + lrng_compress_osr())) {
++ /* Amount of bits we collected too much */
++ unused_bits = collected_ent_bits - requested_bits;
++ /* Put entropy back */
++ atomic_add(unused_bits, &pool->aux_entropy_bits);
++ /* Fix collected entropy */
++ collected_ent_bits = requested_bits;
++ }
++
++ /* Apply oversampling: discount requested oversampling rate */
++ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits);
++
++ pr_debug("obtained %u bits by collecting %u bits of entropy from aux pool, %u bits of entropy remaining\n",
++ returned_ent_bits, collected_ent_bits, unused_bits);
++
++ /* Get the digest for the aux pool to be returned to the caller ... */
++ if (crypto_cb->lrng_hash_final(shash, aux_output) ||
++ /*
++ * ... and re-initialize the aux state. Do not add the aux pool
++ * digest for backward secrecy as it will be added with the
++ * insertion of the complete seed buffer after it has been filled.
++ */
++ crypto_cb->lrng_hash_init(shash, hash)) {
++ returned_ent_bits = 0;
++ } else {
++ /*
++ * Do not truncate the output size exactly to collected_ent_bits
++ * as the aux pool may contain data that is not credited with
++ * entropy, but we want to use them to stir the DRNG state.
++ */
++ memcpy(outbuf, aux_output, requested_bits >> 3);
++ }
++
++ lrng_hash_unlock(drng, flags);
++ memzero_explicit(aux_output, digestsize);
++ return returned_ent_bits;
++}
++
++void lrng_get_backtrack_aux(struct entropy_buf *entropy_buf, u32 requested_bits)
++{
++ struct lrng_pool *pool = &lrng_pool;
++ unsigned long flags;
++
++ /* Ensure aux pool extraction and backtracking op are atomic */
++ spin_lock_irqsave(&pool->lock, flags);
++
++ entropy_buf->a_bits = lrng_get_aux_pool(entropy_buf->a, requested_bits);
++
++ /* Mix the extracted data back into pool for backtracking resistance */
++ if (lrng_pool_insert_aux_locked((u8 *)entropy_buf,
++ sizeof(struct entropy_buf), 0))
++ pr_warn("Backtracking resistance operation failed\n");
++
++ spin_unlock_irqrestore(&pool->lock, flags);
++}
++
++void lrng_aux_es_state(unsigned char *buf, size_t buflen)
++{
++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++
++ /* Assume the lrng_drng_init lock is taken by caller */
++ snprintf(buf, buflen,
++ "Auxiliary ES properties:\n"
++ " Hash for operating entropy pool: %s\n",
++ lrng_drng_init->crypto_cb->lrng_hash_name());
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_irq.c linux-5.15-lrng/drivers/char/lrng/lrng_es_irq.c
+--- linux-5.15/drivers/char/lrng/lrng_es_irq.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_irq.c 2021-11-29 12:36:57.763279152 +1100
+@@ -0,0 +1,823 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG Slow Entropy Source: Interrupt data collection
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <asm/irq_regs.h>
++#include <asm/ptrace.h>
++#include <crypto/hash.h>
++#include <linux/gcd.h>
++#include <linux/lrng.h>
++#include <linux/random.h>
++
++#include "lrng_internal.h"
++#include "lrng_es_irq.h"
++
++/*
++ * Number of interrupts to be recorded to assume that DRNG security strength
++ * bits of entropy are received.
++ * Note: a value below the DRNG security strength should not be defined as this
++ * may imply the DRNG can never be fully seeded in case other noise
++ * sources are unavailable.
++ */
++#define LRNG_IRQ_ENTROPY_BITS CONFIG_LRNG_IRQ_ENTROPY_RATE
++
++
++/* Number of interrupts required for LRNG_DRNG_SECURITY_STRENGTH_BITS entropy */
++static u32 lrng_irq_entropy_bits = LRNG_IRQ_ENTROPY_BITS;
++/* Is high-resolution timer present? */
++static bool lrng_irq_highres_timer = false;
++
++static u32 irq_entropy __read_mostly = LRNG_IRQ_ENTROPY_BITS;
++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG
++module_param(irq_entropy, uint, 0444);
++MODULE_PARM_DESC(irq_entropy,
++ "How many interrupts must be collected for obtaining 256 bits of entropy\n");
++#endif
++
++/* Per-CPU array holding concatenated entropy events */
++static DEFINE_PER_CPU(u32 [LRNG_DATA_ARRAY_SIZE], lrng_pcpu_array)
++ __aligned(LRNG_KCAPI_ALIGN);
++static DEFINE_PER_CPU(u32, lrng_pcpu_array_ptr) = 0;
++static DEFINE_PER_CPU(atomic_t, lrng_pcpu_array_irqs) = ATOMIC_INIT(0);
++
++/*
++ * The entropy collection is performed by executing the following steps:
++ * 1. fill up the per-CPU array holding the time stamps
++ * 2. once the per-CPU array is full, a compression of the data into
++ * the entropy pool is performed - this happens in interrupt context
++ *
++ * If step 2 is not desired in interrupt context, the following boolean
++ * needs to be set to false. This implies that old entropy data in the
++ * per-CPU array collected since the last DRNG reseed is overwritten with
++ * new entropy data instead of retaining the entropy with the compression
++ * operation.
++ *
++ * Impact on entropy:
++ *
++ * If continuous compression is enabled, the maximum entropy that is collected
++ * per CPU between DRNG reseeds is equal to the digest size of the used hash.
++ *
++ * If continuous compression is disabled, the maximum number of entropy events
++ * that can be collected per CPU is equal to LRNG_DATA_ARRAY_SIZE. This amount
++ * of events is converted into an entropy statement which then represents the
++ * maximum amount of entropy collectible per CPU between DRNG reseeds.
++ */
++static bool lrng_pcpu_continuous_compression __read_mostly =
++ IS_ENABLED(CONFIG_LRNG_ENABLE_CONTINUOUS_COMPRESSION);
++
++#ifdef CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION
++module_param(lrng_pcpu_continuous_compression, bool, 0444);
++MODULE_PARM_DESC(lrng_pcpu_continuous_compression,
++ "Perform entropy compression if per-CPU entropy data array is full\n");
++#endif
++
++/*
++ * Per-CPU entropy pool with compressed entropy event
++ *
++ * The per-CPU entropy pool is defined as the hash state. New data is simply
++ * inserted into the entropy pool by performing a hash update operation.
++ * To read the entropy pool, a hash final must be invoked. However, before
++ * the entropy pool is released again after a hash final, the hash init must
++ * be performed.
++ */
++static DEFINE_PER_CPU(u8 [LRNG_POOL_SIZE], lrng_pcpu_pool)
++ __aligned(LRNG_KCAPI_ALIGN);
++/*
++ * Lock to allow other CPUs to read the pool - as this is only done during
++ * reseed which is infrequent, this lock is hardly contended.
++ */
++static DEFINE_PER_CPU(spinlock_t, lrng_pcpu_lock);
++static DEFINE_PER_CPU(bool, lrng_pcpu_lock_init) = false;
++
++/* Number of time stamps analyzed to calculate a GCD */
++#define LRNG_GCD_WINDOW_SIZE 100
++static u32 lrng_gcd_history[LRNG_GCD_WINDOW_SIZE];
++static atomic_t lrng_gcd_history_ptr = ATOMIC_INIT(-1);
++
++/* The common divisor for all timestamps */
++static u32 lrng_gcd_timer = 0;
++
++static inline bool lrng_gcd_tested(void)
++{
++ return (lrng_gcd_timer != 0);
++}
++
++/* Set the GCD for use in IRQ ES - if 0, the GCD calculation is restarted. */
++static inline void _lrng_gcd_set(u32 running_gcd)
++{
++ lrng_gcd_timer = running_gcd;
++ mb();
++}
++
++static void lrng_gcd_set(u32 running_gcd)
++{
++ if (!lrng_gcd_tested()) {
++ _lrng_gcd_set(running_gcd);
++ pr_debug("Setting GCD to %u\n", running_gcd);
++ }
++}
++
++u32 lrng_gcd_analyze(u32 *history, size_t nelem)
++{
++ u32 running_gcd = 0;
++ size_t i;
++
++ /* Now perform the analysis on the accumulated time data. */
++ for (i = 0; i < nelem; i++) {
++ /*
++ * NOTE: this would be the place to add more analysis on the
++ * appropriateness of the timer like checking the presence
++ * of sufficient variations in the timer.
++ */
++
++ /*
++ * This calculates the gcd of all the time values. that is
++ * gcd(time_1, time_2, ..., time_nelem)
++ *
++ * Some timers increment by a fixed (non-1) amount each step.
++ * This code checks for such increments, and allows the library
++ * to output the number of such changes have occurred.
++ */
++ running_gcd = (u32)gcd(history[i], running_gcd);
++
++ /* Zeroize data */
++ history[i] = 0;
++ }
++
++ return running_gcd;
++}
++
++static void lrng_gcd_add_value(u32 time)
++{
++ u32 ptr = (u32)atomic_inc_return_relaxed(&lrng_gcd_history_ptr);
++
++ if (ptr < LRNG_GCD_WINDOW_SIZE) {
++ lrng_gcd_history[ptr] = time;
++ } else if (ptr == LRNG_GCD_WINDOW_SIZE) {
++ u32 gcd = lrng_gcd_analyze(lrng_gcd_history,
++ LRNG_GCD_WINDOW_SIZE);
++
++ if (!gcd)
++ gcd = 1;
++
++ /*
++ * Ensure that we have variations in the time stamp below the
++ * given value. This is just a safety measure to prevent the GCD
++ * becoming too large.
++ */
++ if (gcd >= 1000) {
++ pr_warn("calculated GCD is larger than expected: %u\n",
++ gcd);
++ gcd = 1000;
++ }
++
++ /* Adjust all deltas by the observed (small) common factor. */
++ lrng_gcd_set(gcd);
++ atomic_set(&lrng_gcd_history_ptr, 0);
++ }
++}
++
++/* Return boolean whether LRNG identified presence of high-resolution timer */
++static bool lrng_pool_highres_timer(void)
++{
++ return lrng_irq_highres_timer;
++}
++
++/* Convert entropy in bits into number of IRQs with the same entropy content. */
++static inline u32 lrng_entropy_to_data(u32 entropy_bits)
++{
++ return ((entropy_bits * lrng_irq_entropy_bits) /
++ LRNG_DRNG_SECURITY_STRENGTH_BITS);
++}
++
++/* Convert number of IRQs into entropy value. */
++static inline u32 lrng_data_to_entropy(u32 irqnum)
++{
++ return ((irqnum * LRNG_DRNG_SECURITY_STRENGTH_BITS) /
++ lrng_irq_entropy_bits);
++}
++
++static inline bool lrng_pcpu_pool_online(int cpu)
++{
++ return per_cpu(lrng_pcpu_lock_init, cpu);
++}
++
++static void lrng_pcpu_check_compression_state(void)
++{
++ /* One pool must hold sufficient entropy for disabled compression */
++ if (!lrng_pcpu_continuous_compression) {
++ u32 max_ent = min_t(u32, lrng_get_digestsize(),
++ lrng_data_to_entropy(LRNG_DATA_NUM_VALUES));
++ if (max_ent < lrng_security_strength()) {
++ pr_warn("Force continuous compression operation to ensure LRNG can hold enough entropy\n");
++ lrng_pcpu_continuous_compression = true;
++ }
++ }
++}
++
++static int __init lrng_init_time_source(void)
++{
++ /* Set a minimum number of interrupts that must be collected */
++ irq_entropy = max_t(u32, LRNG_IRQ_ENTROPY_BITS, irq_entropy);
++
++ if ((random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK) ||
++ (random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK)) {
++ /*
++ * As the highres timer is identified here, previous interrupts
++ * obtained during boot time are treated like a lowres-timer
++ * would have been present.
++ */
++ lrng_irq_highres_timer = true;
++ lrng_irq_entropy_bits = irq_entropy;
++ } else {
++ u32 new_entropy = irq_entropy * LRNG_IRQ_OVERSAMPLING_FACTOR;
++
++ lrng_health_disable();
++ lrng_irq_highres_timer = false;
++ lrng_irq_entropy_bits = (irq_entropy < new_entropy) ?
++ new_entropy : irq_entropy;
++ pr_warn("operating without high-resolution timer and applying IRQ oversampling factor %u\n",
++ LRNG_IRQ_OVERSAMPLING_FACTOR);
++ lrng_pcpu_check_compression_state();
++ }
++ mb();
++
++ return 0;
++}
++core_initcall(lrng_init_time_source);
++
++/*
++ * Reset all per-CPU pools - reset entropy estimator but leave the pool data
++ * that may or may not have entropy unchanged.
++ */
++void lrng_pcpu_reset(void)
++{
++ int cpu;
++
++ /* Trigger GCD calculation anew. */
++ _lrng_gcd_set(0);
++
++ for_each_online_cpu(cpu)
++ atomic_set(per_cpu_ptr(&lrng_pcpu_array_irqs, cpu), 0);
++}
++
++u32 lrng_pcpu_avail_pool_size(void)
++{
++ u32 max_size = 0, max_pool = lrng_get_digestsize();
++ int cpu;
++
++ if (!lrng_pcpu_continuous_compression)
++ max_pool = min_t(u32, max_pool, LRNG_DATA_NUM_VALUES);
++
++ for_each_online_cpu(cpu) {
++ if (lrng_pcpu_pool_online(cpu))
++ max_size += max_pool;
++ }
++
++ return max_size;
++}
++
++/* Return entropy of unused IRQs present in all per-CPU pools. */
++u32 lrng_pcpu_avail_entropy(void)
++{
++ u32 digestsize_irqs, irq = 0;
++ int cpu;
++
++ /* Obtain the cap of maximum numbers of IRQs we count */
++ digestsize_irqs = lrng_entropy_to_data(lrng_get_digestsize());
++ if (!lrng_pcpu_continuous_compression) {
++ /* Cap to max. number of IRQs the array can hold */
++ digestsize_irqs = min_t(u32, digestsize_irqs,
++ LRNG_DATA_NUM_VALUES);
++ }
++
++ for_each_online_cpu(cpu) {
++ if (!lrng_pcpu_pool_online(cpu))
++ continue;
++ irq += min_t(u32, digestsize_irqs,
++ atomic_read_u32(per_cpu_ptr(&lrng_pcpu_array_irqs,
++ cpu)));
++ }
++
++ /* Consider oversampling rate */
++ return lrng_reduce_by_osr(lrng_data_to_entropy(irq));
++}
++
++/*
++ * Trigger a switch of the hash implementation for the per-CPU pool.
++ *
++ * For each per-CPU pool, obtain the message digest with the old hash
++ * implementation, initialize the per-CPU pool again with the new hash
++ * implementation and inject the message digest into the new state.
++ *
++ * Assumption: the caller must guarantee that the new_cb is available during the
++ * entire operation (e.g. it must hold the lock against pointer updating).
++ */
++int lrng_pcpu_switch_hash(int node,
++ const struct lrng_crypto_cb *new_cb, void *new_hash,
++ const struct lrng_crypto_cb *old_cb)
++{
++ u8 digest[LRNG_MAX_DIGESTSIZE];
++ u32 digestsize_irqs, found_irqs;
++ int ret = 0, cpu;
++
++ if (!IS_ENABLED(CONFIG_LRNG_DRNG_SWITCH))
++ return -EOPNOTSUPP;
++
++ for_each_online_cpu(cpu) {
++ struct shash_desc *pcpu_shash;
++
++ /*
++ * Only switch the per-CPU pools for the current node because
++ * the crypto_cb only applies NUMA-node-wide.
++ */
++ if (cpu_to_node(cpu) != node || !lrng_pcpu_pool_online(cpu))
++ continue;
++
++ pcpu_shash = (struct shash_desc *)per_cpu_ptr(lrng_pcpu_pool,
++ cpu);
++
++ digestsize_irqs = old_cb->lrng_hash_digestsize(pcpu_shash);
++ digestsize_irqs = lrng_entropy_to_data(digestsize_irqs << 3);
++
++ if (pcpu_shash->tfm == new_hash)
++ continue;
++
++ /* Get the per-CPU pool hash with old digest ... */
++ ret = old_cb->lrng_hash_final(pcpu_shash, digest) ?:
++ /* ... re-initialize the hash with the new digest ... */
++ new_cb->lrng_hash_init(pcpu_shash, new_hash) ?:
++ /*
++ * ... feed the old hash into the new state. We may feed
++ * uninitialized memory into the new state, but this is
++ * considered no issue and even good as we have some more
++ * uncertainty here.
++ */
++ new_cb->lrng_hash_update(pcpu_shash, digest,
++ sizeof(digest));
++ if (ret)
++ goto out;
++
++ /*
++ * In case the new digest is larger than the old one, cap
++ * the available entropy to the old message digest used to
++ * process the existing data.
++ */
++ found_irqs = atomic_xchg_relaxed(
++ per_cpu_ptr(&lrng_pcpu_array_irqs, cpu), 0);
++ found_irqs = min_t(u32, found_irqs, digestsize_irqs);
++ atomic_add_return_relaxed(found_irqs,
++ per_cpu_ptr(&lrng_pcpu_array_irqs, cpu));
++
++ pr_debug("Re-initialize per-CPU entropy pool for CPU %d on NUMA node %d with hash %s\n",
++ cpu, node, new_cb->lrng_hash_name());
++ }
++
++out:
++ memzero_explicit(digest, sizeof(digest));
++ return ret;
++}
++
++/*
++ * When reading the per-CPU message digest, make sure we use the crypto
++ * callbacks defined for the NUMA node the per-CPU pool is defined for because
++ * the LRNG crypto switch support is only atomic per NUMA node.
++ */
++static inline u32
++lrng_pcpu_pool_hash_one(const struct lrng_crypto_cb *pcpu_crypto_cb,
++ void *pcpu_hash, int cpu, u8 *digest, u32 *digestsize)
++{
++ struct shash_desc *pcpu_shash =
++ (struct shash_desc *)per_cpu_ptr(lrng_pcpu_pool, cpu);
++ spinlock_t *lock = per_cpu_ptr(&lrng_pcpu_lock, cpu);
++ unsigned long flags;
++ u32 digestsize_irqs, found_irqs;
++
++ /* Lock guarding against reading / writing to per-CPU pool */
++ spin_lock_irqsave(lock, flags);
++
++ *digestsize = pcpu_crypto_cb->lrng_hash_digestsize(pcpu_hash);
++ digestsize_irqs = lrng_entropy_to_data(*digestsize << 3);
++
++ /* Obtain entropy statement like for the entropy pool */
++ found_irqs = atomic_xchg_relaxed(
++ per_cpu_ptr(&lrng_pcpu_array_irqs, cpu), 0);
++ /* Cap to maximum amount of data we can hold in hash */
++ found_irqs = min_t(u32, found_irqs, digestsize_irqs);
++
++ /* Cap to maximum amount of data we can hold in array */
++ if (!lrng_pcpu_continuous_compression)
++ found_irqs = min_t(u32, found_irqs, LRNG_DATA_NUM_VALUES);
++
++ /* Store all not-yet compressed data in data array into hash, ... */
++ if (pcpu_crypto_cb->lrng_hash_update(pcpu_shash,
++ (u8 *)per_cpu_ptr(lrng_pcpu_array, cpu),
++ LRNG_DATA_ARRAY_SIZE * sizeof(u32)) ?:
++ /* ... get the per-CPU pool digest, ... */
++ pcpu_crypto_cb->lrng_hash_final(pcpu_shash, digest) ?:
++ /* ... re-initialize the hash, ... */
++ pcpu_crypto_cb->lrng_hash_init(pcpu_shash, pcpu_hash) ?:
++ /* ... feed the old hash into the new state. */
++ pcpu_crypto_cb->lrng_hash_update(pcpu_shash, digest, *digestsize))
++ found_irqs = 0;
++
++ spin_unlock_irqrestore(lock, flags);
++ return found_irqs;
++}
++
++/*
++ * Hash all per-CPU pools and return the digest to be used as seed data for
++ * seeding a DRNG. The caller must guarantee backtracking resistance.
++ * The function will only copy as much data as entropy is available into the
++ * caller-provided output buffer.
++ *
++ * This function handles the translation from the number of received interrupts
++ * into an entropy statement. The conversion depends on LRNG_IRQ_ENTROPY_BITS
++ * which defines how many interrupts must be received to obtain 256 bits of
++ * entropy. With this value, the function lrng_data_to_entropy converts a given
++ * data size (received interrupts, requested amount of data, etc.) into an
++ * entropy statement. lrng_entropy_to_data does the reverse.
++ *
++ * @outbuf: buffer to store data in with size requested_bits
++ * @requested_bits: Requested amount of entropy
++ * @fully_seeded: indicator whether LRNG is fully seeded
++ * @return: amount of entropy in outbuf in bits.
++ */
++u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits, bool fully_seeded)
++{
++ SHASH_DESC_ON_STACK(shash, NULL);
++ const struct lrng_crypto_cb *crypto_cb;
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ struct lrng_drng *drng = lrng_drng_init_instance();
++ u8 digest[LRNG_MAX_DIGESTSIZE];
++ unsigned long flags, flags2;
++ u32 found_irqs, collected_irqs = 0, collected_ent_bits, requested_irqs,
++ returned_ent_bits;
++ int ret, cpu;
++ void *hash;
++
++ /* Lock guarding replacement of per-NUMA hash */
++ lrng_hash_lock(drng, &flags);
++
++ crypto_cb = drng->crypto_cb;
++ hash = drng->hash;
++
++ /* The hash state of filled with all per-CPU pool hashes. */
++ ret = crypto_cb->lrng_hash_init(shash, hash);
++ if (ret)
++ goto err;
++
++ requested_irqs = lrng_entropy_to_data(requested_bits +
++ lrng_compress_osr());
++
++ /*
++ * Harvest entropy from each per-CPU hash state - even though we may
++ * have collected sufficient entropy, we will hash all per-CPU pools.
++ */
++ for_each_online_cpu(cpu) {
++ struct lrng_drng *pcpu_drng = drng;
++ u32 digestsize, pcpu_unused_irqs = 0;
++ int node = cpu_to_node(cpu);
++
++ /* If pool is not online, then no entropy is present. */
++ if (!lrng_pcpu_pool_online(cpu))
++ continue;
++
++ if (lrng_drng && lrng_drng[node])
++ pcpu_drng = lrng_drng[node];
++
++ if (pcpu_drng == drng) {
++ found_irqs = lrng_pcpu_pool_hash_one(crypto_cb, hash,
++ cpu, digest,
++ &digestsize);
++ } else {
++ lrng_hash_lock(pcpu_drng, &flags2);
++ found_irqs =
++ lrng_pcpu_pool_hash_one(pcpu_drng->crypto_cb,
++ pcpu_drng->hash, cpu,
++ digest, &digestsize);
++ lrng_hash_unlock(pcpu_drng, flags2);
++ }
++
++ /* Inject the digest into the state of all per-CPU pools */
++ ret = crypto_cb->lrng_hash_update(shash, digest, digestsize);
++ if (ret)
++ goto err;
++
++ collected_irqs += found_irqs;
++ if (collected_irqs > requested_irqs) {
++ pcpu_unused_irqs = collected_irqs - requested_irqs;
++ atomic_add_return_relaxed(pcpu_unused_irqs,
++ per_cpu_ptr(&lrng_pcpu_array_irqs, cpu));
++ collected_irqs = requested_irqs;
++ }
++ pr_debug("%u interrupts used from entropy pool of CPU %d, %u interrupts remain unused\n",
++ found_irqs - pcpu_unused_irqs, cpu, pcpu_unused_irqs);
++ }
++
++ ret = crypto_cb->lrng_hash_final(shash, digest);
++ if (ret)
++ goto err;
++
++ collected_ent_bits = lrng_data_to_entropy(collected_irqs);
++ /* Cap to maximum entropy that can ever be generated with given hash */
++ collected_ent_bits = min_t(u32, collected_ent_bits,
++ crypto_cb->lrng_hash_digestsize(hash) << 3);
++ /* Apply oversampling: discount requested oversampling rate */
++ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits);
++
++ pr_debug("obtained %u bits by collecting %u bits of entropy from entropy pool noise source\n",
++ returned_ent_bits, collected_ent_bits);
++
++ /*
++ * Truncate to available entropy as implicitly allowed by SP800-90B
++ * section 3.1.5.1.1 table 1 which awards truncated hashes full
++ * entropy.
++ *
++ * During boot time, we read requested_bits data with
++ * returned_ent_bits entropy. In case our conservative entropy
++ * estimate underestimates the available entropy we can transport as
++ * much available entropy as possible.
++ */
++ memcpy(outbuf, digest, fully_seeded ? returned_ent_bits >> 3 :
++ requested_bits >> 3);
++
++out:
++ crypto_cb->lrng_hash_desc_zero(shash);
++ lrng_hash_unlock(drng, flags);
++ memzero_explicit(digest, sizeof(digest));
++ return returned_ent_bits;
++
++err:
++ returned_ent_bits = 0;
++ goto out;
++}
++
++/* Compress the lrng_pcpu_array array into lrng_pcpu_pool */
++static inline void lrng_pcpu_array_compress(void)
++{
++ struct shash_desc *shash =
++ (struct shash_desc *)this_cpu_ptr(lrng_pcpu_pool);
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ struct lrng_drng *drng = lrng_drng_init_instance();
++ const struct lrng_crypto_cb *crypto_cb;
++ spinlock_t *lock = this_cpu_ptr(&lrng_pcpu_lock);
++ unsigned long flags, flags2;
++ int node = numa_node_id();
++ void *hash;
++ bool init = false;
++
++ /* Get NUMA-node local hash instance */
++ if (lrng_drng && lrng_drng[node])
++ drng = lrng_drng[node];
++
++ lrng_hash_lock(drng, &flags);
++ crypto_cb = drng->crypto_cb;
++ hash = drng->hash;
++
++ if (unlikely(!this_cpu_read(lrng_pcpu_lock_init))) {
++ init = true;
++ spin_lock_init(lock);
++ this_cpu_write(lrng_pcpu_lock_init, true);
++ pr_debug("Initializing per-CPU entropy pool for CPU %d on NUMA node %d with hash %s\n",
++ raw_smp_processor_id(), node,
++ crypto_cb->lrng_hash_name());
++ }
++
++ spin_lock_irqsave(lock, flags2);
++
++ if (unlikely(init) && crypto_cb->lrng_hash_init(shash, hash)) {
++ this_cpu_write(lrng_pcpu_lock_init, false);
++ pr_warn("Initialization of hash failed\n");
++ } else if (lrng_pcpu_continuous_compression) {
++ /* Add entire per-CPU data array content into entropy pool. */
++ if (crypto_cb->lrng_hash_update(shash,
++ (u8 *)this_cpu_ptr(lrng_pcpu_array),
++ LRNG_DATA_ARRAY_SIZE * sizeof(u32)))
++ pr_warn_ratelimited("Hashing of entropy data failed\n");
++ }
++
++ spin_unlock_irqrestore(lock, flags2);
++ lrng_hash_unlock(drng, flags);
++}
++
++/* Compress data array into hash */
++static inline void lrng_pcpu_array_to_hash(u32 ptr)
++{
++ u32 *array = this_cpu_ptr(lrng_pcpu_array);
++
++ /*
++ * During boot time the hash operation is triggered more often than
++ * during regular operation.
++ */
++ if (unlikely(!lrng_state_fully_seeded())) {
++ if ((ptr & 31) && (ptr < LRNG_DATA_WORD_MASK))
++ return;
++ } else if (ptr < LRNG_DATA_WORD_MASK) {
++ return;
++ }
++
++ if (lrng_raw_array_entropy_store(*array)) {
++ u32 i;
++
++ /*
++ * If we fed even a part of the array to external analysis, we
++ * mark that the entire array and the per-CPU pool to have no
++ * entropy. This is due to the non-IID property of the data as
++ * we do not fully know whether the existing dependencies
++ * diminish the entropy beyond to what we expect it has.
++ */
++ atomic_set(this_cpu_ptr(&lrng_pcpu_array_irqs), 0);
++
++ for (i = 1; i < LRNG_DATA_ARRAY_SIZE; i++)
++ lrng_raw_array_entropy_store(*(array + i));
++ } else {
++ lrng_pcpu_array_compress();
++ /* Ping pool handler about received entropy */
++ lrng_pool_add_entropy();
++ }
++}
++
++/*
++ * Concatenate full 32 bit word at the end of time array even when current
++ * ptr is not aligned to sizeof(data).
++ */
++static inline void _lrng_pcpu_array_add_u32(u32 data)
++{
++ /* Increment pointer by number of slots taken for input value */
++ u32 pre_ptr, mask, ptr = this_cpu_add_return(lrng_pcpu_array_ptr,
++ LRNG_DATA_SLOTS_PER_UINT);
++ unsigned int pre_array;
++
++ /*
++ * This function injects a unit into the array - guarantee that
++ * array unit size is equal to data type of input data.
++ */
++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS != (sizeof(data) << 3));
++
++ /*
++ * The following logic requires at least two units holding
++ * the data as otherwise the pointer would immediately wrap when
++ * injection an u32 word.
++ */
++ BUILD_BUG_ON(LRNG_DATA_NUM_VALUES <= LRNG_DATA_SLOTS_PER_UINT);
++
++ lrng_pcpu_split_u32(&ptr, &pre_ptr, &mask);
++
++ /* MSB of data go into previous unit */
++ pre_array = lrng_data_idx2array(pre_ptr);
++ /* zeroization of slot to ensure the following OR adds the data */
++ this_cpu_and(lrng_pcpu_array[pre_array], ~(0xffffffff & ~mask));
++ this_cpu_or(lrng_pcpu_array[pre_array], data & ~mask);
++
++ /* Invoke compression as we just filled data array completely */
++ if (unlikely(pre_ptr > ptr))
++ lrng_pcpu_array_to_hash(LRNG_DATA_WORD_MASK);
++
++ /* LSB of data go into current unit */
++ this_cpu_write(lrng_pcpu_array[lrng_data_idx2array(ptr)],
++ data & mask);
++
++ if (likely(pre_ptr <= ptr))
++ lrng_pcpu_array_to_hash(ptr);
++}
++
++/* Concatenate a 32-bit word at the end of the per-CPU array */
++void lrng_pcpu_array_add_u32(u32 data)
++{
++ /*
++ * Disregard entropy-less data without continuous compression to
++ * avoid it overwriting data with entropy when array ptr wraps.
++ */
++ if (lrng_pcpu_continuous_compression)
++ _lrng_pcpu_array_add_u32(data);
++}
++
++/* Concatenate data of max LRNG_DATA_SLOTSIZE_MASK at the end of time array */
++static inline void lrng_pcpu_array_add_slot(u32 data)
++{
++ /* Get slot */
++ u32 ptr = this_cpu_inc_return(lrng_pcpu_array_ptr) &
++ LRNG_DATA_WORD_MASK;
++ unsigned int array = lrng_data_idx2array(ptr);
++ unsigned int slot = lrng_data_idx2slot(ptr);
++
++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS % LRNG_DATA_SLOTSIZE_BITS);
++ /* Ensure consistency of values */
++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS !=
++ sizeof(lrng_pcpu_array[0]) << 3);
++
++ /* zeroization of slot to ensure the following OR adds the data */
++ this_cpu_and(lrng_pcpu_array[array],
++ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK,
++ slot)));
++ /* Store data into slot */
++ this_cpu_or(lrng_pcpu_array[array], lrng_data_slot_val(data, slot));
++
++ lrng_pcpu_array_to_hash(ptr);
++}
++
++static inline void
++lrng_time_process_common(u32 time, void(*add_time)(u32 data))
++{
++ enum lrng_health_res health_test;
++
++ if (lrng_raw_hires_entropy_store(time))
++ return;
++
++ health_test = lrng_health_test(time);
++ if (health_test > lrng_health_fail_use)
++ return;
++
++ if (health_test == lrng_health_pass)
++ atomic_inc_return(this_cpu_ptr(&lrng_pcpu_array_irqs));
++
++ add_time(time);
++}
++
++/*
++ * Batching up of entropy in per-CPU array before injecting into entropy pool.
++ */
++static inline void lrng_time_process(void)
++{
++ u32 now_time = random_get_entropy();
++
++ if (unlikely(!lrng_gcd_tested())) {
++ /* When GCD is unknown, we process the full time stamp */
++ lrng_time_process_common(now_time, _lrng_pcpu_array_add_u32);
++ lrng_gcd_add_value(now_time);
++ } else {
++ /* GCD is known and applied */
++ lrng_time_process_common((now_time / lrng_gcd_timer) &
++ LRNG_DATA_SLOTSIZE_MASK,
++ lrng_pcpu_array_add_slot);
++ }
++
++ lrng_perf_time(now_time);
++}
++
++/* Hot code path - Callback for interrupt handler */
++void add_interrupt_randomness(int irq, int irq_flg)
++{
++ if (lrng_pool_highres_timer()) {
++ lrng_time_process();
++ } else {
++ struct pt_regs *regs = get_irq_regs();
++ static atomic_t reg_idx = ATOMIC_INIT(0);
++ u64 ip;
++ u32 tmp;
++
++ if (regs) {
++ u32 *ptr = (u32 *)regs;
++ int reg_ptr = atomic_add_return_relaxed(1, &reg_idx);
++ size_t n = (sizeof(struct pt_regs) / sizeof(u32));
++
++ ip = instruction_pointer(regs);
++ tmp = *(ptr + (reg_ptr % n));
++ tmp = lrng_raw_regs_entropy_store(tmp) ? 0 : tmp;
++ _lrng_pcpu_array_add_u32(tmp);
++ } else {
++ ip = _RET_IP_;
++ }
++
++ lrng_time_process();
++
++ /*
++ * The XOR operation combining the different values is not
++ * considered to destroy entropy since the entirety of all
++ * processed values delivers the entropy (and not each
++ * value separately of the other values).
++ */
++ tmp = lrng_raw_jiffies_entropy_store(jiffies) ? 0 : jiffies;
++ tmp ^= lrng_raw_irq_entropy_store(irq) ? 0 : irq;
++ tmp ^= lrng_raw_irqflags_entropy_store(irq_flg) ? 0 : irq_flg;
++ tmp ^= lrng_raw_retip_entropy_store(ip) ? 0 : ip;
++ tmp ^= ip >> 32;
++ _lrng_pcpu_array_add_u32(tmp);
++ }
++}
++EXPORT_SYMBOL(add_interrupt_randomness);
++
++void lrng_irq_es_state(unsigned char *buf, size_t buflen)
++{
++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++
++ /* Assume the lrng_drng_init lock is taken by caller */
++ snprintf(buf, buflen,
++ "IRQ ES properties:\n"
++ " Hash for operating entropy pool: %s\n"
++ " per-CPU interrupt collection size: %u\n"
++ " Standards compliance: %s\n"
++ " High-resolution timer: %s\n"
++ " Continuous compression: %s\n",
++ lrng_drng_init->crypto_cb->lrng_hash_name(),
++ LRNG_DATA_NUM_VALUES,
++ lrng_sp80090b_compliant() ? "SP800-90B " : "",
++ lrng_pool_highres_timer() ? "true" : "false",
++ lrng_pcpu_continuous_compression ? "true" : "false");
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_irq.h linux-5.15-lrng/drivers/char/lrng/lrng_es_irq.h
+--- linux-5.15/drivers/char/lrng/lrng_es_irq.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_irq.h 2021-11-29 12:36:57.773279152 +1100
+@@ -0,0 +1,71 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++/*
++ * LRNG Slow Noise Source: Time stamp array handling
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++/*
++ * To limit the impact on the interrupt handling, the LRNG concatenates
++ * entropic LSB parts of the time stamps in a per-CPU array and only
++ * injects them into the entropy pool when the array is full.
++ */
++
++/* Store multiple integers in one u32 */
++#define LRNG_DATA_SLOTSIZE_BITS (8)
++#define LRNG_DATA_SLOTSIZE_MASK ((1 << LRNG_DATA_SLOTSIZE_BITS) - 1)
++#define LRNG_DATA_ARRAY_MEMBER_BITS (4 << 3) /* ((sizeof(u32)) << 3) */
++#define LRNG_DATA_SLOTS_PER_UINT (LRNG_DATA_ARRAY_MEMBER_BITS / \
++ LRNG_DATA_SLOTSIZE_BITS)
++
++/*
++ * Number of time values to store in the array - in small environments
++ * only one atomic_t variable per CPU is used.
++ */
++#define LRNG_DATA_NUM_VALUES (CONFIG_LRNG_COLLECTION_SIZE)
++/* Mask of LSB of time stamp to store */
++#define LRNG_DATA_WORD_MASK (LRNG_DATA_NUM_VALUES - 1)
++
++#define LRNG_DATA_SLOTS_MASK (LRNG_DATA_SLOTS_PER_UINT - 1)
++#define LRNG_DATA_ARRAY_SIZE (LRNG_DATA_NUM_VALUES / \
++ LRNG_DATA_SLOTS_PER_UINT)
++
++/* Starting bit index of slot */
++static inline unsigned int lrng_data_slot2bitindex(unsigned int slot)
++{
++ return (LRNG_DATA_SLOTSIZE_BITS * slot);
++}
++
++/* Convert index into the array index */
++static inline unsigned int lrng_data_idx2array(unsigned int idx)
++{
++ return idx / LRNG_DATA_SLOTS_PER_UINT;
++}
++
++/* Convert index into the slot of a given array index */
++static inline unsigned int lrng_data_idx2slot(unsigned int idx)
++{
++ return idx & LRNG_DATA_SLOTS_MASK;
++}
++
++/* Convert value into slot value */
++static inline unsigned int lrng_data_slot_val(unsigned int val,
++ unsigned int slot)
++{
++ return val << lrng_data_slot2bitindex(slot);
++}
++
++/*
++ * Return the pointers for the previous and current units to inject a u32 into.
++ * Also return the mask which the u32 word is to be processed.
++ */
++static inline void lrng_pcpu_split_u32(u32 *ptr, u32 *pre_ptr, u32 *mask)
++{
++ /* ptr to previous unit */
++ *pre_ptr = (*ptr - LRNG_DATA_SLOTS_PER_UINT) & LRNG_DATA_WORD_MASK;
++ *ptr &= LRNG_DATA_WORD_MASK;
++
++ /* mask to split data into the two parts for the two units */
++ *mask = ((1 << (*pre_ptr & (LRNG_DATA_SLOTS_PER_UINT - 1)) *
++ LRNG_DATA_SLOTSIZE_BITS)) - 1;
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_jent.c linux-5.15-lrng/drivers/char/lrng/lrng_es_jent.c
+--- linux-5.15/drivers/char/lrng/lrng_es_jent.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_jent.c 2021-11-29 12:38:04.443278898 +1100
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG Fast Entropy Source: Jitter RNG
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <crypto/internal/jitterentropy.h>
++
++#include "lrng_internal.h"
++
++/*
++ * Estimated entropy of data is a 16th of LRNG_DRNG_SECURITY_STRENGTH_BITS.
++ * Albeit a full entropy assessment is provided for the noise source indicating
++ * that it provides high entropy rates and considering that it deactivates
++ * when it detects insufficient hardware, the chosen under estimation of
++ * entropy is considered to be acceptable to all reviewers.
++ */
++static u32 jitterrng = CONFIG_LRNG_JENT_ENTROPY_RATE;
++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG
++module_param(jitterrng, uint, 0644);
++MODULE_PARM_DESC(jitterrng, "Entropy in bits of 256 data bits from Jitter RNG noise source");
++#endif
++
++static bool lrng_jent_initialized = false;
++static struct rand_data *lrng_jent_state;
++
++static int __init lrng_jent_initialize(void)
++{
++ /* Initialize the Jitter RNG after the clocksources are initialized. */
++ if (jent_entropy_init() ||
++ (lrng_jent_state = jent_entropy_collector_alloc(1, 0)) == NULL) {
++ jitterrng = 0;
++ pr_info("Jitter RNG unusable on current system\n");
++ return 0;
++ }
++ lrng_jent_initialized = true;
++ lrng_pool_add_entropy();
++ pr_debug("Jitter RNG working on current system\n");
++
++ return 0;
++}
++device_initcall(lrng_jent_initialize);
++
++/*
++ * lrng_get_jent() - Get Jitter RNG entropy
++ *
++ * @outbuf: buffer to store entropy
++ * @outbuflen: length of buffer
++ *
++ * Return:
++ * * > 0 on success where value provides the added entropy in bits
++ * * 0 if no fast source was available
++ */
++u32 lrng_get_jent(u8 *outbuf, u32 requested_bits)
++{
++ int ret;
++ u32 ent_bits = lrng_jent_entropylevel(requested_bits);
++ unsigned long flags;
++ static DEFINE_SPINLOCK(lrng_jent_lock);
++
++ spin_lock_irqsave(&lrng_jent_lock, flags);
++
++ if (!lrng_jent_initialized) {
++ spin_unlock_irqrestore(&lrng_jent_lock, flags);
++ return 0;
++ }
++
++ ret = jent_read_entropy(lrng_jent_state, outbuf, requested_bits >> 3);
++ spin_unlock_irqrestore(&lrng_jent_lock, flags);
++
++ if (ret) {
++ pr_debug("Jitter RNG failed with %d\n", ret);
++ return 0;
++ }
++
++ pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n",
++ ent_bits);
++
++ return ent_bits;
++}
++
++u32 lrng_jent_entropylevel(u32 requested_bits)
++{
++ return lrng_fast_noise_entropylevel((lrng_jent_initialized) ?
++ jitterrng : 0, requested_bits);
++}
++
++void lrng_jent_es_state(unsigned char *buf, size_t buflen)
++{
++ snprintf(buf, buflen,
++ "JitterRNG ES properties:\n"
++ " Enabled: %s\n", lrng_jent_initialized ? "true" : "false");
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_es_mgr.c linux-5.15-lrng/drivers/char/lrng/lrng_es_mgr.c
+--- linux-5.15/drivers/char/lrng/lrng_es_mgr.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_es_mgr.c 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,373 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG Entropy sources management
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <asm/irq_regs.h>
++#include <linux/percpu.h>
++#include <linux/random.h>
++#include <linux/utsname.h>
++#include <linux/workqueue.h>
++
++#include "lrng_internal.h"
++
++struct lrng_state {
++ bool can_invalidate; /* Can invalidate batched entropy? */
++ bool perform_seedwork; /* Can seed work be performed? */
++ bool lrng_operational; /* Is DRNG operational? */
++ bool lrng_fully_seeded; /* Is DRNG fully seeded? */
++ bool lrng_min_seeded; /* Is DRNG minimally seeded? */
++ bool all_online_numa_node_seeded;/* All NUMA DRNGs seeded? */
++
++ /*
++ * To ensure that external entropy providers cannot dominate the
++ * internal noise sources but yet cannot be dominated by internal
++ * noise sources, the following booleans are intended to allow
++ * external to provide seed once when a DRNG reseed occurs. This
++ * triggering of external noise source is performed even when the
++ * entropy pool has sufficient entropy.
++ */
++ bool lrng_seed_hw; /* Allow HW to provide seed */
++ bool lrng_seed_user; /* Allow user space to provide seed */
++
++ atomic_t boot_entropy_thresh; /* Reseed threshold */
++ atomic_t reseed_in_progress; /* Flag for on executing reseed */
++ struct work_struct lrng_seed_work; /* (re)seed work queue */
++};
++
++static struct lrng_state lrng_state = {
++ false, false, false, false, false, false, true, true,
++ .boot_entropy_thresh = ATOMIC_INIT(LRNG_INIT_ENTROPY_BITS),
++ .reseed_in_progress = ATOMIC_INIT(0),
++};
++
++/********************************** Helper ***********************************/
++
++/* External entropy provider is allowed to provide seed data */
++bool lrng_state_exseed_allow(enum lrng_external_noise_source source)
++{
++ if (source == lrng_noise_source_hw)
++ return lrng_state.lrng_seed_hw;
++ return lrng_state.lrng_seed_user;
++}
++
++/* Enable / disable external entropy provider to furnish seed */
++void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type)
++{
++ if (source == lrng_noise_source_hw)
++ lrng_state.lrng_seed_hw = type;
++ else
++ lrng_state.lrng_seed_user = type;
++}
++
++static inline void lrng_state_exseed_allow_all(void)
++{
++ lrng_state_exseed_set(lrng_noise_source_hw, true);
++ lrng_state_exseed_set(lrng_noise_source_user, true);
++}
++
++/*
++ * Reading of the LRNG pool is only allowed by one caller. The reading is
++ * only performed to (re)seed DRNGs. Thus, if this "lock" is already taken,
++ * the reseeding operation is in progress. The caller is not intended to wait
++ * but continue with its other operation.
++ */
++int lrng_pool_trylock(void)
++{
++ return atomic_cmpxchg(&lrng_state.reseed_in_progress, 0, 1);
++}
++
++void lrng_pool_unlock(void)
++{
++ atomic_set(&lrng_state.reseed_in_progress, 0);
++}
++
++/* Set new entropy threshold for reseeding during boot */
++void lrng_set_entropy_thresh(u32 new_entropy_bits)
++{
++ atomic_set(&lrng_state.boot_entropy_thresh, new_entropy_bits);
++}
++
++/*
++ * Reset LRNG state - the entropy counters are reset, but the data that may
++ * or may not have entropy remains in the pools as this data will not hurt.
++ */
++void lrng_reset_state(void)
++{
++ lrng_pool_set_entropy(0);
++ lrng_pcpu_reset();
++ lrng_state.lrng_operational = false;
++ lrng_state.lrng_fully_seeded = false;
++ lrng_state.lrng_min_seeded = false;
++ lrng_state.all_online_numa_node_seeded = false;
++ pr_debug("reset LRNG\n");
++}
++
++/* Set flag that all DRNGs are fully seeded */
++void lrng_pool_all_numa_nodes_seeded(bool set)
++{
++ lrng_state.all_online_numa_node_seeded = set;
++}
++
++/* Return boolean whether LRNG reached minimally seed level */
++bool lrng_state_min_seeded(void)
++{
++ return lrng_state.lrng_min_seeded;
++}
++
++/* Return boolean whether LRNG reached fully seed level */
++bool lrng_state_fully_seeded(void)
++{
++ return lrng_state.lrng_fully_seeded;
++}
++
++/* Return boolean whether LRNG is considered fully operational */
++bool lrng_state_operational(void)
++{
++ return lrng_state.lrng_operational;
++}
++
++/* Policy to check whether entropy buffer contains full seeded entropy */
++bool lrng_fully_seeded(bool fully_seeded, struct entropy_buf *eb)
++{
++ return ((eb->a_bits + eb->b_bits + eb->c_bits + eb->d_bits) >=
++ lrng_get_seed_entropy_osr(fully_seeded));
++}
++
++/* Mark one DRNG as not fully seeded */
++void lrng_unset_fully_seeded(struct lrng_drng *drng)
++{
++ drng->fully_seeded = false;
++ lrng_pool_all_numa_nodes_seeded(false);
++
++ /*
++ * The init DRNG instance must always be fully seeded as this instance
++ * is the fall-back if any of the per-NUMA node DRNG instances is
++ * insufficiently seeded. Thus, we mark the entire LRNG as
++ * non-operational if the initial DRNG becomes not fully seeded.
++ */
++ if (drng == lrng_drng_init_instance() && lrng_state_operational()) {
++ pr_debug("LRNG set to non-operational\n");
++ lrng_state.lrng_operational = false;
++ lrng_state.lrng_fully_seeded = false;
++
++ /* If sufficient entropy is available, reseed now. */
++ lrng_pool_add_entropy();
++ }
++}
++
++/* Policy to enable LRNG operational mode */
++static inline void lrng_set_operational(u32 external_es)
++{
++ /* LRNG is operational if the initial DRNG is fully seeded ... */
++ if (lrng_state.lrng_fully_seeded &&
++ /* ... and either internal ES SP800-90B startup is complete ... */
++ (lrng_sp80090b_startup_complete() ||
++ /* ... or the external ES provided sufficient entropy. */
++ (lrng_get_seed_entropy_osr(lrng_state_fully_seeded()) <=
++ external_es))) {
++ lrng_state.lrng_operational = true;
++ lrng_process_ready_list();
++ lrng_init_wakeup();
++ pr_info("LRNG fully operational\n");
++ }
++}
++
++/* Available entropy in the entire LRNG considering all entropy sources */
++u32 lrng_avail_entropy(void)
++{
++ u32 ent_thresh = lrng_security_strength();
++
++ /*
++ * Apply oversampling during initialization according to SP800-90C as
++ * we request a larger buffer from the ES.
++ */
++ if (lrng_sp80090c_compliant() &&
++ !lrng_state.all_online_numa_node_seeded)
++ ent_thresh += CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS;
++
++ return lrng_pcpu_avail_entropy() + lrng_avail_aux_entropy() +
++ lrng_archrandom_entropylevel(ent_thresh) +
++ lrng_jent_entropylevel(ent_thresh);
++}
++
++/*
++ * lrng_init_ops() - Set seed stages of LRNG
++ *
++ * Set the slow noise source reseed trigger threshold. The initial threshold
++ * is set to the minimum data size that can be read from the pool: a word. Upon
++ * reaching this value, the next seed threshold of 128 bits is set followed
++ * by 256 bits.
++ *
++ * @eb: buffer containing the size of entropy currently injected into DRNG
++ */
++void lrng_init_ops(struct entropy_buf *eb)
++{
++ struct lrng_state *state = &lrng_state;
++ u32 requested_bits, seed_bits, external_es;
++
++ if (state->lrng_operational)
++ return;
++
++ requested_bits = lrng_get_seed_entropy_osr(
++ state->all_online_numa_node_seeded);
++
++ /*
++ * Entropy provided by external entropy sources - if they provide
++ * the requested amount of entropy, unblock the interface.
++ */
++ external_es = eb->a_bits + eb->c_bits + eb->d_bits;
++ seed_bits = external_es + eb->b_bits;
++
++ /* DRNG is seeded with full security strength */
++ if (state->lrng_fully_seeded) {
++ lrng_set_operational(external_es);
++ lrng_set_entropy_thresh(requested_bits);
++ } else if (lrng_fully_seeded(state->all_online_numa_node_seeded, eb)) {
++ if (state->can_invalidate)
++ invalidate_batched_entropy();
++
++ state->lrng_fully_seeded = true;
++ lrng_set_operational(external_es);
++ state->lrng_min_seeded = true;
++ pr_info("LRNG fully seeded with %u bits of entropy\n",
++ seed_bits);
++ lrng_set_entropy_thresh(requested_bits);
++ } else if (!state->lrng_min_seeded) {
++
++ /* DRNG is seeded with at least 128 bits of entropy */
++ if (seed_bits >= LRNG_MIN_SEED_ENTROPY_BITS) {
++ if (state->can_invalidate)
++ invalidate_batched_entropy();
++
++ state->lrng_min_seeded = true;
++ pr_info("LRNG minimally seeded with %u bits of entropy\n",
++ seed_bits);
++ lrng_set_entropy_thresh(requested_bits);
++ lrng_init_wakeup();
++
++ /* DRNG is seeded with at least LRNG_INIT_ENTROPY_BITS bits */
++ } else if (seed_bits >= LRNG_INIT_ENTROPY_BITS) {
++ pr_info("LRNG initial entropy level %u bits of entropy\n",
++ seed_bits);
++ lrng_set_entropy_thresh(LRNG_MIN_SEED_ENTROPY_BITS);
++ }
++ }
++}
++
++int __init rand_initialize(void)
++{
++ struct seed {
++ ktime_t time;
++ unsigned long data[(LRNG_MAX_DIGESTSIZE /
++ sizeof(unsigned long))];
++ struct new_utsname utsname;
++ } seed __aligned(LRNG_KCAPI_ALIGN);
++ unsigned int i;
++
++ BUILD_BUG_ON(LRNG_MAX_DIGESTSIZE % sizeof(unsigned long));
++
++ seed.time = ktime_get_real();
++
++ for (i = 0; i < ARRAY_SIZE(seed.data); i++) {
++ if (!arch_get_random_seed_long_early(&(seed.data[i])) &&
++ !arch_get_random_long_early(&seed.data[i]))
++ seed.data[i] = random_get_entropy();
++ }
++ memcpy(&seed.utsname, utsname(), sizeof(*(utsname())));
++
++ lrng_pool_insert_aux((u8 *)&seed, sizeof(seed), 0);
++ memzero_explicit(&seed, sizeof(seed));
++
++ /* Initialize the seed work queue */
++ INIT_WORK(&lrng_state.lrng_seed_work, lrng_drng_seed_work);
++ lrng_state.perform_seedwork = true;
++
++ lrng_drngs_init_cc20(true);
++ invalidate_batched_entropy();
++
++ lrng_state.can_invalidate = true;
++
++ return 0;
++}
++
++/* Interface requesting a reseed of the DRNG */
++void lrng_pool_add_entropy(void)
++{
++ /*
++ * Once all DRNGs are fully seeded, the interrupt noise
++ * sources will not trigger any reseeding any more.
++ */
++ if (likely(lrng_state.all_online_numa_node_seeded))
++ return;
++
++ /* Only try to reseed if the DRNG is alive. */
++ if (!lrng_get_available())
++ return;
++
++ /* Only trigger the DRNG reseed if we have collected entropy. */
++ if (lrng_avail_entropy() <
++ atomic_read_u32(&lrng_state.boot_entropy_thresh))
++ return;
++
++ /* Ensure that the seeding only occurs once at any given time. */
++ if (lrng_pool_trylock())
++ return;
++
++ /* Seed the DRNG with any available noise. */
++ if (lrng_state.perform_seedwork)
++ schedule_work(&lrng_state.lrng_seed_work);
++ else
++ lrng_drng_seed_work(NULL);
++}
++
++/* Fill the seed buffer with data from the noise sources */
++void lrng_fill_seed_buffer(struct entropy_buf *entropy_buf, u32 requested_bits)
++{
++ struct lrng_state *state = &lrng_state;
++ u32 req_ent = lrng_sp80090c_compliant() ?
++ lrng_security_strength() : LRNG_MIN_SEED_ENTROPY_BITS;
++
++ /* Guarantee that requested bits is a multiple of bytes */
++ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BITS % 8);
++
++ /* always reseed the DRNG with the current time stamp */
++ entropy_buf->now = random_get_entropy();
++
++ /*
++ * Require at least 128 bits of entropy for any reseed. If the LRNG is
++ * operated SP800-90C compliant we want to comply with SP800-90A section
++ * 9.2 mandating that DRNG is reseeded with the security strength.
++ */
++ if (state->lrng_fully_seeded && (lrng_avail_entropy() < req_ent)) {
++ entropy_buf->a_bits = entropy_buf->b_bits = 0;
++ entropy_buf->c_bits = entropy_buf->d_bits = 0;
++ goto wakeup;
++ }
++
++ /* Concatenate the output of the entropy sources. */
++ entropy_buf->b_bits = lrng_pcpu_pool_hash(entropy_buf->b,
++ requested_bits,
++ state->lrng_fully_seeded);
++ entropy_buf->c_bits = lrng_get_arch(entropy_buf->c, requested_bits);
++ entropy_buf->d_bits = lrng_get_jent(entropy_buf->d, requested_bits);
++ lrng_get_backtrack_aux(entropy_buf, requested_bits);
++
++ /* allow external entropy provider to provide seed */
++ lrng_state_exseed_allow_all();
++
++wakeup:
++ /*
++ * Shall we wake up user space writers? This location covers
++ * ensures that the user space provider does not dominate the internal
++ * noise sources since in case the first call of this function finds
++ * sufficient entropy in the entropy pool, it will not trigger the
++ * wakeup. This implies that when the next /dev/urandom read happens,
++ * the entropy pool is drained.
++ */
++ lrng_writer_wakeup();
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_health.c linux-5.15-lrng/drivers/char/lrng/lrng_health.c
+--- linux-5.15/drivers/char/lrng/lrng_health.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_health.c 2021-11-29 12:38:11.793278870 +1100
+@@ -0,0 +1,410 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Linux Random Number Generator (LRNG) Health Testing
++ *
++ * Copyright (C) 2019 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/fips.h>
++#include <linux/module.h>
++
++#include "lrng_internal.h"
++
++/* Stuck Test */
++struct lrng_stuck_test {
++ u32 last_time; /* Stuck test: time of previous IRQ */
++ u32 last_delta; /* Stuck test: delta of previous IRQ */
++ u32 last_delta2; /* Stuck test: 2. time derivation of prev IRQ */
++};
++
++/* Repetition Count Test */
++struct lrng_rct {
++ atomic_t rct_count; /* Number of stuck values */
++};
++
++/* Adaptive Proportion Test */
++struct lrng_apt {
++ /* Data window size */
++#define LRNG_APT_WINDOW_SIZE 512
++ /* LSB of time stamp to process */
++#define LRNG_APT_LSB 16
++#define LRNG_APT_WORD_MASK (LRNG_APT_LSB - 1)
++ atomic_t apt_count; /* APT counter */
++ atomic_t apt_base; /* APT base reference */
++
++ atomic_t apt_trigger;
++ bool apt_base_set; /* Is APT base set? */
++};
++
++/* The health test code must operate lock-less */
++struct lrng_health {
++ struct lrng_rct rct;
++ struct lrng_apt apt;
++
++ bool health_test_enabled;
++
++ /* SP800-90B startup health tests */
++#define LRNG_SP80090B_STARTUP_SAMPLES 1024
++#define LRNG_SP80090B_STARTUP_BLOCKS ((LRNG_SP80090B_STARTUP_SAMPLES + \
++ LRNG_APT_WINDOW_SIZE - 1) / \
++ LRNG_APT_WINDOW_SIZE)
++ bool sp80090b_startup_done;
++ atomic_t sp80090b_startup_blocks;
++};
++
++static struct lrng_health lrng_health = {
++ .rct.rct_count = ATOMIC_INIT(0),
++
++ .apt.apt_count = ATOMIC_INIT(0),
++ .apt.apt_base = ATOMIC_INIT(-1),
++ .apt.apt_trigger = ATOMIC_INIT(LRNG_APT_WINDOW_SIZE),
++ .apt.apt_base_set = false,
++
++ .health_test_enabled = true,
++
++ .sp80090b_startup_blocks = ATOMIC_INIT(LRNG_SP80090B_STARTUP_BLOCKS),
++ .sp80090b_startup_done = false,
++};
++
++static DEFINE_PER_CPU(struct lrng_stuck_test, lrng_stuck_test);
++
++static inline bool lrng_sp80090b_health_requested(void)
++{
++ /* Health tests are only requested in FIPS mode */
++ return fips_enabled;
++}
++
++static inline bool lrng_sp80090b_health_enabled(void)
++{
++ struct lrng_health *health = &lrng_health;
++
++ return lrng_sp80090b_health_requested() && health->health_test_enabled;
++}
++
++/***************************************************************************
++ * SP800-90B Compliance
++ *
++ * If the Linux-RNG is booted into FIPS mode, the following interfaces
++ * provide an SP800-90B compliant noise source:
++ *
++ * * /dev/random
++ * * getrandom(2)
++ * * get_random_bytes when using it in conjunction with
++ * add_random_ready_callback
++ *
++ * All other interfaces, including /dev/urandom or get_random_bytes without
++ * the add_random_ready_callback cannot claim to use an SP800-90B compliant
++ * noise source.
++ ***************************************************************************/
++
++/*
++ * Perform SP800-90B startup testing
++ */
++static inline void lrng_sp80090b_startup(struct lrng_health *health)
++{
++ if (!health->sp80090b_startup_done &&
++ atomic_dec_and_test(&health->sp80090b_startup_blocks)) {
++ struct entropy_buf eb;
++
++ health->sp80090b_startup_done = true;
++ pr_info("SP800-90B startup health tests completed\n");
++ memset(&eb, 0, sizeof(eb));
++ lrng_init_ops(&eb);
++
++ /*
++ * Force a reseed of DRNGs to ensure they are seeded with
++ * entropy that passed the SP800-90B health tests.
++ * As the DRNG always will reseed before generating
++ * random numbers, it does not need a reseed trigger.
++ */
++ lrng_drng_force_reseed();
++ }
++}
++
++/*
++ * Handle failure of SP800-90B startup testing
++ */
++static inline void lrng_sp80090b_startup_failure(struct lrng_health *health)
++{
++ /* Reset of LRNG and its entropy - NOTE: we are in atomic context */
++ lrng_reset();
++
++ /*
++ * Reset the SP800-90B startup test.
++ *
++ * NOTE SP800-90B section 4.3 bullet 4 does not specify what
++ * exactly is to be done in case of failure! Thus, we do what
++ * makes sense, i.e. restarting the health test and thus gating
++ * the output function of /dev/random and getrandom(2).
++ */
++ atomic_set(&health->sp80090b_startup_blocks,
++ LRNG_SP80090B_STARTUP_BLOCKS);
++}
++
++/*
++ * Handle failure of SP800-90B runtime testing
++ */
++static inline void lrng_sp80090b_runtime_failure(struct lrng_health *health)
++{
++ lrng_sp80090b_startup_failure(health);
++ health->sp80090b_startup_done = false;
++}
++
++static inline void lrng_sp80090b_failure(struct lrng_health *health)
++{
++ if (health->sp80090b_startup_done) {
++ pr_err("SP800-90B runtime health test failure - invalidating all existing entropy and initiate SP800-90B startup\n");
++ lrng_sp80090b_runtime_failure(health);
++ } else {
++ pr_err("SP800-90B startup test failure - resetting\n");
++ lrng_sp80090b_startup_failure(health);
++ }
++}
++
++/*
++ * Is the SP800-90B startup testing complete?
++ *
++ * This function is called by the LRNG to determine whether to unblock
++ * a certain user interface. Therefore, only the potentially blocking
++ * user interfaces are considered SP800-90B compliant.
++ */
++bool lrng_sp80090b_startup_complete(void)
++{
++ struct lrng_health *health = &lrng_health;
++
++ return (lrng_sp80090b_health_enabled()) ? health->sp80090b_startup_done:
++ true;
++}
++
++bool lrng_sp80090b_compliant(void)
++{
++ struct lrng_health *health = &lrng_health;
++
++ return lrng_sp80090b_health_enabled() && health->sp80090b_startup_done;
++}
++
++/***************************************************************************
++ * Adaptive Proportion Test
++ *
++ * This test complies with SP800-90B section 4.4.2.
++ ***************************************************************************/
++
++/*
++ * Reset the APT counter
++ *
++ * @health [in] Reference to health state
++ */
++static inline void lrng_apt_reset(struct lrng_health *health,
++ unsigned int time_masked)
++{
++ struct lrng_apt *apt = &health->apt;
++
++ pr_debug("APT value %d for base %d\n",
++ atomic_read(&apt->apt_count), atomic_read(&apt->apt_base));
++
++ /* Reset APT */
++ atomic_set(&apt->apt_count, 0);
++ atomic_set(&apt->apt_base, time_masked);
++}
++
++static inline void lrng_apt_restart(struct lrng_health *health)
++{
++ struct lrng_apt *apt = &health->apt;
++
++ atomic_set(&apt->apt_trigger, LRNG_APT_WINDOW_SIZE);
++}
++
++/*
++ * Insert a new entropy event into APT
++ *
++ * This function does is void as it does not decide about the fate of a time
++ * stamp. An APT failure can only happen at the same time of a stuck test
++ * failure. Thus, the stuck failure will already decide how the time stamp
++ * is handled.
++ *
++ * @health [in] Reference to health state
++ * @now_time [in] Time stamp to process
++ */
++static inline void lrng_apt_insert(struct lrng_health *health,
++ unsigned int now_time)
++{
++ struct lrng_apt *apt = &health->apt;
++
++ if (!lrng_sp80090b_health_requested())
++ return;
++
++ now_time &= LRNG_APT_WORD_MASK;
++
++ /* Initialization of APT */
++ if (!apt->apt_base_set) {
++ atomic_set(&apt->apt_base, now_time);
++ apt->apt_base_set = true;
++ return;
++ }
++
++ if (now_time == (unsigned int)atomic_read(&apt->apt_base)) {
++ u32 apt_val = (u32)atomic_inc_return_relaxed(&apt->apt_count);
++
++ if (apt_val >= CONFIG_LRNG_APT_CUTOFF)
++ lrng_sp80090b_failure(health);
++ }
++
++ if (atomic_dec_and_test(&apt->apt_trigger)) {
++ lrng_apt_restart(health);
++ lrng_apt_reset(health, now_time);
++ lrng_sp80090b_startup(health);
++ }
++}
++
++/***************************************************************************
++ * Repetition Count Test
++ *
++ * The LRNG uses an enhanced version of the Repetition Count Test
++ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical
++ * back-to-back values, the input to the RCT is the counting of the stuck
++ * values while filling the entropy pool.
++ *
++ * The RCT is applied with an alpha of 2^-30 compliant to FIPS 140-2 IG 9.8.
++ *
++ * During the counting operation, the LRNG always calculates the RCT
++ * cut-off value of C. If that value exceeds the allowed cut-off value,
++ * the LRNG will invalidate all entropy for the entropy pool which implies
++ * that no data can be extracted from the entropy pool unless new entropy
++ * is received.
++ ***************************************************************************/
++
++/*
++ * Hot code path - Insert data for Repetition Count Test
++ *
++ * @health: Reference to health information
++ * @stuck: Decision of stuck test
++ */
++static inline void lrng_rct(struct lrng_health *health, int stuck)
++{
++ struct lrng_rct *rct = &health->rct;
++
++ if (!lrng_sp80090b_health_requested())
++ return;
++
++ if (stuck) {
++ u32 rct_count = atomic_add_return_relaxed(1, &rct->rct_count);
++
++ pr_debug("RCT count: %u\n", rct_count);
++
++ /*
++ * The cutoff value is based on the following consideration:
++ * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8.
++ * In addition, we imply an entropy value H of 1 bit as this
++ * is the minimum entropy required to provide full entropy.
++ *
++ * Note, rct_count (which equals to value B in the
++ * pseudo code of SP800-90B section 4.4.1) starts with zero.
++ * Hence we need to subtract one from the cutoff value as
++ * calculated following SP800-90B.
++ */
++ if (rct_count >= CONFIG_LRNG_RCT_CUTOFF) {
++ atomic_set(&rct->rct_count, 0);
++
++ /*
++ * APT must start anew as we consider all previously
++ * recorded data to contain no entropy.
++ */
++ lrng_apt_restart(health);
++
++ lrng_sp80090b_failure(health);
++ }
++ } else {
++ atomic_set(&rct->rct_count, 0);
++ }
++}
++
++/***************************************************************************
++ * Stuck Test
++ *
++ * Checking the:
++ * 1st derivative of the event occurrence (time delta)
++ * 2nd derivative of the event occurrence (delta of time deltas)
++ * 3rd derivative of the event occurrence (delta of delta of time deltas)
++ *
++ * All values must always be non-zero. The stuck test is only valid disabled if
++ * high-resolution time stamps are identified after initialization.
++ ***************************************************************************/
++
++static inline u32 lrng_delta(u32 prev, u32 next)
++{
++ /*
++ * Note that this (unsigned) subtraction does yield the correct value
++ * in the wraparound-case, i.e. when next < prev.
++ */
++ return (next - prev);
++}
++
++/*
++ * Hot code path
++ *
++ * @health: Reference to health information
++ * @now: Event time
++ * @return: 0 event occurrence not stuck (good time stamp)
++ * != 0 event occurrence stuck (reject time stamp)
++ */
++static inline int lrng_irq_stuck(struct lrng_stuck_test *stuck, u32 now_time)
++{
++ u32 delta = lrng_delta(stuck->last_time, now_time);
++ u32 delta2 = lrng_delta(stuck->last_delta, delta);
++ u32 delta3 = lrng_delta(stuck->last_delta2, delta2);
++
++ stuck->last_time = now_time;
++ stuck->last_delta = delta;
++ stuck->last_delta2 = delta2;
++
++ if (!delta || !delta2 || !delta3)
++ return 1;
++
++ return 0;
++}
++
++/***************************************************************************
++ * Health test interfaces
++ ***************************************************************************/
++
++/*
++ * Disable all health tests
++ */
++void lrng_health_disable(void)
++{
++ struct lrng_health *health = &lrng_health;
++
++ health->health_test_enabled = false;
++
++ if (lrng_sp80090b_health_requested())
++ pr_warn("SP800-90B compliance requested but the Linux RNG is NOT SP800-90B compliant\n");
++}
++
++/*
++ * Hot code path - Perform health test on time stamp received from an event
++ *
++ * @now_time Time stamp
++ */
++enum lrng_health_res lrng_health_test(u32 now_time)
++{
++ struct lrng_health *health = &lrng_health;
++ struct lrng_stuck_test *stuck_test = this_cpu_ptr(&lrng_stuck_test);
++ int stuck;
++
++ if (!health->health_test_enabled)
++ return lrng_health_pass;
++
++ lrng_apt_insert(health, now_time);
++
++ stuck = lrng_irq_stuck(stuck_test, now_time);
++ lrng_rct(health, stuck);
++ if (stuck) {
++ /* SP800-90B disallows using a failing health test time stamp */
++ return lrng_sp80090b_health_requested() ?
++ lrng_health_fail_drop : lrng_health_fail_use;
++ }
++
++ return lrng_health_pass;
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_interfaces.c linux-5.15-lrng/drivers/char/lrng/lrng_interfaces.c
+--- linux-5.15/drivers/char/lrng/lrng_interfaces.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_interfaces.c 2021-11-29 12:37:03.083279132 +1100
+@@ -0,0 +1,654 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG User and kernel space interfaces
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/freezer.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/hw_random.h>
++#include <linux/kthread.h>
++#include <linux/poll.h>
++#include <linux/preempt.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++#include <linux/syscalls.h>
++#include <linux/timex.h>
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/random.h>
++
++#include "lrng_internal.h"
++
++/*
++ * 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.
++ */
++u32 lrng_write_wakeup_bits = (LRNG_WRITE_WAKEUP_ENTROPY << 3);
++
++static LIST_HEAD(lrng_ready_list);
++static DEFINE_SPINLOCK(lrng_ready_list_lock);
++
++static DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait);
++static DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait);
++static struct fasync_struct *fasync;
++
++/********************************** Helper ***********************************/
++
++/* Is the DRNG seed level too low? */
++static inline bool lrng_need_entropy(void)
++{
++ return (lrng_avail_aux_entropy() < lrng_write_wakeup_bits);
++}
++
++void lrng_writer_wakeup(void)
++{
++ if (lrng_need_entropy() && wq_has_sleeper(&lrng_write_wait)) {
++ wake_up_interruptible(&lrng_write_wait);
++ kill_fasync(&fasync, SIGIO, POLL_OUT);
++ }
++}
++
++void lrng_init_wakeup(void)
++{
++ wake_up_all(&lrng_init_wait);
++ kill_fasync(&fasync, SIGIO, POLL_IN);
++}
++
++/**
++ * lrng_process_ready_list() - Ping all kernel internal callers waiting until
++ * the DRNG is completely initialized to inform that the DRNG reached that
++ * seed level.
++ *
++ * When the SP800-90B testing is enabled, the ping only happens if the SP800-90B
++ * startup health tests are completed. This implies that kernel internal
++ * callers always have an SP800-90B compliant noise source when being
++ * pinged.
++ */
++void lrng_process_ready_list(void)
++{
++ unsigned long flags;
++ struct random_ready_callback *rdy, *tmp;
++
++ if (!lrng_state_operational())
++ return;
++
++ spin_lock_irqsave(&lrng_ready_list_lock, flags);
++ list_for_each_entry_safe(rdy, tmp, &lrng_ready_list, list) {
++ struct module *owner = rdy->owner;
++
++ list_del_init(&rdy->list);
++ rdy->func(rdy);
++ module_put(owner);
++ }
++ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
++}
++
++void lrng_debug_report_seedlevel(const char *name)
++{
++#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
++ static void *previous = NULL;
++ void *caller = (void *) _RET_IP_;
++
++ if (READ_ONCE(previous) == caller)
++ return;
++
++ if (!lrng_state_min_seeded())
++ pr_notice("%pS %s called without reaching minimally seeded level (available entropy %u)\n",
++ caller, name, lrng_avail_entropy());
++
++ WRITE_ONCE(previous, caller);
++#endif
++}
++
++/************************ LRNG kernel input interfaces ************************/
++
++/*
++ * add_hwgenerator_randomness() - 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.
++ *
++ * @buffer: buffer holding the entropic data from HW noise sources to be used to
++ * insert into entropy pool.
++ * @count: length of buffer
++ * @entropy_bits: amount of entropy in buffer (value is in bits)
++ */
++void add_hwgenerator_randomness(const char *buffer, size_t count,
++ size_t entropy_bits)
++{
++ /*
++ * Suspend writing if we are fully loaded with entropy.
++ * We'll be woken up again once below lrng_write_wakeup_thresh,
++ * or when the calling thread is about to terminate.
++ */
++ wait_event_interruptible(lrng_write_wait,
++ lrng_need_entropy() ||
++ lrng_state_exseed_allow(lrng_noise_source_hw) ||
++ kthread_should_stop());
++ lrng_state_exseed_set(lrng_noise_source_hw, false);
++ lrng_pool_insert_aux(buffer, count, entropy_bits);
++}
++EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
++
++/*
++ * add_bootloader_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.
++ *
++ * @buf: buffer holding the entropic data from HW noise sources to be used to
++ * insert into entropy pool.
++ * @size: length of buffer
++ */
++void add_bootloader_randomness(const void *buf, unsigned int size)
++{
++ lrng_pool_insert_aux(buf, size,
++ IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER) ?
++ size * 8 : 0);
++}
++EXPORT_SYMBOL_GPL(add_bootloader_randomness);
++
++/*
++ * Callback for HID layer -- use the HID event values to stir the entropy pool
++ */
++void add_input_randomness(unsigned int type, unsigned int code,
++ unsigned int value)
++{
++ static unsigned char last_value;
++
++ /* ignore autorepeat and the like */
++ if (value == last_value)
++ return;
++
++ last_value = value;
++
++ lrng_pcpu_array_add_u32((type << 4) ^ code ^ (code >> 4) ^ value);
++}
++EXPORT_SYMBOL_GPL(add_input_randomness);
++
++/*
++ * add_device_randomness() - Add device- or boot-specific data to the entropy
++ * 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.
++ *
++ * @buf: buffer holding the entropic data from HW noise sources to be used to
++ * insert into entropy pool.
++ * @size: length of buffer
++ */
++void add_device_randomness(const void *buf, unsigned int size)
++{
++ lrng_pool_insert_aux((u8 *)buf, size, 0);
++}
++EXPORT_SYMBOL(add_device_randomness);
++
++#ifdef CONFIG_BLOCK
++void rand_initialize_disk(struct gendisk *disk) { }
++void add_disk_randomness(struct gendisk *disk) { }
++EXPORT_SYMBOL(add_disk_randomness);
++#endif
++
++#ifndef CONFIG_LRNG_IRQ
++void add_interrupt_randomness(int irq, int irq_flg) { }
++EXPORT_SYMBOL(add_interrupt_randomness);
++#endif
++
++/*
++ * del_random_ready_callback() - Delete a previously registered readiness
++ * callback function.
++ *
++ * @rdy: callback definition that was registered initially
++ */
++void del_random_ready_callback(struct random_ready_callback *rdy)
++{
++ unsigned long flags;
++ struct module *owner = NULL;
++
++ spin_lock_irqsave(&lrng_ready_list_lock, flags);
++ if (!list_empty(&rdy->list)) {
++ list_del_init(&rdy->list);
++ owner = rdy->owner;
++ }
++ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
++
++ module_put(owner);
++}
++EXPORT_SYMBOL(del_random_ready_callback);
++
++/*
++ * add_random_ready_callback() - Add a callback function that will be invoked
++ * when the DRNG is fully initialized and seeded.
++ *
++ * @rdy: callback definition to be invoked when the LRNG is seeded
++ *
++ * Return:
++ * * 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 (likely(lrng_state_operational()))
++ return err;
++
++ owner = rdy->owner;
++ if (!try_module_get(owner))
++ return -ENOENT;
++
++ spin_lock_irqsave(&lrng_ready_list_lock, flags);
++ if (lrng_state_operational())
++ goto out;
++
++ owner = NULL;
++
++ list_add(&rdy->list, &lrng_ready_list);
++ err = 0;
++
++out:
++ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
++
++ module_put(owner);
++
++ return err;
++}
++EXPORT_SYMBOL(add_random_ready_callback);
++
++/*********************** LRNG kernel output interfaces ************************/
++
++/*
++ * get_random_bytes() - Provider of cryptographic strong random numbers for
++ * kernel-internal usage.
++ *
++ * This function is appropriate for all in-kernel use cases. However,
++ * it will always use the ChaCha20 DRNG.
++ *
++ * @buf: buffer to store the random bytes
++ * @nbytes: size of the buffer
++ */
++void get_random_bytes(void *buf, int nbytes)
++{
++ lrng_drng_get_atomic((u8 *)buf, (u32)nbytes);
++ lrng_debug_report_seedlevel("get_random_bytes");
++}
++EXPORT_SYMBOL(get_random_bytes);
++
++/*
++ * get_random_bytes_full() - Provider of cryptographic strong random numbers
++ * for kernel-internal usage.
++ *
++ * This function is appropriate only for non-atomic use cases as this
++ * function may sleep. Though, it provides access to the full functionality
++ * of LRNG including the switchable DRNG support, that may support other
++ * DRNGs such as the SP800-90A DRBG.
++ *
++ * @buf: buffer to store the random bytes
++ * @nbytes: size of the buffer
++ */
++void get_random_bytes_full(void *buf, int nbytes)
++{
++ lrng_drng_get_sleep((u8 *)buf, (u32)nbytes);
++ lrng_debug_report_seedlevel("get_random_bytes_full");
++}
++EXPORT_SYMBOL(get_random_bytes_full);
++
++/*
++ * wait_for_random_bytes() - Wait for the LRNG 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.
++ *
++ * Return:
++ * * 0 if the LRNG has been seeded.
++ * * -ERESTARTSYS if the function was interrupted by a signal.
++ */
++int wait_for_random_bytes(void)
++{
++ if (likely(lrng_state_min_seeded()))
++ return 0;
++ return wait_event_interruptible(lrng_init_wait,
++ lrng_state_min_seeded());
++}
++EXPORT_SYMBOL(wait_for_random_bytes);
++
++/*
++ * get_random_bytes_arch() - 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.
++ *
++ * @buf: buffer allocated by caller to store the random data in
++ * @nbytes: length of outbuf
++ *
++ * Return: number of bytes filled in.
++ */
++int __must_check get_random_bytes_arch(void *buf, int nbytes)
++{
++ u8 *p = buf;
++
++ while (nbytes) {
++ unsigned long v;
++ int chunk = min_t(int, nbytes, sizeof(unsigned long));
++
++ if (!arch_get_random_long(&v))
++ break;
++
++ memcpy(p, &v, chunk);
++ p += chunk;
++ nbytes -= chunk;
++ }
++
++ if (nbytes)
++ lrng_drng_get_atomic((u8 *)p, (u32)nbytes);
++
++ return nbytes;
++}
++EXPORT_SYMBOL(get_random_bytes_arch);
++
++/*
++ * Returns whether or not the LRNG has been seeded.
++ *
++ * Returns: true if the urandom pool has been seeded.
++ * false if the urandom pool has not been seeded.
++ */
++bool rng_is_initialized(void)
++{
++ return lrng_state_operational();
++}
++EXPORT_SYMBOL(rng_is_initialized);
++
++/************************ LRNG user output interfaces *************************/
++
++static ssize_t lrng_read_common(char __user *buf, size_t nbytes)
++{
++ ssize_t ret = 0;
++ u8 tmpbuf[LRNG_DRNG_BLOCKSIZE] __aligned(LRNG_KCAPI_ALIGN);
++ u8 *tmp_large = NULL, *tmp = tmpbuf;
++ u32 tmplen = sizeof(tmpbuf);
++
++ if (nbytes == 0)
++ return 0;
++
++ /*
++ * Satisfy large read requests -- as the common case are smaller
++ * request sizes, such as 16 or 32 bytes, avoid a kmalloc overhead for
++ * those by using the stack variable of tmpbuf.
++ */
++ if (!CONFIG_BASE_SMALL && (nbytes > sizeof(tmpbuf))) {
++ tmplen = min_t(u32, nbytes, LRNG_DRNG_MAX_REQSIZE);
++ tmp_large = kmalloc(tmplen + LRNG_KCAPI_ALIGN, GFP_KERNEL);
++ if (!tmp_large)
++ tmplen = sizeof(tmpbuf);
++ else
++ tmp = PTR_ALIGN(tmp_large, LRNG_KCAPI_ALIGN);
++ }
++
++ while (nbytes) {
++ u32 todo = min_t(u32, nbytes, tmplen);
++ int rc = 0;
++
++ /* Reschedule if we received a large request. */
++ if ((tmp_large) && need_resched()) {
++ if (signal_pending(current)) {
++ if (ret == 0)
++ ret = -ERESTARTSYS;
++ break;
++ }
++ schedule();
++ }
++
++ rc = lrng_drng_get_sleep(tmp, todo);
++ if (rc <= 0) {
++ if (rc < 0)
++ ret = rc;
++ break;
++ }
++ if (copy_to_user(buf, tmp, rc)) {
++ ret = -EFAULT;
++ break;
++ }
++
++ nbytes -= rc;
++ buf += rc;
++ ret += rc;
++ }
++
++ /* Wipe data just returned from memory */
++ if (tmp_large)
++ kfree_sensitive(tmp_large);
++ else
++ memzero_explicit(tmpbuf, sizeof(tmpbuf));
++
++ return ret;
++}
++
++static ssize_t
++lrng_read_common_block(int nonblock, char __user *buf, size_t nbytes)
++{
++ if (nbytes == 0)
++ return 0;
++
++ if (unlikely(!lrng_state_operational())) {
++ int ret;
++
++ if (nonblock)
++ return -EAGAIN;
++
++ ret = wait_event_interruptible(lrng_init_wait,
++ lrng_state_operational());
++ if (unlikely(ret))
++ return ret;
++ }
++
++ return lrng_read_common(buf, nbytes);
++}
++
++static ssize_t lrng_drng_read_block(struct file *file, char __user *buf,
++ size_t nbytes, loff_t *ppos)
++{
++ return lrng_read_common_block(file->f_flags & O_NONBLOCK, buf, nbytes);
++}
++
++static __poll_t lrng_random_poll(struct file *file, poll_table *wait)
++{
++ __poll_t mask;
++
++ poll_wait(file, &lrng_init_wait, wait);
++ poll_wait(file, &lrng_write_wait, wait);
++ mask = 0;
++ if (lrng_state_operational())
++ mask |= EPOLLIN | EPOLLRDNORM;
++ if (lrng_need_entropy() ||
++ lrng_state_exseed_allow(lrng_noise_source_user)) {
++ lrng_state_exseed_set(lrng_noise_source_user, false);
++ mask |= EPOLLOUT | EPOLLWRNORM;
++ }
++ return mask;
++}
++
++static ssize_t lrng_drng_write_common(const char __user *buffer, size_t count,
++ u32 entropy_bits)
++{
++ ssize_t ret = 0;
++ u8 buf[64] __aligned(LRNG_KCAPI_ALIGN);
++ const char __user *p = buffer;
++ u32 orig_entropy_bits = entropy_bits;
++
++ if (!lrng_get_available())
++ return -EAGAIN;
++
++ count = min_t(size_t, count, INT_MAX);
++ while (count > 0) {
++ size_t bytes = min_t(size_t, count, sizeof(buf));
++ u32 ent = min_t(u32, bytes<<3, entropy_bits);
++
++ if (copy_from_user(&buf, p, bytes))
++ return -EFAULT;
++ /* Inject data into entropy pool */
++ lrng_pool_insert_aux(buf, bytes, ent);
++
++ count -= bytes;
++ p += bytes;
++ ret += bytes;
++ entropy_bits -= ent;
++
++ cond_resched();
++ }
++
++ /* Force reseed of DRNG during next data request. */
++ if (!orig_entropy_bits)
++ lrng_drng_force_reseed();
++
++ return ret;
++}
++
++static ssize_t lrng_drng_read(struct file *file, char __user *buf,
++ size_t nbytes, loff_t *ppos)
++{
++ if (!lrng_state_min_seeded())
++ pr_notice_ratelimited("%s - use of insufficiently seeded DRNG (%zu bytes read)\n",
++ current->comm, nbytes);
++ else if (!lrng_state_operational())
++ pr_debug_ratelimited("%s - use of not fully seeded DRNG (%zu bytes read)\n",
++ current->comm, nbytes);
++
++ return lrng_read_common(buf, nbytes);
++}
++
++static ssize_t lrng_drng_write(struct file *file, const char __user *buffer,
++ size_t count, loff_t *ppos)
++{
++ return lrng_drng_write_common(buffer, count, 0);
++}
++
++static long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
++{
++ u32 digestsize_bits;
++ int size, ent_count_bits;
++ int __user *p = (int __user *)arg;
++
++ switch (cmd) {
++ case RNDGETENTCNT:
++ ent_count_bits = lrng_avail_entropy();
++ if (put_user(ent_count_bits, p))
++ return -EFAULT;
++ return 0;
++ case RNDADDTOENTCNT:
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ if (get_user(ent_count_bits, p))
++ return -EFAULT;
++ ent_count_bits = (int)lrng_avail_aux_entropy() + ent_count_bits;
++ if (ent_count_bits < 0)
++ ent_count_bits = 0;
++ digestsize_bits = lrng_get_digestsize();
++ if (ent_count_bits > digestsize_bits)
++ ent_count_bits = digestsize_bits;
++ lrng_pool_set_entropy(ent_count_bits);
++ return 0;
++ case RNDADDENTROPY:
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ if (get_user(ent_count_bits, p++))
++ return -EFAULT;
++ if (ent_count_bits < 0)
++ return -EINVAL;
++ if (get_user(size, p++))
++ return -EFAULT;
++ if (size < 0)
++ return -EINVAL;
++ /* there cannot be more entropy than data */
++ ent_count_bits = min(ent_count_bits, size<<3);
++ return lrng_drng_write_common((const char __user *)p, size,
++ ent_count_bits);
++ case RNDZAPENTCNT:
++ case RNDCLEARPOOL:
++ /* Clear the entropy pool counter. */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ lrng_pool_set_entropy(0);
++ return 0;
++ case RNDRESEEDCRNG:
++ /*
++ * We leave the capability check here since it is present
++ * in the upstream's RNG implementation. Yet, user space
++ * can trigger a reseed as easy as writing into /dev/random
++ * or /dev/urandom where no privilege is needed.
++ */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ /* Force a reseed of all DRNGs */
++ lrng_drng_force_reseed();
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int lrng_fasync(int fd, struct file *filp, int on)
++{
++ return fasync_helper(fd, filp, on, &fasync);
++}
++
++const struct file_operations random_fops = {
++ .read = lrng_drng_read_block,
++ .write = lrng_drng_write,
++ .poll = lrng_random_poll,
++ .unlocked_ioctl = lrng_ioctl,
++ .compat_ioctl = compat_ptr_ioctl,
++ .fasync = lrng_fasync,
++ .llseek = noop_llseek,
++};
++
++const struct file_operations urandom_fops = {
++ .read = lrng_drng_read,
++ .write = lrng_drng_write,
++ .unlocked_ioctl = lrng_ioctl,
++ .compat_ioctl = compat_ptr_ioctl,
++ .fasync = lrng_fasync,
++ .llseek = noop_llseek,
++};
++
++SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
++ unsigned int, flags)
++{
++ if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE))
++ return -EINVAL;
++
++ /*
++ * 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 (count > INT_MAX)
++ count = INT_MAX;
++
++ if (flags & GRND_INSECURE)
++ return lrng_drng_read(NULL, buf, count, NULL);
++
++ return lrng_read_common_block(flags & GRND_NONBLOCK, buf, count);
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_internal.h linux-5.15-lrng/drivers/char/lrng/lrng_internal.h
+--- linux-5.15/drivers/char/lrng/lrng_internal.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_internal.h 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,485 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++/*
++ * Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#ifndef _LRNG_INTERNAL_H
++#define _LRNG_INTERNAL_H
++
++#include <crypto/sha1.h>
++#include <crypto/sha2.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/rwlock.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++/*************************** General LRNG parameter ***************************/
++
++/* Security strength of LRNG -- this must match DRNG security strength */
++#define LRNG_DRNG_SECURITY_STRENGTH_BYTES 32
++#define LRNG_DRNG_SECURITY_STRENGTH_BITS (LRNG_DRNG_SECURITY_STRENGTH_BYTES * 8)
++#define LRNG_DRNG_BLOCKSIZE 64 /* Maximum of DRNG block sizes */
++#define LRNG_DRNG_INIT_SEED_SIZE_BITS (LRNG_DRNG_SECURITY_STRENGTH_BITS + \
++ CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS)
++#define LRNG_DRNG_INIT_SEED_SIZE_BYTES (LRNG_DRNG_INIT_SEED_SIZE_BITS >> 3)
++
++/*
++ * SP800-90A defines a maximum request size of 1<<16 bytes. The given value is
++ * considered a safer margin.
++ *
++ * This value is allowed to be changed.
++ */
++#define LRNG_DRNG_MAX_REQSIZE (1<<12)
++
++/*
++ * SP800-90A defines a maximum number of requests between reseeds of 2^48.
++ * The given value is considered a much safer margin, balancing requests for
++ * frequent reseeds with the need to conserve entropy. This value MUST NOT be
++ * larger than INT_MAX because it is used in an atomic_t.
++ *
++ * This value is allowed to be changed.
++ */
++#define LRNG_DRNG_RESEED_THRESH (1<<20)
++
++/*
++ * Maximum DRNG generation operations without reseed having full entropy
++ * This value defines the absolute maximum value of DRNG generation operations
++ * without a reseed holding full entropy. LRNG_DRNG_RESEED_THRESH is the
++ * threshold when a new reseed is attempted. But it is possible that this fails
++ * to deliver full entropy. In this case the DRNG will continue to provide data
++ * even though it was not reseeded with full entropy. To avoid in the extreme
++ * case that no reseed is performed for too long, this threshold is enforced.
++ * If that absolute low value is reached, the LRNG is marked as not operational.
++ *
++ * This value is allowed to be changed.
++ */
++#define LRNG_DRNG_MAX_WITHOUT_RESEED (1<<30)
++
++/*
++ * Min required seed entropy is 128 bits covering the minimum entropy
++ * requirement of SP800-131A and the German BSI's TR02102.
++ *
++ * This value is allowed to be changed.
++ */
++#define LRNG_FULL_SEED_ENTROPY_BITS LRNG_DRNG_SECURITY_STRENGTH_BITS
++#define LRNG_MIN_SEED_ENTROPY_BITS 128
++#define LRNG_INIT_ENTROPY_BITS 32
++
++/*
++ * Wakeup value
++ *
++ * This value is allowed to be changed but must not be larger than the
++ * digest size of the hash operation used update the aux_pool.
++ */
++#ifdef CONFIG_CRYPTO_LIB_SHA256
++# define LRNG_ATOMIC_DIGEST_SIZE SHA256_DIGEST_SIZE
++#else
++# define LRNG_ATOMIC_DIGEST_SIZE SHA1_DIGEST_SIZE
++#endif
++#define LRNG_WRITE_WAKEUP_ENTROPY LRNG_ATOMIC_DIGEST_SIZE
++
++/*
++ * If the switching support is configured, we must provide support up to
++ * the largest digest size. Without switching support, we know it is only
++ * the built-in digest size.
++ */
++#ifdef CONFIG_LRNG_DRNG_SWITCH
++# define LRNG_MAX_DIGESTSIZE 64
++#else
++# define LRNG_MAX_DIGESTSIZE LRNG_ATOMIC_DIGEST_SIZE
++#endif
++
++/*
++ * Oversampling factor of IRQ events to obtain
++ * LRNG_DRNG_SECURITY_STRENGTH_BYTES. This factor is used when a
++ * high-resolution time stamp is not available. In this case, jiffies and
++ * register contents are used to fill the entropy pool. These noise sources
++ * are much less entropic than the high-resolution timer. The entropy content
++ * is the entropy content assumed with LRNG_IRQ_ENTROPY_BITS divided by
++ * LRNG_IRQ_OVERSAMPLING_FACTOR.
++ *
++ * This value is allowed to be changed.
++ */
++#define LRNG_IRQ_OVERSAMPLING_FACTOR 10
++
++/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */
++#define LRNG_KCAPI_ALIGN ARCH_KMALLOC_MINALIGN
++
++/*
++ * This definition must provide a buffer that is equal to SHASH_DESC_ON_STACK
++ * as it will be casted into a struct shash_desc.
++ */
++#define LRNG_POOL_SIZE (sizeof(struct shash_desc) + HASH_MAX_DESCSIZE)
++
++/************************ Default DRNG implementation *************************/
++
++extern struct chacha20_state chacha20;
++extern const struct lrng_crypto_cb lrng_cc20_crypto_cb;
++void lrng_cc20_init_state(struct chacha20_state *state);
++
++/********************************** /proc *************************************/
++
++#ifdef CONFIG_SYSCTL
++void lrng_pool_inc_numa_node(void);
++void lrng_proc_update_max_write_thresh(u32 new_digestsize);
++#else
++static inline void lrng_pool_inc_numa_node(void) { }
++static inline void lrng_proc_update_max_write_thresh(u32 new_digestsize) { }
++#endif
++
++/****************************** LRNG interfaces *******************************/
++
++extern u32 lrng_write_wakeup_bits;
++extern int lrng_drng_reseed_max_time;
++
++void lrng_writer_wakeup(void);
++void lrng_init_wakeup(void);
++void lrng_debug_report_seedlevel(const char *name);
++void lrng_process_ready_list(void);
++
++/* External interface to use of the switchable DRBG inside the kernel */
++void get_random_bytes_full(void *buf, int nbytes);
++
++/************************* Jitter RNG Entropy Source **************************/
++
++#ifdef CONFIG_LRNG_JENT
++u32 lrng_get_jent(u8 *outbuf, u32 requested_bits);
++u32 lrng_jent_entropylevel(u32 requested_bits);
++void lrng_jent_es_state(unsigned char *buf, size_t buflen);
++#else /* CONFIG_LRNG_JENT */
++static inline u32 lrng_get_jent(u8 *outbuf, u32 requested_bits) { return 0; }
++static inline u32 lrng_jent_entropylevel(u32 requested_bits) { return 0; }
++static inline void lrng_jent_es_state(unsigned char *buf, size_t buflen) { }
++#endif /* CONFIG_LRNG_JENT */
++
++/************************** CPU-based Entropy Source **************************/
++
++static inline u32 lrng_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits)
++{
++ /* Obtain entropy statement */
++ ent_bits = ent_bits * requested_bits / LRNG_DRNG_SECURITY_STRENGTH_BITS;
++ /* Cap entropy to buffer size in bits */
++ ent_bits = min_t(u32, ent_bits, requested_bits);
++ return ent_bits;
++}
++
++#ifdef CONFIG_LRNG_CPU
++u32 lrng_get_arch(u8 *outbuf, u32 requested_bits);
++u32 lrng_archrandom_entropylevel(u32 requested_bits);
++void lrng_arch_es_state(unsigned char *buf, size_t buflen);
++#else /* CONFIG_LRNG_CPU */
++static inline u32 lrng_get_arch(u8 *outbuf, u32 requested_bits) { return 0; }
++static inline u32 lrng_archrandom_entropylevel(u32 requested_bits) { return 0; }
++static inline void lrng_arch_es_state(unsigned char *buf, size_t buflen) { }
++#endif /* CONFIG_LRNG_CPU */
++
++/************************** Interrupt Entropy Source **************************/
++
++#ifdef CONFIG_LRNG_IRQ
++void lrng_pcpu_reset(void);
++u32 lrng_pcpu_avail_pool_size(void);
++u32 lrng_pcpu_avail_entropy(void);
++int lrng_pcpu_switch_hash(int node,
++ const struct lrng_crypto_cb *new_cb, void *new_hash,
++ const struct lrng_crypto_cb *old_cb);
++u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits, bool fully_seeded);
++void lrng_pcpu_array_add_u32(u32 data);
++u32 lrng_gcd_analyze(u32 *history, size_t nelem);
++void lrng_irq_es_state(unsigned char *buf, size_t buflen);
++#else /* CONFIG_LRNG_IRQ */
++static inline void lrng_pcpu_reset(void) { }
++static inline u32 lrng_pcpu_avail_pool_size(void) { return 0; }
++static inline u32 lrng_pcpu_avail_entropy(void) { return 0; }
++static inline int lrng_pcpu_switch_hash(int node,
++ const struct lrng_crypto_cb *new_cb, void *new_hash,
++ const struct lrng_crypto_cb *old_cb)
++{
++ return 0;
++}
++static inline u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits,
++ bool fully_seeded)
++{
++ return 0;
++}
++static inline void lrng_pcpu_array_add_u32(u32 data) { }
++static inline void lrng_irq_es_state(unsigned char *buf, size_t buflen) { }
++#endif /* CONFIG_LRNG_IRQ */
++
++/****************************** DRNG processing *******************************/
++
++/* DRNG state handle */
++struct lrng_drng {
++ void *drng; /* DRNG handle */
++ void *hash; /* Hash handle */
++ const struct lrng_crypto_cb *crypto_cb; /* Crypto callbacks */
++ atomic_t requests; /* Number of DRNG requests */
++ atomic_t requests_since_fully_seeded; /* Number DRNG requests since
++ last fully seeded */
++ unsigned long last_seeded; /* Last time it was seeded */
++ bool fully_seeded; /* Is DRNG fully seeded? */
++ bool force_reseed; /* Force a reseed */
++
++ /* Lock write operations on DRNG state, DRNG replacement of crypto_cb */
++ struct mutex lock;
++ spinlock_t spin_lock;
++ /* Lock *hash replacement - always take before DRNG lock */
++ rwlock_t hash_lock;
++};
++
++extern struct mutex lrng_crypto_cb_update;
++
++struct lrng_drng *lrng_drng_init_instance(void);
++struct lrng_drng *lrng_drng_atomic_instance(void);
++
++static __always_inline bool lrng_drng_is_atomic(struct lrng_drng *drng)
++{
++ return (drng->drng == lrng_drng_atomic_instance()->drng);
++}
++
++/* Lock the DRNG */
++static __always_inline void lrng_drng_lock(struct lrng_drng *drng,
++ unsigned long *flags)
++ __acquires(&drng->spin_lock)
++{
++ /* Use spin lock in case the atomic DRNG context is used */
++ if (lrng_drng_is_atomic(drng)) {
++ spin_lock_irqsave(&drng->spin_lock, *flags);
++
++ /*
++ * In case a lock transition happened while we were spinning,
++ * catch this case and use the new lock type.
++ */
++ if (!lrng_drng_is_atomic(drng)) {
++ spin_unlock_irqrestore(&drng->spin_lock, *flags);
++ __acquire(&drng->spin_lock);
++ mutex_lock(&drng->lock);
++ }
++ } else {
++ __acquire(&drng->spin_lock);
++ mutex_lock(&drng->lock);
++ }
++}
++
++/* Unlock the DRNG */
++static __always_inline void lrng_drng_unlock(struct lrng_drng *drng,
++ unsigned long *flags)
++ __releases(&drng->spin_lock)
++{
++ if (lrng_drng_is_atomic(drng)) {
++ spin_unlock_irqrestore(&drng->spin_lock, *flags);
++ } else {
++ mutex_unlock(&drng->lock);
++ __release(&drng->spin_lock);
++ }
++}
++
++void lrng_reset(void);
++void lrng_drngs_init_cc20(bool force_seed);
++bool lrng_sp80090c_compliant(void);
++
++static inline u32 lrng_compress_osr(void)
++{
++ return lrng_sp80090c_compliant() ? CONFIG_LRNG_OVERSAMPLE_ES_BITS : 0;
++}
++
++static inline u32 lrng_reduce_by_osr(u32 entropy_bits)
++{
++ u32 osr_bits = lrng_compress_osr();
++ return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0;
++}
++
++bool lrng_get_available(void);
++void lrng_set_available(void);
++void lrng_drng_reset(struct lrng_drng *drng);
++int lrng_drng_get_atomic(u8 *outbuf, u32 outbuflen);
++int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen);
++void lrng_drng_force_reseed(void);
++void lrng_drng_seed_work(struct work_struct *dummy);
++
++#ifdef CONFIG_NUMA
++struct lrng_drng **lrng_drng_instances(void);
++void lrng_drngs_numa_alloc(void);
++#else /* CONFIG_NUMA */
++static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; }
++static inline void lrng_drngs_numa_alloc(void) { return; }
++#endif /* CONFIG_NUMA */
++
++/************************* Entropy sources management *************************/
++
++enum lrng_external_noise_source {
++ lrng_noise_source_hw,
++ lrng_noise_source_user
++};
++
++void lrng_set_entropy_thresh(u32 new);
++u32 lrng_avail_entropy(void);
++void lrng_reset_state(void);
++
++bool lrng_state_exseed_allow(enum lrng_external_noise_source source);
++void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type);
++bool lrng_state_min_seeded(void);
++bool lrng_state_fully_seeded(void);
++bool lrng_state_operational(void);
++
++int lrng_pool_trylock(void);
++void lrng_pool_unlock(void);
++void lrng_pool_all_numa_nodes_seeded(bool set);
++void lrng_pool_add_entropy(void);
++
++struct entropy_buf {
++ u8 a[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
++ u8 b[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
++ u8 c[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
++ u8 d[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
++ u32 now, a_bits, b_bits, c_bits, d_bits;
++};
++
++bool lrng_fully_seeded(bool fully_seeded, struct entropy_buf *eb);
++void lrng_unset_fully_seeded(struct lrng_drng *drng);
++void lrng_fill_seed_buffer(struct entropy_buf *entropy_buf, u32 requested_bits);
++void lrng_init_ops(struct entropy_buf *eb);
++
++/*********************** Auxiliary Pool Entropy Source ************************/
++
++u32 lrng_avail_aux_entropy(void);
++void lrng_aux_es_state(unsigned char *buf, size_t buflen);
++u32 lrng_get_digestsize(void);
++void lrng_pool_set_entropy(u32 entropy_bits);
++int lrng_aux_switch_hash(const struct lrng_crypto_cb *new_cb, void *new_hash,
++ const struct lrng_crypto_cb *old_cb);
++int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits);
++void lrng_get_backtrack_aux(struct entropy_buf *entropy_buf,
++ u32 requested_bits);
++
++/* Obtain the security strength of the LRNG in bits */
++static inline u32 lrng_security_strength(void)
++{
++ /*
++ * We use a hash to read the entropy in the entropy pool. According to
++ * SP800-90B table 1, the entropy can be at most the digest size.
++ * Considering this together with the last sentence in section 3.1.5.1.2
++ * the security strength of a (approved) hash is equal to its output
++ * size. On the other hand the entropy cannot be larger than the
++ * security strength of the used DRBG.
++ */
++ return min_t(u32, LRNG_FULL_SEED_ENTROPY_BITS, lrng_get_digestsize());
++}
++
++static inline u32 lrng_get_seed_entropy_osr(bool fully_seeded)
++{
++ u32 requested_bits = lrng_security_strength();
++
++ /* Apply oversampling during initialization according to SP800-90C */
++ if (lrng_sp80090c_compliant() && !fully_seeded)
++ requested_bits += CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS;
++ return requested_bits;
++}
++
++/************************** Health Test linking code **************************/
++
++enum lrng_health_res {
++ lrng_health_pass, /* Health test passes on time stamp */
++ lrng_health_fail_use, /* Time stamp unhealthy, but mix in */
++ lrng_health_fail_drop /* Time stamp unhealthy, drop it */
++};
++
++#ifdef CONFIG_LRNG_HEALTH_TESTS
++bool lrng_sp80090b_startup_complete(void);
++bool lrng_sp80090b_compliant(void);
++
++enum lrng_health_res lrng_health_test(u32 now_time);
++void lrng_health_disable(void);
++
++#else /* CONFIG_LRNG_HEALTH_TESTS */
++static inline bool lrng_sp80090b_startup_complete(void) { return true; }
++static inline bool lrng_sp80090b_compliant(void) { return false; }
++
++static inline enum lrng_health_res
++lrng_health_test(u32 now_time) { return lrng_health_pass; }
++static inline void lrng_health_disable(void) { }
++#endif /* CONFIG_LRNG_HEALTH_TESTS */
++
++/****************************** Helper code ***********************************/
++
++static inline u32 atomic_read_u32(atomic_t *v)
++{
++ return (u32)atomic_read(v);
++}
++
++/******************** Crypto Primitive Switching Support **********************/
++
++#ifdef CONFIG_LRNG_DRNG_SWITCH
++static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
++{
++ read_lock_irqsave(&drng->hash_lock, *flags);
++}
++
++static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
++{
++ read_unlock_irqrestore(&drng->hash_lock, flags);
++}
++#else /* CONFIG_LRNG_DRNG_SWITCH */
++static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
++{ }
++
++static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
++{ }
++#endif /* CONFIG_LRNG_DRNG_SWITCH */
++
++/*************************** Auxiliary functions ******************************/
++
++void invalidate_batched_entropy(void);
++
++/***************************** Testing code ***********************************/
++
++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
++bool lrng_raw_hires_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
++static inline bool lrng_raw_hires_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
++bool lrng_raw_jiffies_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
++static inline bool lrng_raw_jiffies_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
++bool lrng_raw_irq_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
++static inline bool lrng_raw_irq_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY
++bool lrng_raw_irqflags_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
++static inline bool lrng_raw_irqflags_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
++bool lrng_raw_retip_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
++static inline bool lrng_raw_retip_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
++bool lrng_raw_regs_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_REGS_ENTROPY */
++static inline bool lrng_raw_regs_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */
++
++#ifdef CONFIG_LRNG_RAW_ARRAY
++bool lrng_raw_array_entropy_store(u32 value);
++#else /* CONFIG_LRNG_RAW_ARRAY */
++static inline bool lrng_raw_array_entropy_store(u32 value) { return false; }
++#endif /* CONFIG_LRNG_RAW_ARRAY */
++
++#ifdef CONFIG_LRNG_IRQ_PERF
++bool lrng_perf_time(u32 start);
++#else /* CONFIG_LRNG_IRQ_PERF */
++static inline bool lrng_perf_time(u32 start) { return false; }
++#endif /*CONFIG_LRNG_IRQ_PERF */
++
++#endif /* _LRNG_INTERNAL_H */
+diff -urN linux-5.15/drivers/char/lrng/lrng_kcapi.c linux-5.15-lrng/drivers/char/lrng/lrng_kcapi.c
+--- linux-5.15/drivers/char/lrng/lrng_kcapi.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_kcapi.c 2021-11-29 12:37:45.153278971 +1100
+@@ -0,0 +1,227 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Backend for the LRNG providing the cryptographic primitives using the
++ * kernel crypto API.
++ *
++ * Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <crypto/hash.h>
++#include <crypto/rng.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/lrng.h>
++
++#include "lrng_kcapi_hash.h"
++
++static char *drng_name = NULL;
++module_param(drng_name, charp, 0444);
++MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG");
++
++static char *pool_hash = "sha512";
++module_param(pool_hash, charp, 0444);
++MODULE_PARM_DESC(pool_hash,
++ "Kernel crypto API name of hash or keyed message digest to read the entropy pool");
++
++static char *seed_hash = NULL;
++module_param(seed_hash, charp, 0444);
++MODULE_PARM_DESC(seed_hash,
++ "Kernel crypto API name of hash with output size equal to seedsize of DRNG to bring seed string to the size required by the DRNG");
++
++struct lrng_drng_info {
++ struct crypto_rng *kcapi_rng;
++ void *lrng_hash;
++};
++
++static void *lrng_kcapi_drng_hash_alloc(void)
++{
++ return lrng_kcapi_hash_alloc(pool_hash);
++}
++
++static int lrng_kcapi_drng_seed_helper(void *drng, const u8 *inbuf,
++ u32 inbuflen)
++{
++ SHASH_DESC_ON_STACK(shash, NULL);
++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng;
++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng;
++ void *hash = lrng_drng_info->lrng_hash;
++ u32 digestsize = lrng_kcapi_hash_digestsize(hash);
++ u8 digest[64] __aligned(8);
++ int ret;
++
++ if (!hash)
++ return crypto_rng_reset(kcapi_rng, inbuf, inbuflen);
++
++ BUG_ON(digestsize > sizeof(digest));
++
++ ret = lrng_kcapi_hash_init(shash, hash) ?:
++ lrng_kcapi_hash_update(shash, inbuf, inbuflen) ?:
++ lrng_kcapi_hash_final(shash, digest);
++ lrng_kcapi_hash_zero(shash);
++ if (ret)
++ return ret;
++
++ ret = crypto_rng_reset(kcapi_rng, digest, digestsize);
++ if (ret)
++ return ret;
++
++ memzero_explicit(digest, digestsize);
++ return 0;
++}
++
++static int lrng_kcapi_drng_generate_helper(void *drng, u8 *outbuf,
++ u32 outbuflen)
++{
++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng;
++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng;
++ int ret = crypto_rng_get_bytes(kcapi_rng, outbuf, outbuflen);
++
++ if (ret < 0)
++ return ret;
++
++ return outbuflen;
++}
++
++static void *lrng_kcapi_drng_alloc(u32 sec_strength)
++{
++ struct lrng_drng_info *lrng_drng_info;
++ struct crypto_rng *kcapi_rng;
++ int seedsize;
++ void *ret = ERR_PTR(-ENOMEM);
++
++ if (!drng_name) {
++ pr_err("DRNG name missing\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (!memcmp(drng_name, "drbg", 4) ||
++ !memcmp(drng_name, "stdrng", 6) ||
++ !memcmp(drng_name, "jitterentropy_rng", 17)) {
++ pr_err("Refusing to load the requested random number generator\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ lrng_drng_info = kmalloc(sizeof(*lrng_drng_info), GFP_KERNEL);
++ if (!lrng_drng_info)
++ return ERR_PTR(-ENOMEM);
++
++ kcapi_rng = crypto_alloc_rng(drng_name, 0, 0);
++ if (IS_ERR(kcapi_rng)) {
++ pr_err("DRNG %s cannot be allocated\n", drng_name);
++ ret = ERR_CAST(kcapi_rng);
++ goto free;
++ }
++ lrng_drng_info->kcapi_rng = kcapi_rng;
++
++ seedsize = crypto_rng_seedsize(kcapi_rng);
++
++ if (sec_strength > seedsize)
++ pr_info("Seedsize DRNG (%u bits) lower than security strength of LRNG noise source (%u bits)\n",
++ crypto_rng_seedsize(kcapi_rng) * 8, sec_strength * 8);
++
++ if (seedsize) {
++ void *lrng_hash;
++
++ if (!seed_hash) {
++ switch (seedsize) {
++ case 32:
++ seed_hash = "sha256";
++ break;
++ case 48:
++ seed_hash = "sha384";
++ break;
++ case 64:
++ seed_hash = "sha512";
++ break;
++ default:
++ pr_err("Seed size %d cannot be processed\n",
++ seedsize);
++ goto dealloc;
++ }
++ }
++
++ lrng_hash = lrng_kcapi_hash_alloc(seed_hash);
++ if (IS_ERR(lrng_hash)) {
++ ret = ERR_CAST(lrng_hash);
++ goto dealloc;
++ }
++
++ if (seedsize != lrng_kcapi_hash_digestsize(lrng_hash)) {
++ pr_err("Seed hash output size not equal to DRNG seed size\n");
++ lrng_kcapi_hash_dealloc(lrng_hash);
++ ret = ERR_PTR(-EINVAL);
++ goto dealloc;
++ }
++
++ lrng_drng_info->lrng_hash = lrng_hash;
++
++ pr_info("Seed hash %s allocated\n", seed_hash);
++ } else {
++ lrng_drng_info->lrng_hash = NULL;
++ }
++
++ pr_info("Kernel crypto API DRNG %s allocated\n", drng_name);
++
++ return lrng_drng_info;
++
++dealloc:
++ crypto_free_rng(kcapi_rng);
++free:
++ kfree(lrng_drng_info);
++ return ret;
++}
++
++static void lrng_kcapi_drng_dealloc(void *drng)
++{
++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng;
++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng;
++
++ crypto_free_rng(kcapi_rng);
++ if (lrng_drng_info->lrng_hash)
++ lrng_kcapi_hash_dealloc(lrng_drng_info->lrng_hash);
++ kfree(lrng_drng_info);
++ pr_info("DRNG %s deallocated\n", drng_name);
++}
++
++static const char *lrng_kcapi_drng_name(void)
++{
++ return drng_name;
++}
++
++static const char *lrng_kcapi_pool_hash(void)
++{
++ return pool_hash;
++}
++
++static const struct lrng_crypto_cb lrng_kcapi_crypto_cb = {
++ .lrng_drng_name = lrng_kcapi_drng_name,
++ .lrng_hash_name = lrng_kcapi_pool_hash,
++ .lrng_drng_alloc = lrng_kcapi_drng_alloc,
++ .lrng_drng_dealloc = lrng_kcapi_drng_dealloc,
++ .lrng_drng_seed_helper = lrng_kcapi_drng_seed_helper,
++ .lrng_drng_generate_helper = lrng_kcapi_drng_generate_helper,
++ .lrng_hash_alloc = lrng_kcapi_drng_hash_alloc,
++ .lrng_hash_dealloc = lrng_kcapi_hash_dealloc,
++ .lrng_hash_digestsize = lrng_kcapi_hash_digestsize,
++ .lrng_hash_init = lrng_kcapi_hash_init,
++ .lrng_hash_update = lrng_kcapi_hash_update,
++ .lrng_hash_final = lrng_kcapi_hash_final,
++ .lrng_hash_desc_zero = lrng_kcapi_hash_zero,
++};
++
++static int __init lrng_kcapi_init(void)
++{
++ return lrng_set_drng_cb(&lrng_kcapi_crypto_cb);
++}
++static void __exit lrng_kcapi_exit(void)
++{
++ lrng_set_drng_cb(NULL);
++}
++
++late_initcall(lrng_kcapi_init);
++module_exit(lrng_kcapi_exit);
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
++MODULE_DESCRIPTION("Linux Random Number Generator - kernel crypto API DRNG backend");
+diff -urN linux-5.15/drivers/char/lrng/lrng_kcapi_hash.c linux-5.15-lrng/drivers/char/lrng/lrng_kcapi_hash.c
+--- linux-5.15/drivers/char/lrng/lrng_kcapi_hash.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_kcapi_hash.c 2021-11-29 12:37:24.863279049 +1100
+@@ -0,0 +1,103 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Backend for providing the hash primitive using the kernel crypto API.
++ *
++ * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <crypto/hash.h>
++
++#include "lrng_kcapi_hash.h"
++
++struct lrng_hash_info {
++ struct crypto_shash *tfm;
++};
++
++static inline void _lrng_kcapi_hash_free(struct lrng_hash_info *lrng_hash)
++{
++ struct crypto_shash *tfm = lrng_hash->tfm;
++
++ crypto_free_shash(tfm);
++ kfree(lrng_hash);
++}
++
++void *lrng_kcapi_hash_alloc(const char *name)
++{
++ struct lrng_hash_info *lrng_hash;
++ struct crypto_shash *tfm;
++ int ret;
++
++ if (!name) {
++ pr_err("Hash name missing\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ tfm = crypto_alloc_shash(name, 0, 0);
++ if (IS_ERR(tfm)) {
++ pr_err("could not allocate hash %s\n", name);
++ return ERR_CAST(tfm);
++ }
++
++ ret = sizeof(struct lrng_hash_info);
++ lrng_hash = kmalloc(ret, GFP_KERNEL);
++ if (!lrng_hash) {
++ crypto_free_shash(tfm);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ lrng_hash->tfm = tfm;
++
++ pr_info("Hash %s allocated\n", name);
++
++ return lrng_hash;
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_alloc);
++
++u32 lrng_kcapi_hash_digestsize(void *hash)
++{
++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash;
++ struct crypto_shash *tfm = lrng_hash->tfm;
++
++ return crypto_shash_digestsize(tfm);
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_digestsize);
++
++void lrng_kcapi_hash_dealloc(void *hash)
++{
++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash;
++
++ _lrng_kcapi_hash_free(lrng_hash);
++ pr_info("Hash deallocated\n");
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_dealloc);
++
++int lrng_kcapi_hash_init(struct shash_desc *shash, void *hash)
++{
++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash;
++ struct crypto_shash *tfm = lrng_hash->tfm;
++
++ shash->tfm = tfm;
++ return crypto_shash_init(shash);
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_init);
++
++int lrng_kcapi_hash_update(struct shash_desc *shash, const u8 *inbuf,
++ u32 inbuflen)
++{
++ return crypto_shash_update(shash, inbuf, inbuflen);
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_update);
++
++int lrng_kcapi_hash_final(struct shash_desc *shash, u8 *digest)
++{
++ return crypto_shash_final(shash, digest);
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_final);
++
++void lrng_kcapi_hash_zero(struct shash_desc *shash)
++{
++ shash_desc_zero(shash);
++}
++EXPORT_SYMBOL(lrng_kcapi_hash_zero);
+diff -urN linux-5.15/drivers/char/lrng/lrng_kcapi_hash.h linux-5.15-lrng/drivers/char/lrng/lrng_kcapi_hash.h
+--- linux-5.15/drivers/char/lrng/lrng_kcapi_hash.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_kcapi_hash.h 2021-11-29 12:37:24.863279049 +1100
+@@ -0,0 +1,20 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++/*
++ * Copyright (C) 2020 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#ifndef _LRNG_KCAPI_HASH_H
++#define _LRNG_KCAPI_HASH_H
++
++#include <linux/module.h>
++
++void *lrng_kcapi_hash_alloc(const char *name);
++u32 lrng_kcapi_hash_digestsize(void *hash);
++void lrng_kcapi_hash_dealloc(void *hash);
++int lrng_kcapi_hash_init(struct shash_desc *shash, void *hash);
++int lrng_kcapi_hash_update(struct shash_desc *shash, const u8 *inbuf,
++ u32 inbuflen);
++int lrng_kcapi_hash_final(struct shash_desc *shash, u8 *digest);
++void lrng_kcapi_hash_zero(struct shash_desc *shash);
++
++#endif /* _LRNG_KCAPI_HASH_H */
+diff -urN linux-5.15/drivers/char/lrng/lrng_numa.c linux-5.15-lrng/drivers/char/lrng/lrng_numa.c
+--- linux-5.15/drivers/char/lrng/lrng_numa.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_numa.c 2021-11-29 12:37:08.753279110 +1100
+@@ -0,0 +1,122 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG NUMA support
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/lrng.h>
++#include <linux/slab.h>
++
++#include "lrng_internal.h"
++
++static struct lrng_drng **lrng_drng __read_mostly = NULL;
++
++struct lrng_drng **lrng_drng_instances(void)
++{
++ return smp_load_acquire(&lrng_drng);
++}
++
++/* Allocate the data structures for the per-NUMA node DRNGs */
++static void _lrng_drngs_numa_alloc(struct work_struct *work)
++{
++ struct lrng_drng **drngs;
++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++ u32 node;
++ bool init_drng_used = false;
++
++ mutex_lock(&lrng_crypto_cb_update);
++
++ /* per-NUMA-node DRNGs are already present */
++ if (lrng_drng)
++ goto unlock;
++
++ drngs = kcalloc(nr_node_ids, sizeof(void *), GFP_KERNEL|__GFP_NOFAIL);
++ for_each_online_node(node) {
++ struct lrng_drng *drng;
++
++ if (!init_drng_used) {
++ drngs[node] = lrng_drng_init;
++ init_drng_used = true;
++ continue;
++ }
++
++ drng = kmalloc_node(sizeof(struct lrng_drng),
++ GFP_KERNEL|__GFP_NOFAIL, node);
++ memset(drng, 0, sizeof(lrng_drng));
++
++ drng->crypto_cb = lrng_drng_init->crypto_cb;
++ drng->drng = drng->crypto_cb->lrng_drng_alloc(
++ LRNG_DRNG_SECURITY_STRENGTH_BYTES);
++ if (IS_ERR(drng->drng)) {
++ kfree(drng);
++ goto err;
++ }
++
++ drng->hash = drng->crypto_cb->lrng_hash_alloc();
++ if (IS_ERR(drng->hash)) {
++ drng->crypto_cb->lrng_drng_dealloc(drng->drng);
++ kfree(drng);
++ goto err;
++ }
++
++ mutex_init(&drng->lock);
++ spin_lock_init(&drng->spin_lock);
++ rwlock_init(&drng->hash_lock);
++
++ /*
++ * Switch the hash used by the per-CPU pool.
++ * We do not need to lock the new hash as it is not usable yet
++ * due to **drngs not yet being initialized.
++ */
++ if (lrng_pcpu_switch_hash(node, drng->crypto_cb, drng->hash,
++ &lrng_cc20_crypto_cb))
++ goto err;
++
++ /*
++ * No reseeding of NUMA DRNGs from previous DRNGs as this
++ * would complicate the code. Let it simply reseed.
++ */
++ lrng_drng_reset(drng);
++ drngs[node] = drng;
++
++ lrng_pool_inc_numa_node();
++ pr_info("DRNG and entropy pool read hash for NUMA node %d allocated\n",
++ node);
++ }
++
++ /* counterpart to smp_load_acquire in lrng_drng_instances */
++ if (!cmpxchg_release(&lrng_drng, NULL, drngs)) {
++ lrng_pool_all_numa_nodes_seeded(false);
++ goto unlock;
++ }
++
++err:
++ for_each_online_node(node) {
++ struct lrng_drng *drng = drngs[node];
++
++ if (drng == lrng_drng_init)
++ continue;
++
++ if (drng) {
++ lrng_pcpu_switch_hash(node, &lrng_cc20_crypto_cb, NULL,
++ drng->crypto_cb);
++ drng->crypto_cb->lrng_hash_dealloc(drng->hash);
++ drng->crypto_cb->lrng_drng_dealloc(drng->drng);
++ kfree(drng);
++ }
++ }
++ kfree(drngs);
++
++unlock:
++ mutex_unlock(&lrng_crypto_cb_update);
++}
++
++static DECLARE_WORK(lrng_drngs_numa_alloc_work, _lrng_drngs_numa_alloc);
++
++void lrng_drngs_numa_alloc(void)
++{
++ schedule_work(&lrng_drngs_numa_alloc_work);
++}
+diff -urN linux-5.15/drivers/char/lrng/lrng_proc.c linux-5.15-lrng/drivers/char/lrng/lrng_proc.c
+--- linux-5.15/drivers/char/lrng/lrng_proc.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_proc.c 2021-11-29 12:37:03.083279132 +1100
+@@ -0,0 +1,199 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG proc and sysctl interfaces
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#include <linux/lrng.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/sysctl.h>
++#include <linux/uuid.h>
++
++#include "lrng_internal.h"
++
++/*
++ * 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,
++ * 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 lrng_proc_do_uuid(struct ctl_table *table, int write,
++ void *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct ctl_table fake_table;
++ unsigned char buf[64], tmp_uuid[16], *uuid;
++
++ uuid = table->data;
++ if (!uuid) {
++ uuid = tmp_uuid;
++ generate_random_uuid(uuid);
++ } else {
++ static DEFINE_SPINLOCK(bootid_spinlock);
++
++ spin_lock(&bootid_spinlock);
++ if (!uuid[8])
++ generate_random_uuid(uuid);
++ 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);
++}
++
++static int lrng_proc_do_entropy(struct ctl_table *table, int write,
++ void *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct ctl_table fake_table;
++ int entropy_count;
++
++ entropy_count = lrng_avail_entropy();
++
++ fake_table.data = &entropy_count;
++ fake_table.maxlen = sizeof(entropy_count);
++
++ return proc_dointvec(&fake_table, write, buffer, lenp, ppos);
++}
++
++static int lrng_proc_do_poolsize(struct ctl_table *table, int write,
++ void *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct ctl_table fake_table;
++ int entropy_count;
++
++ /* LRNG can at most retain entropy in per-CPU pools and aux pool */
++ entropy_count = lrng_get_digestsize() + lrng_pcpu_avail_pool_size();
++
++ fake_table.data = &entropy_count;
++ fake_table.maxlen = sizeof(entropy_count);
++
++ return proc_dointvec(&fake_table, write, buffer, lenp, ppos);
++}
++
++static int lrng_min_write_thresh;
++static int lrng_max_write_thresh = (LRNG_WRITE_WAKEUP_ENTROPY << 3);
++static char lrng_sysctl_bootid[16];
++static int lrng_drng_reseed_max_min;
++
++void lrng_proc_update_max_write_thresh(u32 new_digestsize)
++{
++ lrng_max_write_thresh = (int)new_digestsize;
++ mb();
++}
++
++struct ctl_table random_table[] = {
++ {
++ .procname = "poolsize",
++ .maxlen = sizeof(int),
++ .mode = 0444,
++ .proc_handler = lrng_proc_do_poolsize,
++ },
++ {
++ .procname = "entropy_avail",
++ .maxlen = sizeof(int),
++ .mode = 0444,
++ .proc_handler = lrng_proc_do_entropy,
++ },
++ {
++ .procname = "write_wakeup_threshold",
++ .data = &lrng_write_wakeup_bits,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = &lrng_min_write_thresh,
++ .extra2 = &lrng_max_write_thresh,
++ },
++ {
++ .procname = "boot_id",
++ .data = &lrng_sysctl_bootid,
++ .maxlen = 16,
++ .mode = 0444,
++ .proc_handler = lrng_proc_do_uuid,
++ },
++ {
++ .procname = "uuid",
++ .maxlen = 16,
++ .mode = 0444,
++ .proc_handler = lrng_proc_do_uuid,
++ },
++ {
++ .procname = "urandom_min_reseed_secs",
++ .data = &lrng_drng_reseed_max_time,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec,
++ .extra1 = &lrng_drng_reseed_max_min,
++ },
++ { }
++};
++
++/* Number of online DRNGs */
++static u32 numa_drngs = 1;
++
++void lrng_pool_inc_numa_node(void)
++{
++ numa_drngs++;
++}
++
++static int lrng_proc_type_show(struct seq_file *m, void *v)
++{
++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++ unsigned long flags = 0;
++ unsigned char buf[250], irq[200], aux[100], cpu[90], jent[45];
++
++ lrng_drng_lock(lrng_drng_init, &flags);
++ snprintf(buf, sizeof(buf),
++ "DRNG name: %s\n"
++ "LRNG security strength in bits: %d\n"
++ "number of DRNG instances: %u\n"
++ "Standards compliance: %s\n"
++ "Entropy Sources: %s%s%sAuxiliary\n"
++ "LRNG minimally seeded: %s\n"
++ "LRNG fully seeded: %s\n",
++ lrng_drng_init->crypto_cb->lrng_drng_name(),
++ lrng_security_strength(),
++ numa_drngs,
++ lrng_sp80090c_compliant() ? "SP800-90C " : "",
++ IS_ENABLED(CONFIG_LRNG_IRQ) ? "IRQ " : "",
++ IS_ENABLED(CONFIG_LRNG_JENT) ? "JitterRNG " : "",
++ IS_ENABLED(CONFIG_LRNG_CPU) ? "CPU " : "",
++ lrng_state_min_seeded() ? "true" : "false",
++ lrng_state_fully_seeded() ? "true" : "false");
++
++ lrng_aux_es_state(aux, sizeof(aux));
++
++ irq[0] = '\0';
++ lrng_irq_es_state(irq, sizeof(irq));
++
++ jent[0] = '\0';
++ lrng_jent_es_state(jent, sizeof(jent));
++
++ cpu[0] = '\0';
++ lrng_arch_es_state(cpu, sizeof(cpu));
++
++ lrng_drng_unlock(lrng_drng_init, &flags);
++
++ seq_write(m, buf, strlen(buf));
++ seq_write(m, aux, strlen(aux));
++ seq_write(m, irq, strlen(irq));
++ seq_write(m, jent, strlen(jent));
++ seq_write(m, cpu, strlen(cpu));
++
++ return 0;
++}
++
++static int __init lrng_proc_type_init(void)
++{
++ proc_create_single("lrng_type", 0444, NULL, &lrng_proc_type_show);
++ return 0;
++}
++
++module_init(lrng_proc_type_init);
+diff -urN linux-5.15/drivers/char/lrng/lrng_selftest.c linux-5.15-lrng/drivers/char/lrng/lrng_selftest.c
+--- linux-5.15/drivers/char/lrng/lrng_selftest.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_selftest.c 2021-11-29 12:38:26.603278813 +1100
+@@ -0,0 +1,386 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG power-on and on-demand self-test
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++/*
++ * In addition to the self-tests below, the following LRNG components
++ * are covered with self-tests during regular operation:
++ *
++ * * power-on self-test: SP800-90A DRBG provided by the Linux kernel crypto API
++ * * power-on self-test: PRNG provided by the Linux kernel crypto API
++ * * runtime test: Raw noise source data testing including SP800-90B compliant
++ * tests when enabling CONFIG_LRNG_HEALTH_TESTS
++ *
++ * Additional developer tests present with LRNG code:
++ * * SP800-90B APT and RCT test enforcement validation when enabling
++ * CONFIG_LRNG_APT_BROKEN or CONFIG_LRNG_RCT_BROKEN.
++ * * Collection of raw entropy from the interrupt noise source when enabling
++ * CONFIG_LRNG_TESTING and pulling the data from the kernel with the provided
++ * interface.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/lrng.h>
++#include <linux/slab.h>
++
++#include "lrng_chacha20.h"
++#include "lrng_internal.h"
++
++#define LRNG_SELFTEST_PASSED 0
++#define LRNG_SEFLTEST_ERROR_TIME (1 << 0)
++#define LRNG_SEFLTEST_ERROR_CHACHA20 (1 << 1)
++#define LRNG_SEFLTEST_ERROR_HASH (1 << 2)
++#define LRNG_SEFLTEST_ERROR_GCD (1 << 3)
++#define LRNG_SELFTEST_NOT_EXECUTED 0xffffffff
++
++#ifdef CONFIG_LRNG_IRQ
++
++#include "lrng_es_irq.h"
++
++static u32 lrng_data_selftest_ptr = 0;
++static u32 lrng_data_selftest[LRNG_DATA_ARRAY_SIZE];
++
++static inline void lrng_data_process_selftest_insert(u32 time)
++{
++ u32 ptr = lrng_data_selftest_ptr++ & LRNG_DATA_WORD_MASK;
++ unsigned int array = lrng_data_idx2array(ptr);
++ unsigned int slot = lrng_data_idx2slot(ptr);
++
++ /* zeroization of slot to ensure the following OR adds the data */
++ lrng_data_selftest[array] &=
++ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK,
++ slot));
++ lrng_data_selftest[array] |=
++ lrng_data_slot_val(time & LRNG_DATA_SLOTSIZE_MASK, slot);
++}
++
++static inline void lrng_data_process_selftest_u32(u32 data)
++{
++ u32 pre_ptr, ptr, mask;
++ unsigned int pre_array;
++
++ /* Increment pointer by number of slots taken for input value */
++ lrng_data_selftest_ptr += LRNG_DATA_SLOTS_PER_UINT;
++
++ /* ptr to current unit */
++ ptr = lrng_data_selftest_ptr;
++
++ lrng_pcpu_split_u32(&ptr, &pre_ptr, &mask);
++
++ /* MSB of data go into previous unit */
++ pre_array = lrng_data_idx2array(pre_ptr);
++ /* zeroization of slot to ensure the following OR adds the data */
++ lrng_data_selftest[pre_array] &= ~(0xffffffff & ~mask);
++ lrng_data_selftest[pre_array] |= data & ~mask;
++
++ /* LSB of data go into current unit */
++ lrng_data_selftest[lrng_data_idx2array(ptr)] = data & mask;
++}
++
++static unsigned int lrng_data_process_selftest(void)
++{
++ u32 time;
++ u32 idx_zero_compare = (0 << 0) | (1 << 8) | (2 << 16) | (3 << 24);
++ u32 idx_one_compare = (4 << 0) | (5 << 8) | (6 << 16) | (7 << 24);
++ u32 idx_last_compare =
++ (((LRNG_DATA_NUM_VALUES - 4) & LRNG_DATA_SLOTSIZE_MASK) << 0) |
++ (((LRNG_DATA_NUM_VALUES - 3) & LRNG_DATA_SLOTSIZE_MASK) << 8) |
++ (((LRNG_DATA_NUM_VALUES - 2) & LRNG_DATA_SLOTSIZE_MASK) << 16) |
++ (((LRNG_DATA_NUM_VALUES - 1) & LRNG_DATA_SLOTSIZE_MASK) << 24);
++
++ (void)idx_one_compare;
++
++ /* "poison" the array to verify the operation of the zeroization */
++ lrng_data_selftest[0] = 0xffffffff;
++ lrng_data_selftest[1] = 0xffffffff;
++
++ lrng_data_process_selftest_insert(0);
++ /*
++ * Note, when using lrng_data_process_u32() on unaligned ptr,
++ * the first slots will go into next word, and the last slots go
++ * into the previous word.
++ */
++ lrng_data_process_selftest_u32((4 << 0) | (1 << 8) | (2 << 16) |
++ (3 << 24));
++ lrng_data_process_selftest_insert(5);
++ lrng_data_process_selftest_insert(6);
++ lrng_data_process_selftest_insert(7);
++
++ if ((lrng_data_selftest[0] != idx_zero_compare) ||
++ (lrng_data_selftest[1] != idx_one_compare))
++ goto err;
++
++ /* Reset for next test */
++ lrng_data_selftest[0] = 0;
++ lrng_data_selftest[1] = 0;
++ lrng_data_selftest_ptr = 0;
++
++ for (time = 0; time < LRNG_DATA_NUM_VALUES; time++)
++ lrng_data_process_selftest_insert(time);
++
++ if ((lrng_data_selftest[0] != idx_zero_compare) ||
++ (lrng_data_selftest[1] != idx_one_compare) ||
++ (lrng_data_selftest[LRNG_DATA_ARRAY_SIZE - 1] != idx_last_compare))
++ goto err;
++
++ return LRNG_SELFTEST_PASSED;
++
++err:
++ pr_err("LRNG data array self-test FAILED\n");
++ return LRNG_SEFLTEST_ERROR_TIME;
++}
++
++static unsigned int lrng_gcd_selftest(void)
++{
++ u32 history[10];
++ unsigned int i;
++
++#define LRNG_GCD_SELFTEST 3
++ for (i = 0; i < ARRAY_SIZE(history); i++)
++ history[i] = i * LRNG_GCD_SELFTEST;
++
++ if (lrng_gcd_analyze(history, ARRAY_SIZE(history)) == LRNG_GCD_SELFTEST)
++ return LRNG_SELFTEST_PASSED;
++
++ pr_err("LRNG GCD self-test FAILED\n");
++ return LRNG_SEFLTEST_ERROR_GCD;
++}
++
++#else /* CONFIG_LRNG_IRQ */
++
++static unsigned int lrng_data_process_selftest(void)
++{
++ return LRNG_SELFTEST_PASSED;
++}
++
++static unsigned int lrng_gcd_selftest(void)
++{
++ return LRNG_SELFTEST_PASSED;
++}
++
++#endif /* CONFIG_LRNG_IRQ */
++
++static inline void lrng_selftest_bswap32(u32 *ptr, u32 words)
++{
++ u32 i;
++
++ /* Byte-swap data which is an LE representation */
++ for (i = 0; i < words; i++) {
++ __le32 *p = (__le32 *)ptr;
++
++ *p = cpu_to_le32(*ptr);
++ ptr++;
++ }
++}
++
++/* The test vectors are taken from crypto/testmgr.h */
++static unsigned int lrng_hash_selftest(void)
++{
++ SHASH_DESC_ON_STACK(shash, NULL);
++ const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb;
++ static const u8 lrng_hash_selftest_result[] =
++#ifdef CONFIG_CRYPTO_LIB_SHA256
++ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
++ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
++ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
++ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad };
++#else /* CONFIG_CRYPTO_LIB_SHA256 */
++ { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
++ 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d };
++#endif /* CONFIG_CRYPTO_LIB_SHA256 */
++ static const u8 hash_input[] = { 0x61, 0x62, 0x63 }; /* "abc" */
++ u8 digest[sizeof(lrng_hash_selftest_result)] __aligned(sizeof(u32));
++
++ BUG_ON(sizeof(digest) != crypto_cb->lrng_hash_digestsize(NULL));
++
++ if (!crypto_cb->lrng_hash_init(shash, NULL) &&
++ !crypto_cb->lrng_hash_update(shash, hash_input,
++ sizeof(hash_input)) &&
++ !crypto_cb->lrng_hash_final(shash, digest) &&
++ !memcmp(digest, lrng_hash_selftest_result, sizeof(digest)))
++ return 0;
++
++ pr_err("LRNG %s Hash self-test FAILED\n", crypto_cb->lrng_hash_name());
++ return LRNG_SEFLTEST_ERROR_HASH;
++}
++
++/*
++ * The test vectors were generated using the ChaCha20 DRNG from
++ * https://www.chronox.de/chacha20.html
++ */
++static unsigned int lrng_chacha20_drng_selftest(void)
++{
++ const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb;
++ u8 seed[CHACHA_KEY_SIZE * 2] = {
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 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,
++ };
++ struct chacha20_block chacha20;
++ int ret;
++ u8 outbuf[CHACHA_KEY_SIZE * 2] __aligned(sizeof(u32));
++
++ /*
++ * Expected result when ChaCha20 DRNG state is zero:
++ * * constants are set to "expand 32-byte k"
++ * * remaining state is 0
++ * and pulling one half ChaCha20 DRNG block.
++ */
++ static const u8 expected_halfblock[CHACHA_KEY_SIZE] = {
++ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
++ 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
++ 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
++ 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7 };
++
++ /*
++ * Expected result when ChaCha20 DRNG state is zero:
++ * * constants are set to "expand 32-byte k"
++ * * remaining state is 0
++ * followed by a reseed with two keyblocks
++ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 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
++ * and pulling one ChaCha20 DRNG block.
++ */
++ static const u8 expected_oneblock[CHACHA_KEY_SIZE * 2] = {
++ 0xe3, 0xb0, 0x8a, 0xcc, 0x34, 0xc3, 0x17, 0x0e,
++ 0xc3, 0xd8, 0xc3, 0x40, 0xe7, 0x73, 0xe9, 0x0d,
++ 0xd1, 0x62, 0xa3, 0x5d, 0x7d, 0xf2, 0xf1, 0x4a,
++ 0x24, 0x42, 0xb7, 0x1e, 0xb0, 0x05, 0x17, 0x07,
++ 0xb9, 0x35, 0x10, 0x69, 0x8b, 0x46, 0xfb, 0x51,
++ 0xe9, 0x91, 0x3f, 0x46, 0xf2, 0x4d, 0xea, 0xd0,
++ 0x81, 0xc1, 0x1b, 0xa9, 0x5d, 0x52, 0x91, 0x5f,
++ 0xcd, 0xdc, 0xc6, 0xd6, 0xc3, 0x7c, 0x50, 0x23 };
++
++ /*
++ * Expected result when ChaCha20 DRNG state is zero:
++ * * constants are set to "expand 32-byte k"
++ * * remaining state is 0
++ * followed by a reseed with one key block plus one byte
++ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 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
++ * and pulling less than one ChaCha20 DRNG block.
++ */
++ static const u8 expected_block_nonalinged[CHACHA_KEY_SIZE + 4] = {
++ 0x9c, 0xfc, 0x5e, 0x31, 0x21, 0x62, 0x11, 0x85,
++ 0xd3, 0x77, 0xd3, 0x69, 0x0f, 0xa8, 0x16, 0x55,
++ 0xb4, 0x4c, 0xf6, 0x52, 0xf3, 0xa8, 0x37, 0x99,
++ 0x38, 0x76, 0xa0, 0x66, 0xec, 0xbb, 0xce, 0xa9,
++ 0x9c, 0x95, 0xa1, 0xfd };
++
++ BUILD_BUG_ON(sizeof(seed) % sizeof(u32));
++
++ memset(&chacha20, 0, sizeof(chacha20));
++ lrng_cc20_init_rfc7539(&chacha20);
++ lrng_selftest_bswap32((u32 *)seed, sizeof(seed) / sizeof(u32));
++
++ /* Generate with zero state */
++ ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf,
++ sizeof(expected_halfblock));
++ if (ret != sizeof(expected_halfblock))
++ goto err;
++ if (memcmp(outbuf, expected_halfblock, sizeof(expected_halfblock)))
++ goto err;
++
++ /* Clear state of DRNG */
++ memset(&chacha20.key.u[0], 0, 48);
++
++ /* Reseed with 2 key blocks */
++ ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed,
++ sizeof(expected_oneblock));
++ if (ret < 0)
++ goto err;
++ ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf,
++ sizeof(expected_oneblock));
++ if (ret != sizeof(expected_oneblock))
++ goto err;
++ if (memcmp(outbuf, expected_oneblock, sizeof(expected_oneblock)))
++ goto err;
++
++ /* Clear state of DRNG */
++ memset(&chacha20.key.u[0], 0, 48);
++
++ /* Reseed with 1 key block and one byte */
++ ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed,
++ sizeof(expected_block_nonalinged));
++ if (ret < 0)
++ goto err;
++ ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf,
++ sizeof(expected_block_nonalinged));
++ if (ret != sizeof(expected_block_nonalinged))
++ goto err;
++ if (memcmp(outbuf, expected_block_nonalinged,
++ sizeof(expected_block_nonalinged)))
++ goto err;
++
++ return LRNG_SELFTEST_PASSED;
++
++err:
++ pr_err("LRNG ChaCha20 DRNG self-test FAILED\n");
++ return LRNG_SEFLTEST_ERROR_CHACHA20;
++}
++
++static unsigned int lrng_selftest_status = LRNG_SELFTEST_NOT_EXECUTED;
++
++static int lrng_selftest(void)
++{
++ unsigned int ret = lrng_data_process_selftest();
++
++ ret |= lrng_chacha20_drng_selftest();
++ ret |= lrng_hash_selftest();
++ ret |= lrng_gcd_selftest();
++
++ if (ret) {
++ if (IS_ENABLED(CONFIG_LRNG_SELFTEST_PANIC))
++ panic("LRNG self-tests failed: %u\n", ret);
++ } else {
++ pr_info("LRNG self-tests passed\n");
++ }
++
++ lrng_selftest_status = ret;
++
++ if (lrng_selftest_status)
++ return -EFAULT;
++ return 0;
++}
++
++#ifdef CONFIG_SYSFS
++/* Re-perform self-test when any value is written to the sysfs file. */
++static int lrng_selftest_sysfs_set(const char *val,
++ const struct kernel_param *kp)
++{
++ return lrng_selftest();
++}
++
++static const struct kernel_param_ops lrng_selftest_sysfs = {
++ .set = lrng_selftest_sysfs_set,
++ .get = param_get_uint,
++};
++module_param_cb(selftest_status, &lrng_selftest_sysfs, &lrng_selftest_status,
++ 0644);
++#endif /* CONFIG_SYSFS */
++
++static int __init lrng_selftest_init(void)
++{
++ return lrng_selftest();
++}
++
++module_init(lrng_selftest_init);
+diff -urN linux-5.15/drivers/char/lrng/lrng_switch.c linux-5.15-lrng/drivers/char/lrng/lrng_switch.c
+--- linux-5.15/drivers/char/lrng/lrng_switch.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_switch.c 2021-11-29 12:37:19.323279070 +1100
+@@ -0,0 +1,226 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * LRNG DRNG switching support
++ *
++ * Copyright (C) 2016 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/lrng.h>
++
++#include "lrng_internal.h"
++
++static int lrng_drng_switch(struct lrng_drng *drng_store,
++ const struct lrng_crypto_cb *cb, int node)
++{
++ const struct lrng_crypto_cb *old_cb;
++ unsigned long flags = 0, flags2 = 0;
++ int ret;
++ u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES];
++ void *new_drng = cb->lrng_drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES);
++ void *old_drng, *new_hash, *old_hash;
++ u32 current_security_strength;
++ bool sl = false, reset_drng = !lrng_get_available();
++
++ if (IS_ERR(new_drng)) {
++ pr_warn("could not allocate new DRNG for NUMA node %d (%ld)\n",
++ node, PTR_ERR(new_drng));
++ return PTR_ERR(new_drng);
++ }
++
++ new_hash = cb->lrng_hash_alloc();
++ if (IS_ERR(new_hash)) {
++ pr_warn("could not allocate new LRNG pool hash (%ld)\n",
++ PTR_ERR(new_hash));
++ cb->lrng_drng_dealloc(new_drng);
++ return PTR_ERR(new_hash);
++ }
++
++ if (cb->lrng_hash_digestsize(new_hash) > LRNG_MAX_DIGESTSIZE) {
++ pr_warn("digest size of newly requested hash too large\n");
++ cb->lrng_hash_dealloc(new_hash);
++ cb->lrng_drng_dealloc(new_drng);
++ return -EINVAL;
++ }
++
++ current_security_strength = lrng_security_strength();
++ lrng_drng_lock(drng_store, &flags);
++
++ /*
++ * Pull from existing DRNG to seed new DRNG regardless of seed status
++ * of old DRNG -- the entropy state for the DRNG is left unchanged which
++ * implies that als the new DRNG is reseeded when deemed necessary. This
++ * seeding of the new DRNG shall only ensure that the new DRNG has the
++ * same entropy as the old DRNG.
++ */
++ ret = drng_store->crypto_cb->lrng_drng_generate_helper(
++ drng_store->drng, seed, sizeof(seed));
++ lrng_drng_unlock(drng_store, &flags);
++
++ if (ret < 0) {
++ reset_drng = true;
++ pr_warn("getting random data from DRNG failed for NUMA node %d (%d)\n",
++ node, ret);
++ } else {
++ /* seed new DRNG with data */
++ ret = cb->lrng_drng_seed_helper(new_drng, seed, ret);
++ memzero_explicit(seed, sizeof(seed));
++ if (ret < 0) {
++ reset_drng = true;
++ pr_warn("seeding of new DRNG failed for NUMA node %d (%d)\n",
++ node, ret);
++ } else {
++ pr_debug("seeded new DRNG of NUMA node %d instance from old DRNG instance\n",
++ node);
++ }
++ }
++
++ mutex_lock(&drng_store->lock);
++ write_lock_irqsave(&drng_store->hash_lock, flags2);
++ /*
++ * If we switch the DRNG from the initial ChaCha20 DRNG to something
++ * else, there is a lock transition from spin lock to mutex (see
++ * lrng_drng_is_atomic and how the lock is taken in lrng_drng_lock).
++ * Thus, we need to take both locks during the transition phase.
++ */
++ if (lrng_drng_is_atomic(drng_store)) {
++ spin_lock_irqsave(&drng_store->spin_lock, flags);
++ sl = true;
++ } else {
++ __acquire(&drng_store->spin_lock);
++ }
++
++ /* Trigger the switch of the aux entropy pool for current node. */
++ if (drng_store == lrng_drng_init_instance()) {
++ ret = lrng_aux_switch_hash(cb, new_hash, drng_store->crypto_cb);
++ if (ret)
++ goto err;
++ }
++
++ /* Trigger the switch of the per-CPU entropy pools for current node. */
++ ret = lrng_pcpu_switch_hash(node, cb, new_hash, drng_store->crypto_cb);
++ if (ret) {
++ /* Switch the crypto operation back to be consistent */
++ WARN_ON(lrng_aux_switch_hash(drng_store->crypto_cb,
++ drng_store->hash, cb));
++ } else {
++ if (reset_drng)
++ lrng_drng_reset(drng_store);
++
++ old_drng = drng_store->drng;
++ old_cb = drng_store->crypto_cb;
++ drng_store->drng = new_drng;
++ drng_store->crypto_cb = cb;
++
++ old_hash = drng_store->hash;
++ drng_store->hash = new_hash;
++ pr_info("Entropy pool read-hash allocated for DRNG for NUMA node %d\n",
++ node);
++
++ /* Reseed if previous LRNG security strength was insufficient */
++ if (current_security_strength < lrng_security_strength())
++ drng_store->force_reseed = true;
++
++ /* Force oversampling seeding as we initialize DRNG */
++ if (IS_ENABLED(CONFIG_LRNG_OVERSAMPLE_ENTROPY_SOURCES))
++ lrng_unset_fully_seeded(drng_store);
++
++ if (lrng_state_min_seeded())
++ lrng_set_entropy_thresh(lrng_get_seed_entropy_osr(
++ drng_store->fully_seeded));
++
++ /* ChaCha20 serves as atomic instance left untouched. */
++ if (old_drng != &chacha20) {
++ old_cb->lrng_drng_dealloc(old_drng);
++ old_cb->lrng_hash_dealloc(old_hash);
++ }
++
++ pr_info("DRNG of NUMA node %d switched\n", node);
++ }
++
++err:
++ if (sl)
++ spin_unlock_irqrestore(&drng_store->spin_lock, flags);
++ else
++ __release(&drng_store->spin_lock);
++ write_unlock_irqrestore(&drng_store->hash_lock, flags2);
++ mutex_unlock(&drng_store->lock);
++
++ return ret;
++}
++
++/*
++ * Switch the existing DRNG instances with new using the new crypto callbacks.
++ * The caller must hold the lrng_crypto_cb_update lock.
++ */
++static int lrng_drngs_switch(const struct lrng_crypto_cb *cb)
++{
++ struct lrng_drng **lrng_drng = lrng_drng_instances();
++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++ int ret = 0;
++
++ /* Update DRNG */
++ if (lrng_drng) {
++ u32 node;
++
++ for_each_online_node(node) {
++ if (lrng_drng[node])
++ ret = lrng_drng_switch(lrng_drng[node], cb,
++ node);
++ }
++ } else {
++ ret = lrng_drng_switch(lrng_drng_init, cb, 0);
++ }
++
++ if (!ret)
++ lrng_set_available();
++
++ return 0;
++}
++
++/*
++ * lrng_set_drng_cb - Register new cryptographic callback functions for DRNG
++ * The registering implies that all old DRNG states are replaced with new
++ * DRNG states.
++ *
++ * @cb: Callback functions to be registered -- if NULL, use the default
++ * callbacks pointing to the ChaCha20 DRNG.
++ *
++ * Return:
++ * * 0 on success
++ * * < 0 on error
++ */
++int lrng_set_drng_cb(const struct lrng_crypto_cb *cb)
++{
++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
++ int ret;
++
++ if (!cb)
++ cb = &lrng_cc20_crypto_cb;
++
++ mutex_lock(&lrng_crypto_cb_update);
++
++ /*
++ * If a callback other than the default is set, allow it only to be
++ * set back to the default callback. This ensures that multiple
++ * different callbacks can be registered at the same time. If a
++ * callback different from the current callback and the default
++ * callback shall be set, the current callback must be deregistered
++ * (e.g. the kernel module providing it must be unloaded) and the new
++ * implementation can be registered.
++ */
++ if ((cb != &lrng_cc20_crypto_cb) &&
++ (lrng_drng_init->crypto_cb != &lrng_cc20_crypto_cb)) {
++ pr_warn("disallow setting new cipher callbacks, unload the old callbacks first!\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = lrng_drngs_switch(cb);
++
++out:
++ mutex_unlock(&lrng_crypto_cb_update);
++ return ret;
++}
++EXPORT_SYMBOL(lrng_set_drng_cb);
+diff -urN linux-5.15/drivers/char/lrng/lrng_testing.c linux-5.15-lrng/drivers/char/lrng/lrng_testing.c
+--- linux-5.15/drivers/char/lrng/lrng_testing.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/drivers/char/lrng/lrng_testing.c 2021-11-29 12:38:19.263278841 +1100
+@@ -0,0 +1,689 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++/*
++ * Linux Random Number Generator (LRNG) testing interfaces
++ *
++ * Copyright (C) 2019 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/atomic.h>
++#include <linux/bug.h>
++#include <linux/debugfs.h>
++#include <linux/lrng.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/sched/signal.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/uaccess.h>
++#include <linux/workqueue.h>
++#include <asm/errno.h>
++
++#include "lrng_internal.h"
++
++#define LRNG_TESTING_RINGBUFFER_SIZE 1024
++#define LRNG_TESTING_RINGBUFFER_MASK (LRNG_TESTING_RINGBUFFER_SIZE - 1)
++
++struct lrng_testing {
++ u32 lrng_testing_rb[LRNG_TESTING_RINGBUFFER_SIZE];
++ u32 rb_reader;
++ u32 rb_writer;
++ atomic_t lrng_testing_enabled;
++ spinlock_t lock;
++ wait_queue_head_t read_wait;
++};
++
++/*************************** Generic Data Handling ****************************/
++
++/*
++ * boot variable:
++ * 0 ==> No boot test, gathering of runtime data allowed
++ * 1 ==> Boot test enabled and ready for collecting data, gathering runtime
++ * data is disabled
++ * 2 ==> Boot test completed and disabled, gathering of runtime data is
++ * disabled
++ */
++
++static inline void lrng_testing_reset(struct lrng_testing *data)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&data->lock, flags);
++ data->rb_reader = 0;
++ data->rb_writer = 0;
++ spin_unlock_irqrestore(&data->lock, flags);
++}
++
++static inline void lrng_testing_init(struct lrng_testing *data, u32 boot)
++{
++ /*
++ * The boot time testing implies we have a running test. If the
++ * caller wants to clear it, he has to unset the boot_test flag
++ * at runtime via sysfs to enable regular runtime testing
++ */
++ if (boot)
++ return;
++
++ lrng_testing_reset(data);
++ atomic_set(&data->lrng_testing_enabled, 1);
++ pr_warn("Enabling data collection\n");
++}
++
++static inline void lrng_testing_fini(struct lrng_testing *data, u32 boot)
++{
++ /* If we have boot data, we do not reset yet to allow data to be read */
++ if (boot)
++ return;
++
++ atomic_set(&data->lrng_testing_enabled, 0);
++ lrng_testing_reset(data);
++ pr_warn("Disabling data collection\n");
++}
++
++static inline bool lrng_testing_store(struct lrng_testing *data, u32 value,
++ u32 *boot)
++{
++ unsigned long flags;
++
++ if (!atomic_read(&data->lrng_testing_enabled) && (*boot != 1))
++ return false;
++
++ spin_lock_irqsave(&data->lock, flags);
++
++ /*
++ * Disable entropy testing for boot time testing after ring buffer
++ * is filled.
++ */
++ if (*boot) {
++ if (data->rb_writer > LRNG_TESTING_RINGBUFFER_SIZE) {
++ *boot = 2;
++ pr_warn_once("One time data collection test disabled\n");
++ spin_unlock_irqrestore(&data->lock, flags);
++ return false;
++ }
++
++ if (data->rb_writer == 1)
++ pr_warn("One time data collection test enabled\n");
++ }
++
++ data->lrng_testing_rb[data->rb_writer & LRNG_TESTING_RINGBUFFER_MASK] =
++ value;
++ data->rb_writer++;
++
++ spin_unlock_irqrestore(&data->lock, flags);
++
++ if (wq_has_sleeper(&data->read_wait))
++ wake_up_interruptible(&data->read_wait);
++
++ return true;
++}
++
++static inline bool lrng_testing_have_data(struct lrng_testing *data)
++{
++ return ((data->rb_writer & LRNG_TESTING_RINGBUFFER_MASK) !=
++ (data->rb_reader & LRNG_TESTING_RINGBUFFER_MASK));
++}
++
++static inline int lrng_testing_reader(struct lrng_testing *data, u32 *boot,
++ u8 *outbuf, u32 outbuflen)
++{
++ unsigned long flags;
++ int collected_data = 0;
++
++ lrng_testing_init(data, *boot);
++
++ while (outbuflen) {
++ spin_lock_irqsave(&data->lock, flags);
++
++ /* We have no data or reached the writer. */
++ if (!data->rb_writer ||
++ (data->rb_writer == data->rb_reader)) {
++
++ spin_unlock_irqrestore(&data->lock, flags);
++
++ /*
++ * Now we gathered all boot data, enable regular data
++ * collection.
++ */
++ if (*boot) {
++ *boot = 0;
++ goto out;
++ }
++
++ wait_event_interruptible(data->read_wait,
++ lrng_testing_have_data(data));
++ if (signal_pending(current)) {
++ collected_data = -ERESTARTSYS;
++ goto out;
++ }
++
++ continue;
++ }
++
++ /* We copy out word-wise */
++ if (outbuflen < sizeof(u32)) {
++ spin_unlock_irqrestore(&data->lock, flags);
++ goto out;
++ }
++
++ memcpy(outbuf, &data->lrng_testing_rb[data->rb_reader],
++ sizeof(u32));
++ data->rb_reader++;
++
++ spin_unlock_irqrestore(&data->lock, flags);
++
++ outbuf += sizeof(u32);
++ outbuflen -= sizeof(u32);
++ collected_data += sizeof(u32);
++ }
++
++out:
++ lrng_testing_fini(data, *boot);
++ return collected_data;
++}
++
++static int lrng_testing_extract_user(struct file *file, char __user *buf,
++ size_t nbytes, loff_t *ppos,
++ int (*reader)(u8 *outbuf, u32 outbuflen))
++{
++ u8 *tmp, *tmp_aligned;
++ int ret = 0, large_request = (nbytes > 256);
++
++ if (!nbytes)
++ return 0;
++
++ /*
++ * The intention of this interface is for collecting at least
++ * 1000 samples due to the SP800-90B requirements. So, we make no
++ * effort in avoiding allocating more memory that actually needed
++ * by the user. Hence, we allocate sufficient memory to always hold
++ * that amount of data.
++ */
++ tmp = kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL);
++ if (!tmp)
++ return -ENOMEM;
++
++ tmp_aligned = PTR_ALIGN(tmp, sizeof(u32));
++
++ while (nbytes) {
++ int i;
++
++ if (large_request && need_resched()) {
++ if (signal_pending(current)) {
++ if (ret == 0)
++ ret = -ERESTARTSYS;
++ break;
++ }
++ schedule();
++ }
++
++ i = min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE);
++ i = reader(tmp_aligned, i);
++ if (i <= 0) {
++ if (i < 0)
++ ret = i;
++ break;
++ }
++ if (copy_to_user(buf, tmp_aligned, i)) {
++ ret = -EFAULT;
++ break;
++ }
++
++ nbytes -= i;
++ buf += i;
++ ret += i;
++ }
++
++ kfree_sensitive(tmp);
++
++ if (ret > 0)
++ *ppos += ret;
++
++ return ret;
++}
++
++/************** Raw High-Resolution Timer Entropy Data Handling ***************/
++
++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
++
++static u32 boot_raw_hires_test = 0;
++module_param(boot_raw_hires_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_hires_test, "Enable gathering boot time high resolution timer entropy of the first entropy events");
++
++static struct lrng_testing lrng_raw_hires = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_hires.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_hires.read_wait)
++};
++
++bool lrng_raw_hires_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_hires, value, &boot_raw_hires_test);
++}
++
++static int lrng_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_hires, &boot_raw_hires_test,
++ outbuf, outbuflen);
++}
++
++static ssize_t lrng_raw_hires_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_hires_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_hires_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_hires_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
++
++/********************* Raw Jiffies Entropy Data Handling **********************/
++
++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
++
++static u32 boot_raw_jiffies_test = 0;
++module_param(boot_raw_jiffies_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_jiffies_test, "Enable gathering boot time high resolution timer entropy of the first entropy events");
++
++static struct lrng_testing lrng_raw_jiffies = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_jiffies.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_jiffies.read_wait)
++};
++
++bool lrng_raw_jiffies_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_jiffies, value,
++ &boot_raw_jiffies_test);
++}
++
++static int lrng_raw_jiffies_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_jiffies, &boot_raw_jiffies_test,
++ outbuf, outbuflen);
++}
++
++static ssize_t lrng_raw_jiffies_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_jiffies_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_jiffies_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_jiffies_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
++
++/************************** Raw IRQ Data Handling ****************************/
++
++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
++
++static u32 boot_raw_irq_test = 0;
++module_param(boot_raw_irq_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_irq_test, "Enable gathering boot time entropy of the first IRQ entropy events");
++
++static struct lrng_testing lrng_raw_irq = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_irq.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_irq.read_wait)
++};
++
++bool lrng_raw_irq_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_irq, value, &boot_raw_irq_test);
++}
++
++static int lrng_raw_irq_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_irq, &boot_raw_irq_test, outbuf,
++ outbuflen);
++}
++
++static ssize_t lrng_raw_irq_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_irq_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_irq_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_irq_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
++
++/************************ Raw IRQFLAGS Data Handling **************************/
++
++#ifdef CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY
++
++static u32 boot_raw_irqflags_test = 0;
++module_param(boot_raw_irqflags_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_irqflags_test, "Enable gathering boot time entropy of the first IRQ flags entropy events");
++
++static struct lrng_testing lrng_raw_irqflags = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_irqflags.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_irqflags.read_wait)
++};
++
++bool lrng_raw_irqflags_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_irqflags, value,
++ &boot_raw_irqflags_test);
++}
++
++static int lrng_raw_irqflags_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_irqflags, &boot_raw_irqflags_test,
++ outbuf, outbuflen);
++}
++
++static ssize_t lrng_raw_irqflags_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_irqflags_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_irqflags_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_irqflags_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
++
++/************************ Raw _RET_IP_ Data Handling **************************/
++
++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
++
++static u32 boot_raw_retip_test = 0;
++module_param(boot_raw_retip_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_retip_test, "Enable gathering boot time entropy of the first return instruction pointer entropy events");
++
++static struct lrng_testing lrng_raw_retip = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_retip.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_retip.read_wait)
++};
++
++bool lrng_raw_retip_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_retip, value, &boot_raw_retip_test);
++}
++
++static int lrng_raw_retip_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_retip, &boot_raw_retip_test,
++ outbuf, outbuflen);
++}
++
++static ssize_t lrng_raw_retip_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_retip_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_retip_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_retip_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
++
++/********************** Raw IRQ register Data Handling ************************/
++
++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
++
++static u32 boot_raw_regs_test = 0;
++module_param(boot_raw_regs_test, uint, 0644);
++MODULE_PARM_DESC(boot_raw_regs_test, "Enable gathering boot time entropy of the first interrupt register entropy events");
++
++static struct lrng_testing lrng_raw_regs = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_regs.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_regs.read_wait)
++};
++
++bool lrng_raw_regs_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_regs, value, &boot_raw_regs_test);
++}
++
++static int lrng_raw_regs_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_regs, &boot_raw_regs_test,
++ outbuf, outbuflen);
++}
++
++static ssize_t lrng_raw_regs_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_regs_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_regs_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_regs_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */
++
++/********************** Raw Entropy Array Data Handling ***********************/
++
++#ifdef CONFIG_LRNG_RAW_ARRAY
++
++static u32 boot_raw_array = 0;
++module_param(boot_raw_array, uint, 0644);
++MODULE_PARM_DESC(boot_raw_array, "Enable gathering boot time raw noise array data of the first entropy events");
++
++static struct lrng_testing lrng_raw_array = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_array.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_array.read_wait)
++};
++
++bool lrng_raw_array_entropy_store(u32 value)
++{
++ return lrng_testing_store(&lrng_raw_array, value, &boot_raw_array);
++}
++
++static int lrng_raw_array_entropy_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_raw_array, &boot_raw_array, outbuf,
++ outbuflen);
++}
++
++static ssize_t lrng_raw_array_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_raw_array_entropy_reader);
++}
++
++static const struct file_operations lrng_raw_array_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_raw_array_read,
++};
++
++#endif /* CONFIG_LRNG_RAW_ARRAY */
++
++/******************** Interrupt Performance Data Handling *********************/
++
++#ifdef CONFIG_LRNG_IRQ_PERF
++
++static u32 boot_irq_perf = 0;
++module_param(boot_irq_perf, uint, 0644);
++MODULE_PARM_DESC(boot_irq_perf, "Enable gathering boot time interrupt performance data of the first entropy events");
++
++static struct lrng_testing lrng_irq_perf = {
++ .rb_reader = 0,
++ .rb_writer = 0,
++ .lock = __SPIN_LOCK_UNLOCKED(lrng_irq_perf.lock),
++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_irq_perf.read_wait)
++};
++
++bool lrng_perf_time(u32 start)
++{
++ return lrng_testing_store(&lrng_irq_perf, random_get_entropy() - start,
++ &boot_irq_perf);
++}
++
++static int lrng_irq_perf_reader(u8 *outbuf, u32 outbuflen)
++{
++ return lrng_testing_reader(&lrng_irq_perf, &boot_irq_perf, outbuf,
++ outbuflen);
++}
++
++static ssize_t lrng_irq_perf_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ return lrng_testing_extract_user(file, to, count, ppos,
++ lrng_irq_perf_reader);
++}
++
++static const struct file_operations lrng_irq_perf_fops = {
++ .owner = THIS_MODULE,
++ .read = lrng_irq_perf_read,
++};
++
++#endif /* CONFIG_LRNG_IRQ_PERF */
++
++/*********************************** ACVT ************************************/
++
++#ifdef CONFIG_LRNG_ACVT_HASH
++
++/* maximum amount of data to be hashed as defined by ACVP */
++#define LRNG_ACVT_MAX_SHA_MSG (65536 >> 3)
++
++/*
++ * As we use static variables to store the data, it is clear that the
++ * test interface is only able to handle single threaded testing. This is
++ * considered to be sufficient for testing. If multi-threaded use of the
++ * ACVT test interface would be performed, the caller would get garbage
++ * but the kernel operation is unaffected by this.
++ */
++static u8 lrng_acvt_hash_data[LRNG_ACVT_MAX_SHA_MSG]
++ __aligned(LRNG_KCAPI_ALIGN);
++static atomic_t lrng_acvt_hash_data_size = ATOMIC_INIT(0);
++static u8 lrng_acvt_hash_digest[LRNG_ATOMIC_DIGEST_SIZE];
++
++static ssize_t lrng_acvt_hash_write(struct file *file, const char __user *buf,
++ size_t nbytes, loff_t *ppos)
++{
++ if (nbytes > LRNG_ACVT_MAX_SHA_MSG)
++ return -EINVAL;
++
++ atomic_set(&lrng_acvt_hash_data_size, (int)nbytes);
++
++ return simple_write_to_buffer(lrng_acvt_hash_data,
++ LRNG_ACVT_MAX_SHA_MSG, ppos, buf, nbytes);
++}
++
++static ssize_t lrng_acvt_hash_read(struct file *file, char __user *to,
++ size_t count, loff_t *ppos)
++{
++ SHASH_DESC_ON_STACK(shash, NULL);
++ const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb;
++ ssize_t ret;
++
++ if (count > LRNG_ATOMIC_DIGEST_SIZE)
++ return -EINVAL;
++
++ ret = crypto_cb->lrng_hash_init(shash, NULL) ?:
++ crypto_cb->lrng_hash_update(shash, lrng_acvt_hash_data,
++ atomic_read_u32(&lrng_acvt_hash_data_size)) ?:
++ crypto_cb->lrng_hash_final(shash, lrng_acvt_hash_digest);
++ if (ret)
++ return ret;
++
++ return simple_read_from_buffer(to, count, ppos, lrng_acvt_hash_digest,
++ sizeof(lrng_acvt_hash_digest));
++}
++
++static const struct file_operations lrng_acvt_hash_fops = {
++ .owner = THIS_MODULE,
++ .open = simple_open,
++ .llseek = default_llseek,
++ .read = lrng_acvt_hash_read,
++ .write = lrng_acvt_hash_write,
++};
++
++#endif /* CONFIG_LRNG_ACVT_DRNG */
++
++/**************************************************************************
++ * Debugfs interface
++ **************************************************************************/
++
++static int __init lrng_raw_init(void)
++{
++ struct dentry *lrng_raw_debugfs_root;
++
++ lrng_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
++
++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_hires", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_hires_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_jiffies", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_jiffies_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_irq", 0400, lrng_raw_debugfs_root,
++ NULL, &lrng_raw_irq_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_irqflags", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_irqflags_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_retip", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_retip_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
++ debugfs_create_file_unsafe("lrng_raw_regs", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_regs_fops);
++#endif
++#ifdef CONFIG_LRNG_RAW_ARRAY
++ debugfs_create_file_unsafe("lrng_raw_array", 0400,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_raw_array_fops);
++#endif
++#ifdef CONFIG_LRNG_IRQ_PERF
++ debugfs_create_file_unsafe("lrng_irq_perf", 0400, lrng_raw_debugfs_root,
++ NULL, &lrng_irq_perf_fops);
++#endif
++#ifdef CONFIG_LRNG_ACVT_HASH
++ debugfs_create_file_unsafe("lrng_acvt_hash", 0600,
++ lrng_raw_debugfs_root, NULL,
++ &lrng_acvt_hash_fops);
++#endif
++
++ return 0;
++}
++
++module_init(lrng_raw_init);
+diff -urN linux-5.15/include/crypto/drbg.h linux-5.15-lrng/include/crypto/drbg.h
+--- linux-5.15/include/crypto/drbg.h 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-lrng/include/crypto/drbg.h 2021-11-29 12:37:31.183279025 +1100
+@@ -278,4 +278,11 @@
+ DRBG_PREFIX3
+ };
+
++extern int drbg_alloc_state(struct drbg_state *drbg);
++extern void drbg_dealloc_state(struct drbg_state *drbg);
++extern void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref,
++ bool *pr);
++extern const struct drbg_core drbg_cores[];
++extern unsigned short drbg_sec_strength(drbg_flag_t flags);
++
+ #endif /* _DRBG_H */
+diff -urN linux-5.15/include/crypto/internal/jitterentropy.h linux-5.15-lrng/include/crypto/internal/jitterentropy.h
+--- linux-5.15/include/crypto/internal/jitterentropy.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/include/crypto/internal/jitterentropy.h 2021-11-29 12:37:52.903278942 +1100
+@@ -0,0 +1,17 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++
++extern void *jent_zalloc(unsigned int len);
++extern void jent_zfree(void *ptr);
++extern int jent_fips_enabled(void);
++extern void jent_panic(char *s);
++extern void jent_memcpy(void *dest, const void *src, unsigned int n);
++extern void jent_get_nstime(__u64 *out);
++
++struct rand_data;
++extern int jent_entropy_init(void);
++extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
++ unsigned int len);
++
++extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
++ unsigned int flags);
++extern void jent_entropy_collector_free(struct rand_data *entropy_collector);
+diff -urN linux-5.15/include/linux/lrng.h linux-5.15-lrng/include/linux/lrng.h
+--- linux-5.15/include/linux/lrng.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-5.15-lrng/include/linux/lrng.h 2021-11-29 12:36:52.113279174 +1100
+@@ -0,0 +1,81 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++/*
++ * Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
++ */
++
++#ifndef _LRNG_H
++#define _LRNG_H
++
++#include <crypto/hash.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++
++/*
++ * struct lrng_crypto_cb - cryptographic callback functions
++ * @lrng_drng_name Name of DRNG
++ * @lrng_hash_name Name of Hash used for reading entropy pool
++ * @lrng_drng_alloc: Allocate DRNG -- the provided integer should be
++ * used for sanity checks.
++ * return: allocated data structure or PTR_ERR on
++ * error
++ * @lrng_drng_dealloc: Deallocate DRNG
++ * @lrng_drng_seed_helper: Seed the DRNG with data of arbitrary length
++ * drng: is pointer to data structure allocated
++ * with lrng_drng_alloc
++ * return: >= 0 on success, < 0 on error
++ * @lrng_drng_generate_helper: Generate random numbers from the DRNG with
++ * arbitrary length
++ * @lrng_hash_alloc: Allocate the hash for reading the entropy pool
++ * return: allocated data structure (NULL is
++ * success too) or ERR_PTR on error
++ * @lrng_hash_dealloc: Deallocate Hash
++ * @lrng_hash_digestsize: Return the digestsize for the used hash to read
++ * out entropy pool
++ * hash: is pointer to data structure allocated
++ * with lrng_hash_alloc
++ * return: size of digest of hash in bytes
++ * @lrng_hash_init: Initialize hash
++ * hash: is pointer to data structure allocated
++ * with lrng_hash_alloc
++ * return: 0 on success, < 0 on error
++ * @lrng_hash_update: Update hash operation
++ * hash: is pointer to data structure allocated
++ * with lrng_hash_alloc
++ * return: 0 on success, < 0 on error
++ * @lrng_hash_final Final hash operation
++ * hash: is pointer to data structure allocated
++ * with lrng_hash_alloc
++ * return: 0 on success, < 0 on error
++ * @lrng_hash_desc_zero Zeroization of hash state buffer
++ *
++ * Assumptions:
++ *
++ * 1. Hash operation will not sleep
++ * 2. The hash' volatile state information is provided with *shash by caller.
++ */
++struct lrng_crypto_cb {
++ const char *(*lrng_drng_name)(void);
++ const char *(*lrng_hash_name)(void);
++ void *(*lrng_drng_alloc)(u32 sec_strength);
++ void (*lrng_drng_dealloc)(void *drng);
++ int (*lrng_drng_seed_helper)(void *drng, const u8 *inbuf, u32 inbuflen);
++ int (*lrng_drng_generate_helper)(void *drng, u8 *outbuf, u32 outbuflen);
++ void *(*lrng_hash_alloc)(void);
++ void (*lrng_hash_dealloc)(void *hash);
++ u32 (*lrng_hash_digestsize)(void *hash);
++ int (*lrng_hash_init)(struct shash_desc *shash, void *hash);
++ int (*lrng_hash_update)(struct shash_desc *shash, const u8 *inbuf,
++ u32 inbuflen);
++ int (*lrng_hash_final)(struct shash_desc *shash, u8 *digest);
++ void (*lrng_hash_desc_zero)(struct shash_desc *shash);
++};
++
++/* Register cryptographic backend */
++#ifdef CONFIG_LRNG_DRNG_SWITCH
++int lrng_set_drng_cb(const struct lrng_crypto_cb *cb);
++#else /* CONFIG_LRNG_DRNG_SWITCH */
++static inline int
++lrng_set_drng_cb(const struct lrng_crypto_cb *cb) { return -EOPNOTSUPP; }
++#endif /* CONFIG_LRNG_DRNG_SWITCH */
++
++#endif /* _LRNG_H */
diff --git a/system/easy-kernel/0250-projectc-5.15-r1.patch b/system/easy-kernel/0250-projectc-5.15-r1.patch
new file mode 100644
index 000000000..3a3bf7420
--- /dev/null
+++ b/system/easy-kernel/0250-projectc-5.15-r1.patch
@@ -0,0 +1,9746 @@
+diff -urN linux-5.15.3/Documentation/admin-guide/kernel-parameters.txt linux-prjc-v5.15-prjc-r1/Documentation/admin-guide/kernel-parameters.txt
+--- linux-5.15.3/Documentation/admin-guide/kernel-parameters.txt 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/Documentation/admin-guide/kernel-parameters.txt 2021-11-20 02:15:12.000000000 +1100
+@@ -4985,6 +4985,12 @@
+ sa1100ir [NET]
+ See drivers/net/irda/sa1100_ir.c.
+
++ sched_timeslice=
++ [KNL] Time slice in ms for Project C BMQ/PDS scheduler.
++ Format: integer 2, 4
++ Default: 4
++ See Documentation/scheduler/sched-BMQ.txt
++
+ sched_verbose [KNL] Enables verbose scheduler debug messages.
+
+ schedstats= [KNL,X86] Enable or disable scheduled statistics.
+diff -urN linux-5.15.3/Documentation/admin-guide/sysctl/kernel.rst linux-prjc-v5.15-prjc-r1/Documentation/admin-guide/sysctl/kernel.rst
+--- linux-5.15.3/Documentation/admin-guide/sysctl/kernel.rst 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/Documentation/admin-guide/sysctl/kernel.rst 2021-11-20 02:15:12.000000000 +1100
+@@ -1542,3 +1542,13 @@
+
+ The softlockup threshold is (``2 * watchdog_thresh``). Setting this
+ tunable to zero will disable lockup detection altogether.
++
++yield_type:
++===========
++
++BMQ/PDS CPU scheduler only. This determines what type of yield calls
++to sched_yield will perform.
++
++ 0 - No yield.
++ 1 - Deboost and requeue task. (default)
++ 2 - Set run queue skip task.
+diff -urN linux-5.15.3/Documentation/scheduler/sched-BMQ.txt linux-prjc-v5.15-prjc-r1/Documentation/scheduler/sched-BMQ.txt
+--- linux-5.15.3/Documentation/scheduler/sched-BMQ.txt 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/Documentation/scheduler/sched-BMQ.txt 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,110 @@
++ BitMap queue CPU Scheduler
++ --------------------------
++
++CONTENT
++========
++
++ Background
++ Design
++ Overview
++ Task policy
++ Priority management
++ BitMap Queue
++ CPU Assignment and Migration
++
++
++Background
++==========
++
++BitMap Queue CPU scheduler, referred to as BMQ from here on, is an evolution
++of previous Priority and Deadline based Skiplist multiple queue scheduler(PDS),
++and inspired by Zircon scheduler. The goal of it is to keep the scheduler code
++simple, while efficiency and scalable for interactive tasks, such as desktop,
++movie playback and gaming etc.
++
++Design
++======
++
++Overview
++--------
++
++BMQ use per CPU run queue design, each CPU(logical) has it's own run queue,
++each CPU is responsible for scheduling the tasks that are putting into it's
++run queue.
++
++The run queue is a set of priority queues. Note that these queues are fifo
++queue for non-rt tasks or priority queue for rt tasks in data structure. See
++BitMap Queue below for details. BMQ is optimized for non-rt tasks in the fact
++that most applications are non-rt tasks. No matter the queue is fifo or
++priority, In each queue is an ordered list of runnable tasks awaiting execution
++and the data structures are the same. When it is time for a new task to run,
++the scheduler simply looks the lowest numbered queueue that contains a task,
++and runs the first task from the head of that queue. And per CPU idle task is
++also in the run queue, so the scheduler can always find a task to run on from
++its run queue.
++
++Each task will assigned the same timeslice(default 4ms) when it is picked to
++start running. Task will be reinserted at the end of the appropriate priority
++queue when it uses its whole timeslice. When the scheduler selects a new task
++from the priority queue it sets the CPU's preemption timer for the remainder of
++the previous timeslice. When that timer fires the scheduler will stop execution
++on that task, select another task and start over again.
++
++If a task blocks waiting for a shared resource then it's taken out of its
++priority queue and is placed in a wait queue for the shared resource. When it
++is unblocked it will be reinserted in the appropriate priority queue of an
++eligible CPU.
++
++Task policy
++-----------
++
++BMQ supports DEADLINE, FIFO, RR, NORMAL, BATCH and IDLE task policy like the
++mainline CFS scheduler. But BMQ is heavy optimized for non-rt task, that's
++NORMAL/BATCH/IDLE policy tasks. Below is the implementation detail of each
++policy.
++
++DEADLINE
++ It is squashed as priority 0 FIFO task.
++
++FIFO/RR
++ All RT tasks share one single priority queue in BMQ run queue designed. The
++complexity of insert operation is O(n). BMQ is not designed for system runs
++with major rt policy tasks.
++
++NORMAL/BATCH/IDLE
++ BATCH and IDLE tasks are treated as the same policy. They compete CPU with
++NORMAL policy tasks, but they just don't boost. To control the priority of
++NORMAL/BATCH/IDLE tasks, simply use nice level.
++
++ISO
++ ISO policy is not supported in BMQ. Please use nice level -20 NORMAL policy
++task instead.
++
++Priority management
++-------------------
++
++RT tasks have priority from 0-99. For non-rt tasks, there are three different
++factors used to determine the effective priority of a task. The effective
++priority being what is used to determine which queue it will be in.
++
++The first factor is simply the task’s static priority. Which is assigned from
++task's nice level, within [-20, 19] in userland's point of view and [0, 39]
++internally.
++
++The second factor is the priority boost. This is a value bounded between
++[-MAX_PRIORITY_ADJ, MAX_PRIORITY_ADJ] used to offset the base priority, it is
++modified by the following cases:
++
++*When a thread has used up its entire timeslice, always deboost its boost by
++increasing by one.
++*When a thread gives up cpu control(voluntary or non-voluntary) to reschedule,
++and its switch-in time(time after last switch and run) below the thredhold
++based on its priority boost, will boost its boost by decreasing by one buti is
++capped at 0 (won’t go negative).
++
++The intent in this system is to ensure that interactive threads are serviced
++quickly. These are usually the threads that interact directly with the user
++and cause user-perceivable latency. These threads usually do little work and
++spend most of their time blocked awaiting another user event. So they get the
++priority boost from unblocking while background threads that do most of the
++processing receive the priority penalty for using their entire timeslice.
+diff -urN linux-5.15.3/fs/proc/base.c linux-prjc-v5.15-prjc-r1/fs/proc/base.c
+--- linux-5.15.3/fs/proc/base.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/fs/proc/base.c 2021-11-20 02:15:12.000000000 +1100
+@@ -480,7 +480,7 @@
+ seq_puts(m, "0 0 0\n");
+ else
+ seq_printf(m, "%llu %llu %lu\n",
+- (unsigned long long)task->se.sum_exec_runtime,
++ (unsigned long long)tsk_seruntime(task),
+ (unsigned long long)task->sched_info.run_delay,
+ task->sched_info.pcount);
+
+diff -urN linux-5.15.3/include/asm-generic/resource.h linux-prjc-v5.15-prjc-r1/include/asm-generic/resource.h
+--- linux-5.15.3/include/asm-generic/resource.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/asm-generic/resource.h 2021-11-20 02:15:12.000000000 +1100
+@@ -23,7 +23,7 @@
+ [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \
+ [RLIMIT_SIGPENDING] = { 0, 0 }, \
+ [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \
+- [RLIMIT_NICE] = { 0, 0 }, \
++ [RLIMIT_NICE] = { 30, 30 }, \
+ [RLIMIT_RTPRIO] = { 0, 0 }, \
+ [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \
+ }
+diff -urN linux-5.15.3/include/linux/sched/deadline.h linux-prjc-v5.15-prjc-r1/include/linux/sched/deadline.h
+--- linux-5.15.3/include/linux/sched/deadline.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/linux/sched/deadline.h 2021-11-20 02:15:12.000000000 +1100
+@@ -1,5 +1,24 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+
++#ifdef CONFIG_SCHED_ALT
++
++static inline int dl_task(struct task_struct *p)
++{
++ return 0;
++}
++
++#ifdef CONFIG_SCHED_BMQ
++#define __tsk_deadline(p) (0UL)
++#endif
++
++#ifdef CONFIG_SCHED_PDS
++#define __tsk_deadline(p) ((((u64) ((p)->prio))<<56) | (p)->deadline)
++#endif
++
++#else
++
++#define __tsk_deadline(p) ((p)->dl.deadline)
++
+ /*
+ * SCHED_DEADLINE tasks has negative priorities, reflecting
+ * the fact that any of them has higher prio than RT and
+@@ -19,6 +38,7 @@
+ {
+ return dl_prio(p->prio);
+ }
++#endif /* CONFIG_SCHED_ALT */
+
+ static inline bool dl_time_before(u64 a, u64 b)
+ {
+diff -urN linux-5.15.3/include/linux/sched/prio.h linux-prjc-v5.15-prjc-r1/include/linux/sched/prio.h
+--- linux-5.15.3/include/linux/sched/prio.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/linux/sched/prio.h 2021-11-20 02:15:12.000000000 +1100
+@@ -18,6 +18,32 @@
+ #define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH)
+ #define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
+
++#ifdef CONFIG_SCHED_ALT
++
++/* Undefine MAX_PRIO and DEFAULT_PRIO */
++#undef MAX_PRIO
++#undef DEFAULT_PRIO
++
++/* +/- priority levels from the base priority */
++#ifdef CONFIG_SCHED_BMQ
++#define MAX_PRIORITY_ADJ (7)
++
++#define MIN_NORMAL_PRIO (MAX_RT_PRIO)
++#define MAX_PRIO (MIN_NORMAL_PRIO + NICE_WIDTH)
++#define DEFAULT_PRIO (MIN_NORMAL_PRIO + NICE_WIDTH / 2)
++#endif
++
++#ifdef CONFIG_SCHED_PDS
++#define MAX_PRIORITY_ADJ (0)
++
++#define MIN_NORMAL_PRIO (128)
++#define NORMAL_PRIO_NUM (64)
++#define MAX_PRIO (MIN_NORMAL_PRIO + NORMAL_PRIO_NUM)
++#define DEFAULT_PRIO (MAX_PRIO - NICE_WIDTH / 2)
++#endif
++
++#endif /* CONFIG_SCHED_ALT */
++
+ /*
+ * Convert user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
+diff -urN linux-5.15.3/include/linux/sched/rt.h linux-prjc-v5.15-prjc-r1/include/linux/sched/rt.h
+--- linux-5.15.3/include/linux/sched/rt.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/linux/sched/rt.h 2021-11-20 02:15:12.000000000 +1100
+@@ -24,8 +24,10 @@
+
+ if (policy == SCHED_FIFO || policy == SCHED_RR)
+ return true;
++#ifndef CONFIG_SCHED_ALT
+ if (policy == SCHED_DEADLINE)
+ return true;
++#endif
+ return false;
+ }
+
+diff -urN linux-5.15.3/include/linux/sched/topology.h linux-prjc-v5.15-prjc-r1/include/linux/sched/topology.h
+--- linux-5.15.3/include/linux/sched/topology.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/linux/sched/topology.h 2021-11-20 02:15:12.000000000 +1100
+@@ -225,7 +225,8 @@
+
+ #endif /* !CONFIG_SMP */
+
+-#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
++#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) && \
++ !defined(CONFIG_SCHED_ALT)
+ extern void rebuild_sched_domains_energy(void);
+ #else
+ static inline void rebuild_sched_domains_energy(void)
+diff -urN linux-5.15.3/include/linux/sched.h linux-prjc-v5.15-prjc-r1/include/linux/sched.h
+--- linux-5.15.3/include/linux/sched.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/include/linux/sched.h 2021-11-20 02:15:12.000000000 +1100
+@@ -748,12 +748,18 @@
+ unsigned int ptrace;
+
+ #ifdef CONFIG_SMP
+- int on_cpu;
+ struct __call_single_node wake_entry;
++#endif
++#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_ALT)
++ int on_cpu;
++#endif
++
++#ifdef CONFIG_SMP
+ #ifdef CONFIG_THREAD_INFO_IN_TASK
+ /* Current CPU: */
+ unsigned int cpu;
+ #endif
++#ifndef CONFIG_SCHED_ALT
+ unsigned int wakee_flips;
+ unsigned long wakee_flip_decay_ts;
+ struct task_struct *last_wakee;
+@@ -767,6 +773,7 @@
+ */
+ int recent_used_cpu;
+ int wake_cpu;
++#endif /* !CONFIG_SCHED_ALT */
+ #endif
+ int on_rq;
+
+@@ -775,6 +782,20 @@
+ int normal_prio;
+ unsigned int rt_priority;
+
++#ifdef CONFIG_SCHED_ALT
++ u64 last_ran;
++ s64 time_slice;
++ int sq_idx;
++ struct list_head sq_node;
++#ifdef CONFIG_SCHED_BMQ
++ int boost_prio;
++#endif /* CONFIG_SCHED_BMQ */
++#ifdef CONFIG_SCHED_PDS
++ u64 deadline;
++#endif /* CONFIG_SCHED_PDS */
++ /* sched_clock time spent running */
++ u64 sched_time;
++#else /* !CONFIG_SCHED_ALT */
+ const struct sched_class *sched_class;
+ struct sched_entity se;
+ struct sched_rt_entity rt;
+@@ -785,6 +806,7 @@
+ unsigned long core_cookie;
+ unsigned int core_occupation;
+ #endif
++#endif /* !CONFIG_SCHED_ALT */
+
+ #ifdef CONFIG_CGROUP_SCHED
+ struct task_group *sched_task_group;
+@@ -1505,6 +1527,15 @@
+ */
+ };
+
++#ifdef CONFIG_SCHED_ALT
++#define tsk_seruntime(t) ((t)->sched_time)
++/* replace the uncertian rt_timeout with 0UL */
++#define tsk_rttimeout(t) (0UL)
++#else /* CFS */
++#define tsk_seruntime(t) ((t)->se.sum_exec_runtime)
++#define tsk_rttimeout(t) ((t)->rt.timeout)
++#endif /* !CONFIG_SCHED_ALT */
++
+ static inline struct pid *task_pid(struct task_struct *task)
+ {
+ return task->thread_pid;
+diff -urN linux-5.15.3/init/Kconfig linux-prjc-v5.15-prjc-r1/init/Kconfig
+--- linux-5.15.3/init/Kconfig 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/init/Kconfig 2021-11-20 02:15:12.000000000 +1100
+@@ -814,9 +814,39 @@
+
+ menu "Scheduler features"
+
++menuconfig SCHED_ALT
++ bool "Alternative CPU Schedulers"
++ default y
++ help
++ This feature enable alternative CPU scheduler"
++
++if SCHED_ALT
++
++choice
++ prompt "Alternative CPU Scheduler"
++ default SCHED_BMQ
++
++config SCHED_BMQ
++ bool "BMQ CPU scheduler"
++ help
++ The BitMap Queue CPU scheduler for excellent interactivity and
++ responsiveness on the desktop and solid scalability on normal
++ hardware and commodity servers.
++
++config SCHED_PDS
++ bool "PDS CPU scheduler"
++ help
++ The Priority and Deadline based Skip list multiple queue CPU
++ Scheduler.
++
++endchoice
++
++endif
++
+ config UCLAMP_TASK
+ bool "Enable utilization clamping for RT/FAIR tasks"
+ depends on CPU_FREQ_GOV_SCHEDUTIL
++ depends on !SCHED_ALT
+ help
+ This feature enables the scheduler to track the clamped utilization
+ of each CPU based on RUNNABLE tasks scheduled on that CPU.
+@@ -902,6 +932,7 @@
+ depends on ARCH_SUPPORTS_NUMA_BALANCING
+ depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY
+ depends on SMP && NUMA && MIGRATION
++ depends on !SCHED_ALT
+ help
+ This option adds support for automatic NUMA aware memory/task placement.
+ The mechanism is quite primitive and is based on migrating memory when
+@@ -994,6 +1025,7 @@
+ depends on CGROUP_SCHED
+ default CGROUP_SCHED
+
++if !SCHED_ALT
+ config CFS_BANDWIDTH
+ bool "CPU bandwidth provisioning for FAIR_GROUP_SCHED"
+ depends on FAIR_GROUP_SCHED
+@@ -1016,6 +1048,7 @@
+ realtime bandwidth for them.
+ See Documentation/scheduler/sched-rt-group.rst for more information.
+
++endif #!SCHED_ALT
+ endif #CGROUP_SCHED
+
+ config UCLAMP_TASK_GROUP
+@@ -1259,6 +1292,7 @@
+
+ config SCHED_AUTOGROUP
+ bool "Automatic process group scheduling"
++ depends on !SCHED_ALT
+ select CGROUPS
+ select CGROUP_SCHED
+ select FAIR_GROUP_SCHED
+diff -urN linux-5.15.3/init/init_task.c linux-prjc-v5.15-prjc-r1/init/init_task.c
+--- linux-5.15.3/init/init_task.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/init/init_task.c 2021-11-20 02:15:12.000000000 +1100
+@@ -75,9 +75,15 @@
+ .stack = init_stack,
+ .usage = REFCOUNT_INIT(2),
+ .flags = PF_KTHREAD,
++#ifdef CONFIG_SCHED_ALT
++ .prio = DEFAULT_PRIO + MAX_PRIORITY_ADJ,
++ .static_prio = DEFAULT_PRIO,
++ .normal_prio = DEFAULT_PRIO + MAX_PRIORITY_ADJ,
++#else
+ .prio = MAX_PRIO - 20,
+ .static_prio = MAX_PRIO - 20,
+ .normal_prio = MAX_PRIO - 20,
++#endif
+ .policy = SCHED_NORMAL,
+ .cpus_ptr = &init_task.cpus_mask,
+ .user_cpus_ptr = NULL,
+@@ -88,6 +94,17 @@
+ .restart_block = {
+ .fn = do_no_restart_syscall,
+ },
++#ifdef CONFIG_SCHED_ALT
++ .sq_node = LIST_HEAD_INIT(init_task.sq_node),
++#ifdef CONFIG_SCHED_BMQ
++ .boost_prio = 0,
++ .sq_idx = 15,
++#endif
++#ifdef CONFIG_SCHED_PDS
++ .deadline = 0,
++#endif
++ .time_slice = HZ,
++#else
+ .se = {
+ .group_node = LIST_HEAD_INIT(init_task.se.group_node),
+ },
+@@ -95,6 +112,7 @@
+ .run_list = LIST_HEAD_INIT(init_task.rt.run_list),
+ .time_slice = RR_TIMESLICE,
+ },
++#endif
+ .tasks = LIST_HEAD_INIT(init_task.tasks),
+ #ifdef CONFIG_SMP
+ .pushable_tasks = PLIST_NODE_INIT(init_task.pushable_tasks, MAX_PRIO),
+diff -urN linux-5.15.3/kernel/Kconfig.preempt linux-prjc-v5.15-prjc-r1/kernel/Kconfig.preempt
+--- linux-5.15.3/kernel/Kconfig.preempt 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/Kconfig.preempt 2021-11-20 02:15:12.000000000 +1100
+@@ -102,7 +102,7 @@
+
+ config SCHED_CORE
+ bool "Core Scheduling for SMT"
+- depends on SCHED_SMT
++ depends on SCHED_SMT && !SCHED_ALT
+ help
+ This option permits Core Scheduling, a means of coordinated task
+ selection across SMT siblings. When enabled -- see
+diff -urN linux-5.15.3/kernel/cgroup/cpuset.c linux-prjc-v5.15-prjc-r1/kernel/cgroup/cpuset.c
+--- linux-5.15.3/kernel/cgroup/cpuset.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/cgroup/cpuset.c 2021-11-20 02:15:12.000000000 +1100
+@@ -664,7 +664,7 @@
+ return ret;
+ }
+
+-#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP) && !defined(CONFIG_SCHED_ALT)
+ /*
+ * Helper routine for generate_sched_domains().
+ * Do cpusets a, b have overlapping effective cpus_allowed masks?
+@@ -1060,7 +1060,7 @@
+ /* Have scheduler rebuild the domains */
+ partition_and_rebuild_sched_domains(ndoms, doms, attr);
+ }
+-#else /* !CONFIG_SMP */
++#else /* !CONFIG_SMP || CONFIG_SCHED_ALT */
+ static void rebuild_sched_domains_locked(void)
+ {
+ }
+diff -urN linux-5.15.3/kernel/delayacct.c linux-prjc-v5.15-prjc-r1/kernel/delayacct.c
+--- linux-5.15.3/kernel/delayacct.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/delayacct.c 2021-11-20 02:15:12.000000000 +1100
+@@ -139,7 +139,7 @@
+ */
+ t1 = tsk->sched_info.pcount;
+ t2 = tsk->sched_info.run_delay;
+- t3 = tsk->se.sum_exec_runtime;
++ t3 = tsk_seruntime(tsk);
+
+ d->cpu_count += t1;
+
+diff -urN linux-5.15.3/kernel/exit.c linux-prjc-v5.15-prjc-r1/kernel/exit.c
+--- linux-5.15.3/kernel/exit.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/exit.c 2021-11-20 02:15:12.000000000 +1100
+@@ -122,7 +122,7 @@
+ sig->curr_target = next_thread(tsk);
+ }
+
+- add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
++ add_device_randomness((const void*) &tsk_seruntime(tsk),
+ sizeof(unsigned long long));
+
+ /*
+@@ -143,7 +143,7 @@
+ sig->inblock += task_io_get_inblock(tsk);
+ sig->oublock += task_io_get_oublock(tsk);
+ task_io_accounting_add(&sig->ioac, &tsk->ioac);
+- sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
++ sig->sum_sched_runtime += tsk_seruntime(tsk);
+ sig->nr_threads--;
+ __unhash_process(tsk, group_dead);
+ write_sequnlock(&sig->stats_lock);
+diff -urN linux-5.15.3/kernel/livepatch/transition.c linux-prjc-v5.15-prjc-r1/kernel/livepatch/transition.c
+--- linux-5.15.3/kernel/livepatch/transition.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/livepatch/transition.c 2021-11-20 02:15:12.000000000 +1100
+@@ -307,7 +307,11 @@
+ */
+ rq = task_rq_lock(task, &flags);
+
++#ifdef CONFIG_SCHED_ALT
++ if (task_running(task) && task != current) {
++#else
+ if (task_running(rq, task) && task != current) {
++#endif
+ snprintf(err_buf, STACK_ERR_BUF_SIZE,
+ "%s: %s:%d is running\n", __func__, task->comm,
+ task->pid);
+diff -urN linux-5.15.3/kernel/locking/rtmutex.c linux-prjc-v5.15-prjc-r1/kernel/locking/rtmutex.c
+--- linux-5.15.3/kernel/locking/rtmutex.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/locking/rtmutex.c 2021-11-20 02:15:12.000000000 +1100
+@@ -298,21 +298,25 @@
+ waiter_update_prio(struct rt_mutex_waiter *waiter, struct task_struct *task)
+ {
+ waiter->prio = __waiter_prio(task);
+- waiter->deadline = task->dl.deadline;
++ waiter->deadline = __tsk_deadline(task);
+ }
+
+ /*
+ * Only use with rt_mutex_waiter_{less,equal}()
+ */
+ #define task_to_waiter(p) \
+- &(struct rt_mutex_waiter){ .prio = __waiter_prio(p), .deadline = (p)->dl.deadline }
++ &(struct rt_mutex_waiter){ .prio = __waiter_prio(p), .deadline = __tsk_deadline(p) }
+
+ static __always_inline int rt_mutex_waiter_less(struct rt_mutex_waiter *left,
+ struct rt_mutex_waiter *right)
+ {
++#ifdef CONFIG_SCHED_PDS
++ return (left->deadline < right->deadline);
++#else
+ if (left->prio < right->prio)
+ return 1;
+
++#ifndef CONFIG_SCHED_BMQ
+ /*
+ * If both waiters have dl_prio(), we check the deadlines of the
+ * associated tasks.
+@@ -321,16 +325,22 @@
+ */
+ if (dl_prio(left->prio))
+ return dl_time_before(left->deadline, right->deadline);
++#endif
+
+ return 0;
++#endif
+ }
+
+ static __always_inline int rt_mutex_waiter_equal(struct rt_mutex_waiter *left,
+ struct rt_mutex_waiter *right)
+ {
++#ifdef CONFIG_SCHED_PDS
++ return (left->deadline == right->deadline);
++#else
+ if (left->prio != right->prio)
+ return 0;
+
++#ifndef CONFIG_SCHED_BMQ
+ /*
+ * If both waiters have dl_prio(), we check the deadlines of the
+ * associated tasks.
+@@ -339,8 +349,10 @@
+ */
+ if (dl_prio(left->prio))
+ return left->deadline == right->deadline;
++#endif
+
+ return 1;
++#endif
+ }
+
+ static inline bool rt_mutex_steal(struct rt_mutex_waiter *waiter,
+diff -urN linux-5.15.3/kernel/sched/Makefile linux-prjc-v5.15-prjc-r1/kernel/sched/Makefile
+--- linux-5.15.3/kernel/sched/Makefile 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/Makefile 2021-11-20 02:15:12.000000000 +1100
+@@ -22,14 +22,21 @@
+ CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
+ endif
+
+-obj-y += core.o loadavg.o clock.o cputime.o
+-obj-y += idle.o fair.o rt.o deadline.o
+-obj-y += wait.o wait_bit.o swait.o completion.o
+-
+-obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o topology.o stop_task.o pelt.o
++ifdef CONFIG_SCHED_ALT
++obj-y += alt_core.o
++obj-$(CONFIG_SCHED_DEBUG) += alt_debug.o
++else
++obj-y += core.o
++obj-y += fair.o rt.o deadline.o
++obj-$(CONFIG_SMP) += cpudeadline.o stop_task.o
+ obj-$(CONFIG_SCHED_AUTOGROUP) += autogroup.o
+-obj-$(CONFIG_SCHEDSTATS) += stats.o
++endif
+ obj-$(CONFIG_SCHED_DEBUG) += debug.o
++obj-y += loadavg.o clock.o cputime.o
++obj-y += idle.o
++obj-y += wait.o wait_bit.o swait.o completion.o
++obj-$(CONFIG_SMP) += cpupri.o pelt.o topology.o
++obj-$(CONFIG_SCHEDSTATS) += stats.o
+ obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
+ obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+ obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
+diff -urN linux-5.15.3/kernel/sched/alt_core.c linux-prjc-v5.15-prjc-r1/kernel/sched/alt_core.c
+--- linux-5.15.3/kernel/sched/alt_core.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/alt_core.c 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,7627 @@
++/*
++ * kernel/sched/alt_core.c
++ *
++ * Core alternative kernel scheduler code and related syscalls
++ *
++ * Copyright (C) 1991-2002 Linus Torvalds
++ *
++ * 2009-08-13 Brainfuck deadline scheduling policy by Con Kolivas deletes
++ * a whole lot of those previous things.
++ * 2017-09-06 Priority and Deadline based Skip list multiple queue kernel
++ * scheduler by Alfred Chen.
++ * 2019-02-20 BMQ(BitMap Queue) kernel scheduler by Alfred Chen.
++ */
++#define CREATE_TRACE_POINTS
++#include <trace/events/sched.h>
++#undef CREATE_TRACE_POINTS
++
++#include "sched.h"
++
++#include <linux/sched/rt.h>
++
++#include <linux/context_tracking.h>
++#include <linux/compat.h>
++#include <linux/blkdev.h>
++#include <linux/delayacct.h>
++#include <linux/freezer.h>
++#include <linux/init_task.h>
++#include <linux/kprobes.h>
++#include <linux/mmu_context.h>
++#include <linux/nmi.h>
++#include <linux/profile.h>
++#include <linux/rcupdate_wait.h>
++#include <linux/security.h>
++#include <linux/syscalls.h>
++#include <linux/wait_bit.h>
++
++#include <linux/kcov.h>
++#include <linux/scs.h>
++
++#include <asm/switch_to.h>
++
++#include "../workqueue_internal.h"
++#include "../../fs/io-wq.h"
++#include "../smpboot.h"
++
++#include "pelt.h"
++#include "smp.h"
++
++/*
++ * Export tracepoints that act as a bare tracehook (ie: have no trace event
++ * associated with them) to allow external modules to probe them.
++ */
++EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp);
++
++#ifdef CONFIG_SCHED_DEBUG
++#define sched_feat(x) (1)
++/*
++ * Print a warning if need_resched is set for the given duration (if
++ * LATENCY_WARN is enabled).
++ *
++ * If sysctl_resched_latency_warn_once is set, only one warning will be shown
++ * per boot.
++ */
++__read_mostly int sysctl_resched_latency_warn_ms = 100;
++__read_mostly int sysctl_resched_latency_warn_once = 1;
++#else
++#define sched_feat(x) (0)
++#endif /* CONFIG_SCHED_DEBUG */
++
++#define ALT_SCHED_VERSION "v5.15-r1"
++
++/* rt_prio(prio) defined in include/linux/sched/rt.h */
++#define rt_task(p) rt_prio((p)->prio)
++#define rt_policy(policy) ((policy) == SCHED_FIFO || (policy) == SCHED_RR)
++#define task_has_rt_policy(p) (rt_policy((p)->policy))
++
++#define STOP_PRIO (MAX_RT_PRIO - 1)
++
++/* Default time slice is 4 in ms, can be set via kernel parameter "sched_timeslice" */
++u64 sched_timeslice_ns __read_mostly = (4 << 20);
++
++static inline void requeue_task(struct task_struct *p, struct rq *rq);
++
++#ifdef CONFIG_SCHED_BMQ
++#include "bmq.h"
++#endif
++#ifdef CONFIG_SCHED_PDS
++#include "pds.h"
++#endif
++
++static int __init sched_timeslice(char *str)
++{
++ int timeslice_ms;
++
++ get_option(&str, &timeslice_ms);
++ if (2 != timeslice_ms)
++ timeslice_ms = 4;
++ sched_timeslice_ns = timeslice_ms << 20;
++ sched_timeslice_imp(timeslice_ms);
++
++ return 0;
++}
++early_param("sched_timeslice", sched_timeslice);
++
++/* Reschedule if less than this many μs left */
++#define RESCHED_NS (100 << 10)
++
++/**
++ * sched_yield_type - Choose what sort of yield sched_yield will perform.
++ * 0: No yield.
++ * 1: Deboost and requeue task. (default)
++ * 2: Set rq skip task.
++ */
++int sched_yield_type __read_mostly = 1;
++
++#ifdef CONFIG_SMP
++static cpumask_t sched_rq_pending_mask ____cacheline_aligned_in_smp;
++
++DEFINE_PER_CPU(cpumask_t [NR_CPU_AFFINITY_LEVELS], sched_cpu_topo_masks);
++DEFINE_PER_CPU(cpumask_t *, sched_cpu_llc_mask);
++DEFINE_PER_CPU(cpumask_t *, sched_cpu_topo_end_mask);
++
++#ifdef CONFIG_SCHED_SMT
++DEFINE_STATIC_KEY_FALSE(sched_smt_present);
++EXPORT_SYMBOL_GPL(sched_smt_present);
++#endif
++
++/*
++ * Keep a unique ID per domain (we use the first CPUs number in the cpumask of
++ * the domain), this allows us to quickly tell if two cpus are in the same cache
++ * domain, see cpus_share_cache().
++ */
++DEFINE_PER_CPU(int, sd_llc_id);
++#endif /* CONFIG_SMP */
++
++static DEFINE_MUTEX(sched_hotcpu_mutex);
++
++DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
++
++#ifndef prepare_arch_switch
++# define prepare_arch_switch(next) do { } while (0)
++#endif
++#ifndef finish_arch_post_lock_switch
++# define finish_arch_post_lock_switch() do { } while (0)
++#endif
++
++#ifdef CONFIG_SCHED_SMT
++static cpumask_t sched_sg_idle_mask ____cacheline_aligned_in_smp;
++#endif
++static cpumask_t sched_rq_watermark[SCHED_BITS] ____cacheline_aligned_in_smp;
++
++/* sched_queue related functions */
++static inline void sched_queue_init(struct sched_queue *q)
++{
++ int i;
++
++ bitmap_zero(q->bitmap, SCHED_BITS);
++ for(i = 0; i < SCHED_BITS; i++)
++ INIT_LIST_HEAD(&q->heads[i]);
++}
++
++/*
++ * Init idle task and put into queue structure of rq
++ * IMPORTANT: may be called multiple times for a single cpu
++ */
++static inline void sched_queue_init_idle(struct sched_queue *q,
++ struct task_struct *idle)
++{
++ idle->sq_idx = IDLE_TASK_SCHED_PRIO;
++ INIT_LIST_HEAD(&q->heads[idle->sq_idx]);
++ list_add(&idle->sq_node, &q->heads[idle->sq_idx]);
++}
++
++/* water mark related functions */
++static inline void update_sched_rq_watermark(struct rq *rq)
++{
++ unsigned long watermark = find_first_bit(rq->queue.bitmap, SCHED_QUEUE_BITS);
++ unsigned long last_wm = rq->watermark;
++ unsigned long i;
++ int cpu;
++
++ if (watermark == last_wm)
++ return;
++
++ rq->watermark = watermark;
++ cpu = cpu_of(rq);
++ if (watermark < last_wm) {
++ for (i = last_wm; i > watermark; i--)
++ cpumask_clear_cpu(cpu, sched_rq_watermark + SCHED_BITS - 1 - i);
++#ifdef CONFIG_SCHED_SMT
++ if (static_branch_likely(&sched_smt_present) &&
++ IDLE_TASK_SCHED_PRIO == last_wm)
++ cpumask_andnot(&sched_sg_idle_mask,
++ &sched_sg_idle_mask, cpu_smt_mask(cpu));
++#endif
++ return;
++ }
++ /* last_wm < watermark */
++ for (i = watermark; i > last_wm; i--)
++ cpumask_set_cpu(cpu, sched_rq_watermark + SCHED_BITS - 1 - i);
++#ifdef CONFIG_SCHED_SMT
++ if (static_branch_likely(&sched_smt_present) &&
++ IDLE_TASK_SCHED_PRIO == watermark) {
++ cpumask_t tmp;
++
++ cpumask_and(&tmp, cpu_smt_mask(cpu), sched_rq_watermark);
++ if (cpumask_equal(&tmp, cpu_smt_mask(cpu)))
++ cpumask_or(&sched_sg_idle_mask,
++ &sched_sg_idle_mask, cpu_smt_mask(cpu));
++ }
++#endif
++}
++
++/*
++ * This routine assume that the idle task always in queue
++ */
++static inline struct task_struct *sched_rq_first_task(struct rq *rq)
++{
++ unsigned long idx = find_first_bit(rq->queue.bitmap, SCHED_QUEUE_BITS);
++ const struct list_head *head = &rq->queue.heads[sched_prio2idx(idx, rq)];
++
++ return list_first_entry(head, struct task_struct, sq_node);
++}
++
++static inline struct task_struct *
++sched_rq_next_task(struct task_struct *p, struct rq *rq)
++{
++ unsigned long idx = p->sq_idx;
++ struct list_head *head = &rq->queue.heads[idx];
++
++ if (list_is_last(&p->sq_node, head)) {
++ idx = find_next_bit(rq->queue.bitmap, SCHED_QUEUE_BITS,
++ sched_idx2prio(idx, rq) + 1);
++ head = &rq->queue.heads[sched_prio2idx(idx, rq)];
++
++ return list_first_entry(head, struct task_struct, sq_node);
++ }
++
++ return list_next_entry(p, sq_node);
++}
++
++static inline struct task_struct *rq_runnable_task(struct rq *rq)
++{
++ struct task_struct *next = sched_rq_first_task(rq);
++
++ if (unlikely(next == rq->skip))
++ next = sched_rq_next_task(next, rq);
++
++ return next;
++}
++
++/*
++ * Serialization rules:
++ *
++ * Lock order:
++ *
++ * p->pi_lock
++ * rq->lock
++ * hrtimer_cpu_base->lock (hrtimer_start() for bandwidth controls)
++ *
++ * rq1->lock
++ * rq2->lock where: rq1 < rq2
++ *
++ * Regular state:
++ *
++ * Normal scheduling state is serialized by rq->lock. __schedule() takes the
++ * local CPU's rq->lock, it optionally removes the task from the runqueue and
++ * always looks at the local rq data structures to find the most eligible task
++ * to run next.
++ *
++ * Task enqueue is also under rq->lock, possibly taken from another CPU.
++ * Wakeups from another LLC domain might use an IPI to transfer the enqueue to
++ * the local CPU to avoid bouncing the runqueue state around [ see
++ * ttwu_queue_wakelist() ]
++ *
++ * Task wakeup, specifically wakeups that involve migration, are horribly
++ * complicated to avoid having to take two rq->locks.
++ *
++ * Special state:
++ *
++ * System-calls and anything external will use task_rq_lock() which acquires
++ * both p->pi_lock and rq->lock. As a consequence the state they change is
++ * stable while holding either lock:
++ *
++ * - sched_setaffinity()/
++ * set_cpus_allowed_ptr(): p->cpus_ptr, p->nr_cpus_allowed
++ * - set_user_nice(): p->se.load, p->*prio
++ * - __sched_setscheduler(): p->sched_class, p->policy, p->*prio,
++ * p->se.load, p->rt_priority,
++ * p->dl.dl_{runtime, deadline, period, flags, bw, density}
++ * - sched_setnuma(): p->numa_preferred_nid
++ * - sched_move_task()/
++ * cpu_cgroup_fork(): p->sched_task_group
++ * - uclamp_update_active() p->uclamp*
++ *
++ * p->state <- TASK_*:
++ *
++ * is changed locklessly using set_current_state(), __set_current_state() or
++ * set_special_state(), see their respective comments, or by
++ * try_to_wake_up(). This latter uses p->pi_lock to serialize against
++ * concurrent self.
++ *
++ * p->on_rq <- { 0, 1 = TASK_ON_RQ_QUEUED, 2 = TASK_ON_RQ_MIGRATING }:
++ *
++ * is set by activate_task() and cleared by deactivate_task(), under
++ * rq->lock. Non-zero indicates the task is runnable, the special
++ * ON_RQ_MIGRATING state is used for migration without holding both
++ * rq->locks. It indicates task_cpu() is not stable, see task_rq_lock().
++ *
++ * p->on_cpu <- { 0, 1 }:
++ *
++ * is set by prepare_task() and cleared by finish_task() such that it will be
++ * set before p is scheduled-in and cleared after p is scheduled-out, both
++ * under rq->lock. Non-zero indicates the task is running on its CPU.
++ *
++ * [ The astute reader will observe that it is possible for two tasks on one
++ * CPU to have ->on_cpu = 1 at the same time. ]
++ *
++ * task_cpu(p): is changed by set_task_cpu(), the rules are:
++ *
++ * - Don't call set_task_cpu() on a blocked task:
++ *
++ * We don't care what CPU we're not running on, this simplifies hotplug,
++ * the CPU assignment of blocked tasks isn't required to be valid.
++ *
++ * - for try_to_wake_up(), called under p->pi_lock:
++ *
++ * This allows try_to_wake_up() to only take one rq->lock, see its comment.
++ *
++ * - for migration called under rq->lock:
++ * [ see task_on_rq_migrating() in task_rq_lock() ]
++ *
++ * o move_queued_task()
++ * o detach_task()
++ *
++ * - for migration called under double_rq_lock():
++ *
++ * o __migrate_swap_task()
++ * o push_rt_task() / pull_rt_task()
++ * o push_dl_task() / pull_dl_task()
++ * o dl_task_offline_migration()
++ *
++ */
++
++/*
++ * Context: p->pi_lock
++ */
++static inline struct rq
++*__task_access_lock(struct task_struct *p, raw_spinlock_t **plock)
++{
++ struct rq *rq;
++ for (;;) {
++ rq = task_rq(p);
++ if (p->on_cpu || task_on_rq_queued(p)) {
++ raw_spin_lock(&rq->lock);
++ if (likely((p->on_cpu || task_on_rq_queued(p))
++ && rq == task_rq(p))) {
++ *plock = &rq->lock;
++ return rq;
++ }
++ raw_spin_unlock(&rq->lock);
++ } else if (task_on_rq_migrating(p)) {
++ do {
++ cpu_relax();
++ } while (unlikely(task_on_rq_migrating(p)));
++ } else {
++ *plock = NULL;
++ return rq;
++ }
++ }
++}
++
++static inline void
++__task_access_unlock(struct task_struct *p, raw_spinlock_t *lock)
++{
++ if (NULL != lock)
++ raw_spin_unlock(lock);
++}
++
++static inline struct rq
++*task_access_lock_irqsave(struct task_struct *p, raw_spinlock_t **plock,
++ unsigned long *flags)
++{
++ struct rq *rq;
++ for (;;) {
++ rq = task_rq(p);
++ if (p->on_cpu || task_on_rq_queued(p)) {
++ raw_spin_lock_irqsave(&rq->lock, *flags);
++ if (likely((p->on_cpu || task_on_rq_queued(p))
++ && rq == task_rq(p))) {
++ *plock = &rq->lock;
++ return rq;
++ }
++ raw_spin_unlock_irqrestore(&rq->lock, *flags);
++ } else if (task_on_rq_migrating(p)) {
++ do {
++ cpu_relax();
++ } while (unlikely(task_on_rq_migrating(p)));
++ } else {
++ raw_spin_lock_irqsave(&p->pi_lock, *flags);
++ if (likely(!p->on_cpu && !p->on_rq &&
++ rq == task_rq(p))) {
++ *plock = &p->pi_lock;
++ return rq;
++ }
++ raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
++ }
++ }
++}
++
++static inline void
++task_access_unlock_irqrestore(struct task_struct *p, raw_spinlock_t *lock,
++ unsigned long *flags)
++{
++ raw_spin_unlock_irqrestore(lock, *flags);
++}
++
++/*
++ * __task_rq_lock - lock the rq @p resides on.
++ */
++struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf)
++ __acquires(rq->lock)
++{
++ struct rq *rq;
++
++ lockdep_assert_held(&p->pi_lock);
++
++ for (;;) {
++ rq = task_rq(p);
++ raw_spin_lock(&rq->lock);
++ if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
++ return rq;
++ raw_spin_unlock(&rq->lock);
++
++ while (unlikely(task_on_rq_migrating(p)))
++ cpu_relax();
++ }
++}
++
++/*
++ * task_rq_lock - lock p->pi_lock and lock the rq @p resides on.
++ */
++struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
++ __acquires(p->pi_lock)
++ __acquires(rq->lock)
++{
++ struct rq *rq;
++
++ for (;;) {
++ raw_spin_lock_irqsave(&p->pi_lock, rf->flags);
++ rq = task_rq(p);
++ raw_spin_lock(&rq->lock);
++ /*
++ * move_queued_task() task_rq_lock()
++ *
++ * ACQUIRE (rq->lock)
++ * [S] ->on_rq = MIGRATING [L] rq = task_rq()
++ * WMB (__set_task_cpu()) ACQUIRE (rq->lock);
++ * [S] ->cpu = new_cpu [L] task_rq()
++ * [L] ->on_rq
++ * RELEASE (rq->lock)
++ *
++ * If we observe the old CPU in task_rq_lock(), the acquire of
++ * the old rq->lock will fully serialize against the stores.
++ *
++ * If we observe the new CPU in task_rq_lock(), the address
++ * dependency headed by '[L] rq = task_rq()' and the acquire
++ * will pair with the WMB to ensure we then also see migrating.
++ */
++ if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
++ return rq;
++ }
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
++
++ while (unlikely(task_on_rq_migrating(p)))
++ cpu_relax();
++ }
++}
++
++static inline void
++rq_lock_irqsave(struct rq *rq, struct rq_flags *rf)
++ __acquires(rq->lock)
++{
++ raw_spin_lock_irqsave(&rq->lock, rf->flags);
++}
++
++static inline void
++rq_unlock_irqrestore(struct rq *rq, struct rq_flags *rf)
++ __releases(rq->lock)
++{
++ raw_spin_unlock_irqrestore(&rq->lock, rf->flags);
++}
++
++void raw_spin_rq_lock_nested(struct rq *rq, int subclass)
++{
++ raw_spinlock_t *lock;
++
++ /* Matches synchronize_rcu() in __sched_core_enable() */
++ preempt_disable();
++
++ for (;;) {
++ lock = __rq_lockp(rq);
++ raw_spin_lock_nested(lock, subclass);
++ if (likely(lock == __rq_lockp(rq))) {
++ /* preempt_count *MUST* be > 1 */
++ preempt_enable_no_resched();
++ return;
++ }
++ raw_spin_unlock(lock);
++ }
++}
++
++void raw_spin_rq_unlock(struct rq *rq)
++{
++ raw_spin_unlock(rq_lockp(rq));
++}
++
++/*
++ * RQ-clock updating methods:
++ */
++
++static void update_rq_clock_task(struct rq *rq, s64 delta)
++{
++/*
++ * In theory, the compile should just see 0 here, and optimize out the call
++ * to sched_rt_avg_update. But I don't trust it...
++ */
++ s64 __maybe_unused steal = 0, irq_delta = 0;
++
++#ifdef CONFIG_IRQ_TIME_ACCOUNTING
++ irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time;
++
++ /*
++ * Since irq_time is only updated on {soft,}irq_exit, we might run into
++ * this case when a previous update_rq_clock() happened inside a
++ * {soft,}irq region.
++ *
++ * When this happens, we stop ->clock_task and only update the
++ * prev_irq_time stamp to account for the part that fit, so that a next
++ * update will consume the rest. This ensures ->clock_task is
++ * monotonic.
++ *
++ * It does however cause some slight miss-attribution of {soft,}irq
++ * time, a more accurate solution would be to update the irq_time using
++ * the current rq->clock timestamp, except that would require using
++ * atomic ops.
++ */
++ if (irq_delta > delta)
++ irq_delta = delta;
++
++ rq->prev_irq_time += irq_delta;
++ delta -= irq_delta;
++#endif
++#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
++ if (static_key_false((&paravirt_steal_rq_enabled))) {
++ steal = paravirt_steal_clock(cpu_of(rq));
++ steal -= rq->prev_steal_time_rq;
++
++ if (unlikely(steal > delta))
++ steal = delta;
++
++ rq->prev_steal_time_rq += steal;
++ delta -= steal;
++ }
++#endif
++
++ rq->clock_task += delta;
++
++#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
++ if ((irq_delta + steal))
++ update_irq_load_avg(rq, irq_delta + steal);
++#endif
++}
++
++static inline void update_rq_clock(struct rq *rq)
++{
++ s64 delta = sched_clock_cpu(cpu_of(rq)) - rq->clock;
++
++ if (unlikely(delta <= 0))
++ return;
++ rq->clock += delta;
++ update_rq_time_edge(rq);
++ update_rq_clock_task(rq, delta);
++}
++
++/*
++ * RQ Load update routine
++ */
++#define RQ_LOAD_HISTORY_BITS (sizeof(s32) * 8ULL)
++#define RQ_UTIL_SHIFT (8)
++#define RQ_LOAD_HISTORY_TO_UTIL(l) (((l) >> (RQ_LOAD_HISTORY_BITS - 1 - RQ_UTIL_SHIFT)) & 0xff)
++
++#define LOAD_BLOCK(t) ((t) >> 17)
++#define LOAD_HALF_BLOCK(t) ((t) >> 16)
++#define BLOCK_MASK(t) ((t) & ((0x01 << 18) - 1))
++#define LOAD_BLOCK_BIT(b) (1UL << (RQ_LOAD_HISTORY_BITS - 1 - (b)))
++#define CURRENT_LOAD_BIT LOAD_BLOCK_BIT(0)
++
++static inline void rq_load_update(struct rq *rq)
++{
++ u64 time = rq->clock;
++ u64 delta = min(LOAD_BLOCK(time) - LOAD_BLOCK(rq->load_stamp),
++ RQ_LOAD_HISTORY_BITS - 1);
++ u64 prev = !!(rq->load_history & CURRENT_LOAD_BIT);
++ u64 curr = !!rq->nr_running;
++
++ if (delta) {
++ rq->load_history = rq->load_history >> delta;
++
++ if (delta < RQ_UTIL_SHIFT) {
++ rq->load_block += (~BLOCK_MASK(rq->load_stamp)) * prev;
++ if (!!LOAD_HALF_BLOCK(rq->load_block) ^ curr)
++ rq->load_history ^= LOAD_BLOCK_BIT(delta);
++ }
++
++ rq->load_block = BLOCK_MASK(time) * prev;
++ } else {
++ rq->load_block += (time - rq->load_stamp) * prev;
++ }
++ if (prev ^ curr)
++ rq->load_history ^= CURRENT_LOAD_BIT;
++ rq->load_stamp = time;
++}
++
++unsigned long rq_load_util(struct rq *rq, unsigned long max)
++{
++ return RQ_LOAD_HISTORY_TO_UTIL(rq->load_history) * (max >> RQ_UTIL_SHIFT);
++}
++
++#ifdef CONFIG_SMP
++unsigned long sched_cpu_util(int cpu, unsigned long max)
++{
++ return rq_load_util(cpu_rq(cpu), max);
++}
++#endif /* CONFIG_SMP */
++
++#ifdef CONFIG_CPU_FREQ
++/**
++ * cpufreq_update_util - Take a note about CPU utilization changes.
++ * @rq: Runqueue to carry out the update for.
++ * @flags: Update reason flags.
++ *
++ * This function is called by the scheduler on the CPU whose utilization is
++ * being updated.
++ *
++ * It can only be called from RCU-sched read-side critical sections.
++ *
++ * The way cpufreq is currently arranged requires it to evaluate the CPU
++ * performance state (frequency/voltage) on a regular basis to prevent it from
++ * being stuck in a completely inadequate performance level for too long.
++ * That is not guaranteed to happen if the updates are only triggered from CFS
++ * and DL, though, because they may not be coming in if only RT tasks are
++ * active all the time (or there are RT tasks only).
++ *
++ * As a workaround for that issue, this function is called periodically by the
++ * RT sched class to trigger extra cpufreq updates to prevent it from stalling,
++ * but that really is a band-aid. Going forward it should be replaced with
++ * solutions targeted more specifically at RT tasks.
++ */
++static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
++{
++ struct update_util_data *data;
++
++#ifdef CONFIG_SMP
++ rq_load_update(rq);
++#endif
++ data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
++ cpu_of(rq)));
++ if (data)
++ data->func(data, rq_clock(rq), flags);
++}
++#else
++static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
++{
++#ifdef CONFIG_SMP
++ rq_load_update(rq);
++#endif
++}
++#endif /* CONFIG_CPU_FREQ */
++
++#ifdef CONFIG_NO_HZ_FULL
++/*
++ * Tick may be needed by tasks in the runqueue depending on their policy and
++ * requirements. If tick is needed, lets send the target an IPI to kick it out
++ * of nohz mode if necessary.
++ */
++static inline void sched_update_tick_dependency(struct rq *rq)
++{
++ int cpu = cpu_of(rq);
++
++ if (!tick_nohz_full_cpu(cpu))
++ return;
++
++ if (rq->nr_running < 2)
++ tick_nohz_dep_clear_cpu(cpu, TICK_DEP_BIT_SCHED);
++ else
++ tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED);
++}
++#else /* !CONFIG_NO_HZ_FULL */
++static inline void sched_update_tick_dependency(struct rq *rq) { }
++#endif
++
++bool sched_task_on_rq(struct task_struct *p)
++{
++ return task_on_rq_queued(p);
++}
++
++/*
++ * Add/Remove/Requeue task to/from the runqueue routines
++ * Context: rq->lock
++ */
++#define __SCHED_DEQUEUE_TASK(p, rq, flags, func) \
++ psi_dequeue(p, flags & DEQUEUE_SLEEP); \
++ sched_info_dequeue(rq, p); \
++ \
++ list_del(&p->sq_node); \
++ if (list_empty(&rq->queue.heads[p->sq_idx])) { \
++ clear_bit(sched_idx2prio(p->sq_idx, rq), \
++ rq->queue.bitmap); \
++ func; \
++ }
++
++#define __SCHED_ENQUEUE_TASK(p, rq, flags) \
++ sched_info_enqueue(rq, p); \
++ psi_enqueue(p, flags); \
++ \
++ p->sq_idx = task_sched_prio_idx(p, rq); \
++ list_add_tail(&p->sq_node, &rq->queue.heads[p->sq_idx]); \
++ set_bit(sched_idx2prio(p->sq_idx, rq), rq->queue.bitmap);
++
++static inline void dequeue_task(struct task_struct *p, struct rq *rq, int flags)
++{
++ lockdep_assert_held(&rq->lock);
++
++ /*printk(KERN_INFO "sched: dequeue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/
++ WARN_ONCE(task_rq(p) != rq, "sched: dequeue task reside on cpu%d from cpu%d\n",
++ task_cpu(p), cpu_of(rq));
++
++ __SCHED_DEQUEUE_TASK(p, rq, flags, update_sched_rq_watermark(rq));
++ --rq->nr_running;
++#ifdef CONFIG_SMP
++ if (1 == rq->nr_running)
++ cpumask_clear_cpu(cpu_of(rq), &sched_rq_pending_mask);
++#endif
++
++ sched_update_tick_dependency(rq);
++}
++
++static inline void enqueue_task(struct task_struct *p, struct rq *rq, int flags)
++{
++ lockdep_assert_held(&rq->lock);
++
++ /*printk(KERN_INFO "sched: enqueue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/
++ WARN_ONCE(task_rq(p) != rq, "sched: enqueue task reside on cpu%d to cpu%d\n",
++ task_cpu(p), cpu_of(rq));
++
++ __SCHED_ENQUEUE_TASK(p, rq, flags);
++ update_sched_rq_watermark(rq);
++ ++rq->nr_running;
++#ifdef CONFIG_SMP
++ if (2 == rq->nr_running)
++ cpumask_set_cpu(cpu_of(rq), &sched_rq_pending_mask);
++#endif
++
++ sched_update_tick_dependency(rq);
++}
++
++static inline void requeue_task(struct task_struct *p, struct rq *rq)
++{
++ int idx;
++
++ lockdep_assert_held(&rq->lock);
++ /*printk(KERN_INFO "sched: requeue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/
++ WARN_ONCE(task_rq(p) != rq, "sched: cpu[%d] requeue task reside on cpu%d\n",
++ cpu_of(rq), task_cpu(p));
++
++ idx = task_sched_prio_idx(p, rq);
++
++ list_del(&p->sq_node);
++ list_add_tail(&p->sq_node, &rq->queue.heads[idx]);
++ if (idx != p->sq_idx) {
++ if (list_empty(&rq->queue.heads[p->sq_idx]))
++ clear_bit(sched_idx2prio(p->sq_idx, rq),
++ rq->queue.bitmap);
++ p->sq_idx = idx;
++ set_bit(sched_idx2prio(p->sq_idx, rq), rq->queue.bitmap);
++ update_sched_rq_watermark(rq);
++ }
++}
++
++/*
++ * cmpxchg based fetch_or, macro so it works for different integer types
++ */
++#define fetch_or(ptr, mask) \
++ ({ \
++ typeof(ptr) _ptr = (ptr); \
++ typeof(mask) _mask = (mask); \
++ typeof(*_ptr) _old, _val = *_ptr; \
++ \
++ for (;;) { \
++ _old = cmpxchg(_ptr, _val, _val | _mask); \
++ if (_old == _val) \
++ break; \
++ _val = _old; \
++ } \
++ _old; \
++})
++
++#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
++/*
++ * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG,
++ * this avoids any races wrt polling state changes and thereby avoids
++ * spurious IPIs.
++ */
++static bool set_nr_and_not_polling(struct task_struct *p)
++{
++ struct thread_info *ti = task_thread_info(p);
++ return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG);
++}
++
++/*
++ * Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set.
++ *
++ * If this returns true, then the idle task promises to call
++ * sched_ttwu_pending() and reschedule soon.
++ */
++static bool set_nr_if_polling(struct task_struct *p)
++{
++ struct thread_info *ti = task_thread_info(p);
++ typeof(ti->flags) old, val = READ_ONCE(ti->flags);
++
++ for (;;) {
++ if (!(val & _TIF_POLLING_NRFLAG))
++ return false;
++ if (val & _TIF_NEED_RESCHED)
++ return true;
++ old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED);
++ if (old == val)
++ break;
++ val = old;
++ }
++ return true;
++}
++
++#else
++static bool set_nr_and_not_polling(struct task_struct *p)
++{
++ set_tsk_need_resched(p);
++ return true;
++}
++
++#ifdef CONFIG_SMP
++static bool set_nr_if_polling(struct task_struct *p)
++{
++ return false;
++}
++#endif
++#endif
++
++static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
++{
++ struct wake_q_node *node = &task->wake_q;
++
++ /*
++ * Atomically grab the task, if ->wake_q is !nil already it means
++ * it's already queued (either by us or someone else) and will get the
++ * wakeup due to that.
++ *
++ * In order to ensure that a pending wakeup will observe our pending
++ * state, even in the failed case, an explicit smp_mb() must be used.
++ */
++ smp_mb__before_atomic();
++ if (unlikely(cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL)))
++ return false;
++
++ /*
++ * The head is context local, there can be no concurrency.
++ */
++ *head->lastp = node;
++ head->lastp = &node->next;
++ return true;
++}
++
++/**
++ * wake_q_add() - queue a wakeup for 'later' waking.
++ * @head: the wake_q_head to add @task to
++ * @task: the task to queue for 'later' wakeup
++ *
++ * Queue a task for later wakeup, most likely by the wake_up_q() call in the
++ * same context, _HOWEVER_ this is not guaranteed, the wakeup can come
++ * instantly.
++ *
++ * This function must be used as-if it were wake_up_process(); IOW the task
++ * must be ready to be woken at this location.
++ */
++void wake_q_add(struct wake_q_head *head, struct task_struct *task)
++{
++ if (__wake_q_add(head, task))
++ get_task_struct(task);
++}
++
++/**
++ * wake_q_add_safe() - safely queue a wakeup for 'later' waking.
++ * @head: the wake_q_head to add @task to
++ * @task: the task to queue for 'later' wakeup
++ *
++ * Queue a task for later wakeup, most likely by the wake_up_q() call in the
++ * same context, _HOWEVER_ this is not guaranteed, the wakeup can come
++ * instantly.
++ *
++ * This function must be used as-if it were wake_up_process(); IOW the task
++ * must be ready to be woken at this location.
++ *
++ * This function is essentially a task-safe equivalent to wake_q_add(). Callers
++ * that already hold reference to @task can call the 'safe' version and trust
++ * wake_q to do the right thing depending whether or not the @task is already
++ * queued for wakeup.
++ */
++void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)
++{
++ if (!__wake_q_add(head, task))
++ put_task_struct(task);
++}
++
++void wake_up_q(struct wake_q_head *head)
++{
++ struct wake_q_node *node = head->first;
++
++ while (node != WAKE_Q_TAIL) {
++ struct task_struct *task;
++
++ task = container_of(node, struct task_struct, wake_q);
++ /* task can safely be re-inserted now: */
++ node = node->next;
++ task->wake_q.next = NULL;
++
++ /*
++ * wake_up_process() executes a full barrier, which pairs with
++ * the queueing in wake_q_add() so as not to miss wakeups.
++ */
++ wake_up_process(task);
++ put_task_struct(task);
++ }
++}
++
++/*
++ * resched_curr - mark rq's current task 'to be rescheduled now'.
++ *
++ * On UP this means the setting of the need_resched flag, on SMP it
++ * might also involve a cross-CPU call to trigger the scheduler on
++ * the target CPU.
++ */
++void resched_curr(struct rq *rq)
++{
++ struct task_struct *curr = rq->curr;
++ int cpu;
++
++ lockdep_assert_held(&rq->lock);
++
++ if (test_tsk_need_resched(curr))
++ return;
++
++ cpu = cpu_of(rq);
++ if (cpu == smp_processor_id()) {
++ set_tsk_need_resched(curr);
++ set_preempt_need_resched();
++ return;
++ }
++
++ if (set_nr_and_not_polling(curr))
++ smp_send_reschedule(cpu);
++ else
++ trace_sched_wake_idle_without_ipi(cpu);
++}
++
++void resched_cpu(int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ if (cpu_online(cpu) || cpu == smp_processor_id())
++ resched_curr(cpu_rq(cpu));
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++}
++
++#ifdef CONFIG_SMP
++#ifdef CONFIG_NO_HZ_COMMON
++void nohz_balance_enter_idle(int cpu) {}
++
++void select_nohz_load_balancer(int stop_tick) {}
++
++void set_cpu_sd_state_idle(void) {}
++
++/*
++ * In the semi idle case, use the nearest busy CPU for migrating timers
++ * from an idle CPU. This is good for power-savings.
++ *
++ * We don't do similar optimization for completely idle system, as
++ * selecting an idle CPU will add more delays to the timers than intended
++ * (as that CPU's timer base may not be uptodate wrt jiffies etc).
++ */
++int get_nohz_timer_target(void)
++{
++ int i, cpu = smp_processor_id(), default_cpu = -1;
++ struct cpumask *mask;
++ const struct cpumask *hk_mask;
++
++ if (housekeeping_cpu(cpu, HK_FLAG_TIMER)) {
++ if (!idle_cpu(cpu))
++ return cpu;
++ default_cpu = cpu;
++ }
++
++ hk_mask = housekeeping_cpumask(HK_FLAG_TIMER);
++
++ for (mask = per_cpu(sched_cpu_topo_masks, cpu) + 1;
++ mask < per_cpu(sched_cpu_topo_end_mask, cpu); mask++)
++ for_each_cpu_and(i, mask, hk_mask)
++ if (!idle_cpu(i))
++ return i;
++
++ if (default_cpu == -1)
++ default_cpu = housekeeping_any_cpu(HK_FLAG_TIMER);
++ cpu = default_cpu;
++
++ return cpu;
++}
++
++/*
++ * When add_timer_on() enqueues a timer into the timer wheel of an
++ * idle CPU then this timer might expire before the next timer event
++ * which is scheduled to wake up that CPU. In case of a completely
++ * idle system the next event might even be infinite time into the
++ * future. wake_up_idle_cpu() ensures that the CPU is woken up and
++ * leaves the inner idle loop so the newly added timer is taken into
++ * account when the CPU goes back to idle and evaluates the timer
++ * wheel for the next timer event.
++ */
++static inline void wake_up_idle_cpu(int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ if (cpu == smp_processor_id())
++ return;
++
++ if (set_nr_and_not_polling(rq->idle))
++ smp_send_reschedule(cpu);
++ else
++ trace_sched_wake_idle_without_ipi(cpu);
++}
++
++static inline bool wake_up_full_nohz_cpu(int cpu)
++{
++ /*
++ * We just need the target to call irq_exit() and re-evaluate
++ * the next tick. The nohz full kick at least implies that.
++ * If needed we can still optimize that later with an
++ * empty IRQ.
++ */
++ if (cpu_is_offline(cpu))
++ return true; /* Don't try to wake offline CPUs. */
++ if (tick_nohz_full_cpu(cpu)) {
++ if (cpu != smp_processor_id() ||
++ tick_nohz_tick_stopped())
++ tick_nohz_full_kick_cpu(cpu);
++ return true;
++ }
++
++ return false;
++}
++
++void wake_up_nohz_cpu(int cpu)
++{
++ if (!wake_up_full_nohz_cpu(cpu))
++ wake_up_idle_cpu(cpu);
++}
++
++static void nohz_csd_func(void *info)
++{
++ struct rq *rq = info;
++ int cpu = cpu_of(rq);
++ unsigned int flags;
++
++ /*
++ * Release the rq::nohz_csd.
++ */
++ flags = atomic_fetch_andnot(NOHZ_KICK_MASK, nohz_flags(cpu));
++ WARN_ON(!(flags & NOHZ_KICK_MASK));
++
++ rq->idle_balance = idle_cpu(cpu);
++ if (rq->idle_balance && !need_resched()) {
++ rq->nohz_idle_balance = flags;
++ raise_softirq_irqoff(SCHED_SOFTIRQ);
++ }
++}
++
++#endif /* CONFIG_NO_HZ_COMMON */
++#endif /* CONFIG_SMP */
++
++static inline void check_preempt_curr(struct rq *rq)
++{
++ if (sched_rq_first_task(rq) != rq->curr)
++ resched_curr(rq);
++}
++
++#ifdef CONFIG_SCHED_HRTICK
++/*
++ * Use HR-timers to deliver accurate preemption points.
++ */
++
++static void hrtick_clear(struct rq *rq)
++{
++ if (hrtimer_active(&rq->hrtick_timer))
++ hrtimer_cancel(&rq->hrtick_timer);
++}
++
++/*
++ * High-resolution timer tick.
++ * Runs from hardirq context with interrupts disabled.
++ */
++static enum hrtimer_restart hrtick(struct hrtimer *timer)
++{
++ struct rq *rq = container_of(timer, struct rq, hrtick_timer);
++
++ WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
++
++ raw_spin_lock(&rq->lock);
++ resched_curr(rq);
++ raw_spin_unlock(&rq->lock);
++
++ return HRTIMER_NORESTART;
++}
++
++/*
++ * Use hrtick when:
++ * - enabled by features
++ * - hrtimer is actually high res
++ */
++static inline int hrtick_enabled(struct rq *rq)
++{
++ /**
++ * Alt schedule FW doesn't support sched_feat yet
++ if (!sched_feat(HRTICK))
++ return 0;
++ */
++ if (!cpu_active(cpu_of(rq)))
++ return 0;
++ return hrtimer_is_hres_active(&rq->hrtick_timer);
++}
++
++#ifdef CONFIG_SMP
++
++static void __hrtick_restart(struct rq *rq)
++{
++ struct hrtimer *timer = &rq->hrtick_timer;
++ ktime_t time = rq->hrtick_time;
++
++ hrtimer_start(timer, time, HRTIMER_MODE_ABS_PINNED_HARD);
++}
++
++/*
++ * called from hardirq (IPI) context
++ */
++static void __hrtick_start(void *arg)
++{
++ struct rq *rq = arg;
++
++ raw_spin_lock(&rq->lock);
++ __hrtick_restart(rq);
++ raw_spin_unlock(&rq->lock);
++}
++
++/*
++ * Called to set the hrtick timer state.
++ *
++ * called with rq->lock held and irqs disabled
++ */
++void hrtick_start(struct rq *rq, u64 delay)
++{
++ struct hrtimer *timer = &rq->hrtick_timer;
++ s64 delta;
++
++ /*
++ * Don't schedule slices shorter than 10000ns, that just
++ * doesn't make sense and can cause timer DoS.
++ */
++ delta = max_t(s64, delay, 10000LL);
++
++ rq->hrtick_time = ktime_add_ns(timer->base->get_time(), delta);
++
++ if (rq == this_rq())
++ __hrtick_restart(rq);
++ else
++ smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
++}
++
++#else
++/*
++ * Called to set the hrtick timer state.
++ *
++ * called with rq->lock held and irqs disabled
++ */
++void hrtick_start(struct rq *rq, u64 delay)
++{
++ /*
++ * Don't schedule slices shorter than 10000ns, that just
++ * doesn't make sense. Rely on vruntime for fairness.
++ */
++ delay = max_t(u64, delay, 10000LL);
++ hrtimer_start(&rq->hrtick_timer, ns_to_ktime(delay),
++ HRTIMER_MODE_REL_PINNED_HARD);
++}
++#endif /* CONFIG_SMP */
++
++static void hrtick_rq_init(struct rq *rq)
++{
++#ifdef CONFIG_SMP
++ INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
++#endif
++
++ hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
++ rq->hrtick_timer.function = hrtick;
++}
++#else /* CONFIG_SCHED_HRTICK */
++static inline int hrtick_enabled(struct rq *rq)
++{
++ return 0;
++}
++
++static inline void hrtick_clear(struct rq *rq)
++{
++}
++
++static inline void hrtick_rq_init(struct rq *rq)
++{
++}
++#endif /* CONFIG_SCHED_HRTICK */
++
++static inline int __normal_prio(int policy, int rt_prio, int static_prio)
++{
++ return rt_policy(policy) ? (MAX_RT_PRIO - 1 - rt_prio) :
++ static_prio + MAX_PRIORITY_ADJ;
++}
++
++/*
++ * Calculate the expected normal priority: i.e. priority
++ * without taking RT-inheritance into account. Might be
++ * boosted by interactivity modifiers. Changes upon fork,
++ * setprio syscalls, and whenever the interactivity
++ * estimator recalculates.
++ */
++static inline int normal_prio(struct task_struct *p)
++{
++ return __normal_prio(p->policy, p->rt_priority, p->static_prio);
++}
++
++/*
++ * Calculate the current priority, i.e. the priority
++ * taken into account by the scheduler. This value might
++ * be boosted by RT tasks as it will be RT if the task got
++ * RT-boosted. If not then it returns p->normal_prio.
++ */
++static int effective_prio(struct task_struct *p)
++{
++ p->normal_prio = normal_prio(p);
++ /*
++ * If we are RT tasks or we were boosted to RT priority,
++ * keep the priority unchanged. Otherwise, update priority
++ * to the normal priority:
++ */
++ if (!rt_prio(p->prio))
++ return p->normal_prio;
++ return p->prio;
++}
++
++/*
++ * activate_task - move a task to the runqueue.
++ *
++ * Context: rq->lock
++ */
++static void activate_task(struct task_struct *p, struct rq *rq)
++{
++ enqueue_task(p, rq, ENQUEUE_WAKEUP);
++ p->on_rq = TASK_ON_RQ_QUEUED;
++
++ /*
++ * If in_iowait is set, the code below may not trigger any cpufreq
++ * utilization updates, so do it here explicitly with the IOWAIT flag
++ * passed.
++ */
++ cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT * p->in_iowait);
++}
++
++/*
++ * deactivate_task - remove a task from the runqueue.
++ *
++ * Context: rq->lock
++ */
++static inline void deactivate_task(struct task_struct *p, struct rq *rq)
++{
++ dequeue_task(p, rq, DEQUEUE_SLEEP);
++ p->on_rq = 0;
++ cpufreq_update_util(rq, 0);
++}
++
++static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
++{
++#ifdef CONFIG_SMP
++ /*
++ * After ->cpu is set up to a new value, task_access_lock(p, ...) can be
++ * successfully executed on another CPU. We must ensure that updates of
++ * per-task data have been completed by this moment.
++ */
++ smp_wmb();
++
++#ifdef CONFIG_THREAD_INFO_IN_TASK
++ WRITE_ONCE(p->cpu, cpu);
++#else
++ WRITE_ONCE(task_thread_info(p)->cpu, cpu);
++#endif
++#endif
++}
++
++static inline bool is_migration_disabled(struct task_struct *p)
++{
++#ifdef CONFIG_SMP
++ return p->migration_disabled;
++#else
++ return false;
++#endif
++}
++
++#define SCA_CHECK 0x01
++#define SCA_USER 0x08
++
++#ifdef CONFIG_SMP
++
++void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
++{
++#ifdef CONFIG_SCHED_DEBUG
++ unsigned int state = READ_ONCE(p->__state);
++
++ /*
++ * We should never call set_task_cpu() on a blocked task,
++ * ttwu() will sort out the placement.
++ */
++ WARN_ON_ONCE(state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq);
++
++#ifdef CONFIG_LOCKDEP
++ /*
++ * The caller should hold either p->pi_lock or rq->lock, when changing
++ * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
++ *
++ * sched_move_task() holds both and thus holding either pins the cgroup,
++ * see task_group().
++ */
++ WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
++ lockdep_is_held(&task_rq(p)->lock)));
++#endif
++ /*
++ * Clearly, migrating tasks to offline CPUs is a fairly daft thing.
++ */
++ WARN_ON_ONCE(!cpu_online(new_cpu));
++
++ WARN_ON_ONCE(is_migration_disabled(p));
++#endif
++ if (task_cpu(p) == new_cpu)
++ return;
++ trace_sched_migrate_task(p, new_cpu);
++ rseq_migrate(p);
++ perf_event_task_migrate(p);
++
++ __set_task_cpu(p, new_cpu);
++}
++
++#define MDF_FORCE_ENABLED 0x80
++
++static void
++__do_set_cpus_ptr(struct task_struct *p, const struct cpumask *new_mask)
++{
++ /*
++ * This here violates the locking rules for affinity, since we're only
++ * supposed to change these variables while holding both rq->lock and
++ * p->pi_lock.
++ *
++ * HOWEVER, it magically works, because ttwu() is the only code that
++ * accesses these variables under p->pi_lock and only does so after
++ * smp_cond_load_acquire(&p->on_cpu, !VAL), and we're in __schedule()
++ * before finish_task().
++ *
++ * XXX do further audits, this smells like something putrid.
++ */
++ SCHED_WARN_ON(!p->on_cpu);
++ p->cpus_ptr = new_mask;
++}
++
++void migrate_disable(void)
++{
++ struct task_struct *p = current;
++ int cpu;
++
++ if (p->migration_disabled) {
++ p->migration_disabled++;
++ return;
++ }
++
++ preempt_disable();
++ cpu = smp_processor_id();
++ if (cpumask_test_cpu(cpu, &p->cpus_mask)) {
++ cpu_rq(cpu)->nr_pinned++;
++ p->migration_disabled = 1;
++ p->migration_flags &= ~MDF_FORCE_ENABLED;
++
++ /*
++ * Violates locking rules! see comment in __do_set_cpus_ptr().
++ */
++ if (p->cpus_ptr == &p->cpus_mask)
++ __do_set_cpus_ptr(p, cpumask_of(cpu));
++ }
++ preempt_enable();
++}
++EXPORT_SYMBOL_GPL(migrate_disable);
++
++void migrate_enable(void)
++{
++ struct task_struct *p = current;
++
++ if (0 == p->migration_disabled)
++ return;
++
++ if (p->migration_disabled > 1) {
++ p->migration_disabled--;
++ return;
++ }
++
++ /*
++ * Ensure stop_task runs either before or after this, and that
++ * __set_cpus_allowed_ptr(SCA_MIGRATE_ENABLE) doesn't schedule().
++ */
++ preempt_disable();
++ /*
++ * Assumption: current should be running on allowed cpu
++ */
++ WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &p->cpus_mask));
++ if (p->cpus_ptr != &p->cpus_mask)
++ __do_set_cpus_ptr(p, &p->cpus_mask);
++ /*
++ * Mustn't clear migration_disabled() until cpus_ptr points back at the
++ * regular cpus_mask, otherwise things that race (eg.
++ * select_fallback_rq) get confused.
++ */
++ barrier();
++ p->migration_disabled = 0;
++ this_rq()->nr_pinned--;
++ preempt_enable();
++}
++EXPORT_SYMBOL_GPL(migrate_enable);
++
++static inline bool rq_has_pinned_tasks(struct rq *rq)
++{
++ return rq->nr_pinned;
++}
++
++/*
++ * Per-CPU kthreads are allowed to run on !active && online CPUs, see
++ * __set_cpus_allowed_ptr() and select_fallback_rq().
++ */
++static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
++{
++ /* When not in the task's cpumask, no point in looking further. */
++ if (!cpumask_test_cpu(cpu, p->cpus_ptr))
++ return false;
++
++ /* migrate_disabled() must be allowed to finish. */
++ if (is_migration_disabled(p))
++ return cpu_online(cpu);
++
++ /* Non kernel threads are not allowed during either online or offline. */
++ if (!(p->flags & PF_KTHREAD))
++ return cpu_active(cpu) && task_cpu_possible(cpu, p);
++
++ /* KTHREAD_IS_PER_CPU is always allowed. */
++ if (kthread_is_per_cpu(p))
++ return cpu_online(cpu);
++
++ /* Regular kernel threads don't get to stay during offline. */
++ if (cpu_dying(cpu))
++ return false;
++
++ /* But are allowed during online. */
++ return cpu_online(cpu);
++}
++
++/*
++ * This is how migration works:
++ *
++ * 1) we invoke migration_cpu_stop() on the target CPU using
++ * stop_one_cpu().
++ * 2) stopper starts to run (implicitly forcing the migrated thread
++ * off the CPU)
++ * 3) it checks whether the migrated task is still in the wrong runqueue.
++ * 4) if it's in the wrong runqueue then the migration thread removes
++ * it and puts it into the right queue.
++ * 5) stopper completes and stop_one_cpu() returns and the migration
++ * is done.
++ */
++
++/*
++ * move_queued_task - move a queued task to new rq.
++ *
++ * Returns (locked) new rq. Old rq's lock is released.
++ */
++static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int
++ new_cpu)
++{
++ lockdep_assert_held(&rq->lock);
++
++ WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
++ dequeue_task(p, rq, 0);
++ set_task_cpu(p, new_cpu);
++ raw_spin_unlock(&rq->lock);
++
++ rq = cpu_rq(new_cpu);
++
++ raw_spin_lock(&rq->lock);
++ BUG_ON(task_cpu(p) != new_cpu);
++ sched_task_sanity_check(p, rq);
++ enqueue_task(p, rq, 0);
++ p->on_rq = TASK_ON_RQ_QUEUED;
++ check_preempt_curr(rq);
++
++ return rq;
++}
++
++struct migration_arg {
++ struct task_struct *task;
++ int dest_cpu;
++};
++
++/*
++ * Move (not current) task off this CPU, onto the destination CPU. We're doing
++ * this because either it can't run here any more (set_cpus_allowed()
++ * away from this CPU, or CPU going down), or because we're
++ * attempting to rebalance this task on exec (sched_exec).
++ *
++ * So we race with normal scheduler movements, but that's OK, as long
++ * as the task is no longer on this CPU.
++ */
++static struct rq *__migrate_task(struct rq *rq, struct task_struct *p, int
++ dest_cpu)
++{
++ /* Affinity changed (again). */
++ if (!is_cpu_allowed(p, dest_cpu))
++ return rq;
++
++ update_rq_clock(rq);
++ return move_queued_task(rq, p, dest_cpu);
++}
++
++/*
++ * migration_cpu_stop - this will be executed by a highprio stopper thread
++ * and performs thread migration by bumping thread off CPU then
++ * 'pushing' onto another runqueue.
++ */
++static int migration_cpu_stop(void *data)
++{
++ struct migration_arg *arg = data;
++ struct task_struct *p = arg->task;
++ struct rq *rq = this_rq();
++ unsigned long flags;
++
++ /*
++ * The original target CPU might have gone down and we might
++ * be on another CPU but it doesn't matter.
++ */
++ local_irq_save(flags);
++ /*
++ * We need to explicitly wake pending tasks before running
++ * __migrate_task() such that we will not miss enforcing cpus_ptr
++ * during wakeups, see set_cpus_allowed_ptr()'s TASK_WAKING test.
++ */
++ flush_smp_call_function_from_idle();
++
++ raw_spin_lock(&p->pi_lock);
++ raw_spin_lock(&rq->lock);
++ /*
++ * If task_rq(p) != rq, it cannot be migrated here, because we're
++ * holding rq->lock, if p->on_rq == 0 it cannot get enqueued because
++ * we're holding p->pi_lock.
++ */
++ if (task_rq(p) == rq && task_on_rq_queued(p))
++ rq = __migrate_task(rq, p, arg->dest_cpu);
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++
++ return 0;
++}
++
++static inline void
++set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask)
++{
++ cpumask_copy(&p->cpus_mask, new_mask);
++ p->nr_cpus_allowed = cpumask_weight(new_mask);
++}
++
++static void
++__do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
++{
++ lockdep_assert_held(&p->pi_lock);
++ set_cpus_allowed_common(p, new_mask);
++}
++
++void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
++{
++ __do_set_cpus_allowed(p, new_mask);
++}
++
++int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
++ int node)
++{
++ if (!src->user_cpus_ptr)
++ return 0;
++
++ dst->user_cpus_ptr = kmalloc_node(cpumask_size(), GFP_KERNEL, node);
++ if (!dst->user_cpus_ptr)
++ return -ENOMEM;
++
++ cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
++ return 0;
++}
++
++static inline struct cpumask *clear_user_cpus_ptr(struct task_struct *p)
++{
++ struct cpumask *user_mask = NULL;
++
++ swap(p->user_cpus_ptr, user_mask);
++
++ return user_mask;
++}
++
++void release_user_cpus_ptr(struct task_struct *p)
++{
++ kfree(clear_user_cpus_ptr(p));
++}
++
++#endif
++
++/**
++ * task_curr - is this task currently executing on a CPU?
++ * @p: the task in question.
++ *
++ * Return: 1 if the task is currently executing. 0 otherwise.
++ */
++inline int task_curr(const struct task_struct *p)
++{
++ return cpu_curr(task_cpu(p)) == p;
++}
++
++#ifdef CONFIG_SMP
++/*
++ * wait_task_inactive - wait for a thread to unschedule.
++ *
++ * If @match_state is nonzero, it's the @p->state value just checked and
++ * not expected to change. If it changes, i.e. @p might have woken up,
++ * then return zero. When we succeed in waiting for @p to be off its CPU,
++ * we return a positive number (its total switch count). If a second call
++ * a short while later returns the same number, the caller can be sure that
++ * @p has remained unscheduled the whole time.
++ *
++ * The caller must ensure that the task *will* unschedule sometime soon,
++ * else this function might spin for a *long* time. This function can't
++ * be called with interrupts off, or it may introduce deadlock with
++ * smp_call_function() if an IPI is sent by the same process we are
++ * waiting to become inactive.
++ */
++unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
++{
++ unsigned long flags;
++ bool running, on_rq;
++ unsigned long ncsw;
++ struct rq *rq;
++ raw_spinlock_t *lock;
++
++ for (;;) {
++ rq = task_rq(p);
++
++ /*
++ * If the task is actively running on another CPU
++ * still, just relax and busy-wait without holding
++ * any locks.
++ *
++ * NOTE! Since we don't hold any locks, it's not
++ * even sure that "rq" stays as the right runqueue!
++ * But we don't care, since this will return false
++ * if the runqueue has changed and p is actually now
++ * running somewhere else!
++ */
++ while (task_running(p) && p == rq->curr) {
++ if (match_state && unlikely(READ_ONCE(p->__state) != match_state))
++ return 0;
++ cpu_relax();
++ }
++
++ /*
++ * Ok, time to look more closely! We need the rq
++ * lock now, to be *sure*. If we're wrong, we'll
++ * just go back and repeat.
++ */
++ task_access_lock_irqsave(p, &lock, &flags);
++ trace_sched_wait_task(p);
++ running = task_running(p);
++ on_rq = p->on_rq;
++ ncsw = 0;
++ if (!match_state || READ_ONCE(p->__state) == match_state)
++ ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
++ task_access_unlock_irqrestore(p, lock, &flags);
++
++ /*
++ * If it changed from the expected state, bail out now.
++ */
++ if (unlikely(!ncsw))
++ break;
++
++ /*
++ * Was it really running after all now that we
++ * checked with the proper locks actually held?
++ *
++ * Oops. Go back and try again..
++ */
++ if (unlikely(running)) {
++ cpu_relax();
++ continue;
++ }
++
++ /*
++ * It's not enough that it's not actively running,
++ * it must be off the runqueue _entirely_, and not
++ * preempted!
++ *
++ * So if it was still runnable (but just not actively
++ * running right now), it's preempted, and we should
++ * yield - it could be a while.
++ */
++ if (unlikely(on_rq)) {
++ ktime_t to = NSEC_PER_SEC / HZ;
++
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_hrtimeout(&to, HRTIMER_MODE_REL);
++ continue;
++ }
++
++ /*
++ * Ahh, all good. It wasn't running, and it wasn't
++ * runnable, which means that it will never become
++ * running in the future either. We're all done!
++ */
++ break;
++ }
++
++ return ncsw;
++}
++
++/***
++ * kick_process - kick a running thread to enter/exit the kernel
++ * @p: the to-be-kicked thread
++ *
++ * Cause a process which is running on another CPU to enter
++ * kernel-mode, without any delay. (to get signals handled.)
++ *
++ * NOTE: this function doesn't have to take the runqueue lock,
++ * because all it wants to ensure is that the remote task enters
++ * the kernel. If the IPI races and the task has been migrated
++ * to another CPU then no harm is done and the purpose has been
++ * achieved as well.
++ */
++void kick_process(struct task_struct *p)
++{
++ int cpu;
++
++ preempt_disable();
++ cpu = task_cpu(p);
++ if ((cpu != smp_processor_id()) && task_curr(p))
++ smp_send_reschedule(cpu);
++ preempt_enable();
++}
++EXPORT_SYMBOL_GPL(kick_process);
++
++/*
++ * ->cpus_ptr is protected by both rq->lock and p->pi_lock
++ *
++ * A few notes on cpu_active vs cpu_online:
++ *
++ * - cpu_active must be a subset of cpu_online
++ *
++ * - on CPU-up we allow per-CPU kthreads on the online && !active CPU,
++ * see __set_cpus_allowed_ptr(). At this point the newly online
++ * CPU isn't yet part of the sched domains, and balancing will not
++ * see it.
++ *
++ * - on cpu-down we clear cpu_active() to mask the sched domains and
++ * avoid the load balancer to place new tasks on the to be removed
++ * CPU. Existing tasks will remain running there and will be taken
++ * off.
++ *
++ * This means that fallback selection must not select !active CPUs.
++ * And can assume that any active CPU must be online. Conversely
++ * select_task_rq() below may allow selection of !active CPUs in order
++ * to satisfy the above rules.
++ */
++static int select_fallback_rq(int cpu, struct task_struct *p)
++{
++ int nid = cpu_to_node(cpu);
++ const struct cpumask *nodemask = NULL;
++ enum { cpuset, possible, fail } state = cpuset;
++ int dest_cpu;
++
++ /*
++ * If the node that the CPU is on has been offlined, cpu_to_node()
++ * will return -1. There is no CPU on the node, and we should
++ * select the CPU on the other node.
++ */
++ if (nid != -1) {
++ nodemask = cpumask_of_node(nid);
++
++ /* Look for allowed, online CPU in same node. */
++ for_each_cpu(dest_cpu, nodemask) {
++ if (is_cpu_allowed(p, dest_cpu))
++ return dest_cpu;
++ }
++ }
++
++ for (;;) {
++ /* Any allowed, online CPU? */
++ for_each_cpu(dest_cpu, p->cpus_ptr) {
++ if (!is_cpu_allowed(p, dest_cpu))
++ continue;
++ goto out;
++ }
++
++ /* No more Mr. Nice Guy. */
++ switch (state) {
++ case cpuset:
++ if (cpuset_cpus_allowed_fallback(p)) {
++ state = possible;
++ break;
++ }
++ fallthrough;
++ case possible:
++ /*
++ * XXX When called from select_task_rq() we only
++ * hold p->pi_lock and again violate locking order.
++ *
++ * More yuck to audit.
++ */
++ do_set_cpus_allowed(p, task_cpu_possible_mask(p));
++ state = fail;
++ break;
++
++ case fail:
++ BUG();
++ break;
++ }
++ }
++
++out:
++ if (state != cpuset) {
++ /*
++ * Don't tell them about moving exiting tasks or
++ * kernel threads (both mm NULL), since they never
++ * leave kernel.
++ */
++ if (p->mm && printk_ratelimit()) {
++ printk_deferred("process %d (%s) no longer affine to cpu%d\n",
++ task_pid_nr(p), p->comm, cpu);
++ }
++ }
++
++ return dest_cpu;
++}
++
++static inline int select_task_rq(struct task_struct *p)
++{
++ cpumask_t chk_mask, tmp;
++
++ if (unlikely(!cpumask_and(&chk_mask, p->cpus_ptr, cpu_active_mask)))
++ return select_fallback_rq(task_cpu(p), p);
++
++ if (
++#ifdef CONFIG_SCHED_SMT
++ cpumask_and(&tmp, &chk_mask, &sched_sg_idle_mask) ||
++#endif
++ cpumask_and(&tmp, &chk_mask, sched_rq_watermark) ||
++ cpumask_and(&tmp, &chk_mask,
++ sched_rq_watermark + SCHED_BITS - task_sched_prio(p)))
++ return best_mask_cpu(task_cpu(p), &tmp);
++
++ return best_mask_cpu(task_cpu(p), &chk_mask);
++}
++
++void sched_set_stop_task(int cpu, struct task_struct *stop)
++{
++ static struct lock_class_key stop_pi_lock;
++ struct sched_param stop_param = { .sched_priority = STOP_PRIO };
++ struct sched_param start_param = { .sched_priority = 0 };
++ struct task_struct *old_stop = cpu_rq(cpu)->stop;
++
++ if (stop) {
++ /*
++ * Make it appear like a SCHED_FIFO task, its something
++ * userspace knows about and won't get confused about.
++ *
++ * Also, it will make PI more or less work without too
++ * much confusion -- but then, stop work should not
++ * rely on PI working anyway.
++ */
++ sched_setscheduler_nocheck(stop, SCHED_FIFO, &stop_param);
++
++ /*
++ * The PI code calls rt_mutex_setprio() with ->pi_lock held to
++ * adjust the effective priority of a task. As a result,
++ * rt_mutex_setprio() can trigger (RT) balancing operations,
++ * which can then trigger wakeups of the stop thread to push
++ * around the current task.
++ *
++ * The stop task itself will never be part of the PI-chain, it
++ * never blocks, therefore that ->pi_lock recursion is safe.
++ * Tell lockdep about this by placing the stop->pi_lock in its
++ * own class.
++ */
++ lockdep_set_class(&stop->pi_lock, &stop_pi_lock);
++ }
++
++ cpu_rq(cpu)->stop = stop;
++
++ if (old_stop) {
++ /*
++ * Reset it back to a normal scheduling policy so that
++ * it can die in pieces.
++ */
++ sched_setscheduler_nocheck(old_stop, SCHED_NORMAL, &start_param);
++ }
++}
++
++static int affine_move_task(struct rq *rq, struct task_struct *p, int dest_cpu,
++ raw_spinlock_t *lock, unsigned long irq_flags)
++{
++ /* Can the task run on the task's current CPU? If so, we're done */
++ if (!cpumask_test_cpu(task_cpu(p), &p->cpus_mask)) {
++ if (p->migration_disabled) {
++ if (likely(p->cpus_ptr != &p->cpus_mask))
++ __do_set_cpus_ptr(p, &p->cpus_mask);
++ p->migration_disabled = 0;
++ p->migration_flags |= MDF_FORCE_ENABLED;
++ /* When p is migrate_disabled, rq->lock should be held */
++ rq->nr_pinned--;
++ }
++
++ if (task_running(p) || READ_ONCE(p->__state) == TASK_WAKING) {
++ struct migration_arg arg = { p, dest_cpu };
++
++ /* Need help from migration thread: drop lock and wait. */
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags);
++ stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
++ return 0;
++ }
++ if (task_on_rq_queued(p)) {
++ /*
++ * OK, since we're going to drop the lock immediately
++ * afterwards anyway.
++ */
++ update_rq_clock(rq);
++ rq = move_queued_task(rq, p, dest_cpu);
++ lock = &rq->lock;
++ }
++ }
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags);
++ return 0;
++}
++
++static int __set_cpus_allowed_ptr_locked(struct task_struct *p,
++ const struct cpumask *new_mask,
++ u32 flags,
++ struct rq *rq,
++ raw_spinlock_t *lock,
++ unsigned long irq_flags)
++{
++ const struct cpumask *cpu_allowed_mask = task_cpu_possible_mask(p);
++ const struct cpumask *cpu_valid_mask = cpu_active_mask;
++ bool kthread = p->flags & PF_KTHREAD;
++ struct cpumask *user_mask = NULL;
++ int dest_cpu;
++ int ret = 0;
++
++ if (kthread || is_migration_disabled(p)) {
++ /*
++ * Kernel threads are allowed on online && !active CPUs,
++ * however, during cpu-hot-unplug, even these might get pushed
++ * away if not KTHREAD_IS_PER_CPU.
++ *
++ * Specifically, migration_disabled() tasks must not fail the
++ * cpumask_any_and_distribute() pick below, esp. so on
++ * SCA_MIGRATE_ENABLE, otherwise we'll not call
++ * set_cpus_allowed_common() and actually reset p->cpus_ptr.
++ */
++ cpu_valid_mask = cpu_online_mask;
++ }
++
++ if (!kthread && !cpumask_subset(new_mask, cpu_allowed_mask)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /*
++ * Must re-check here, to close a race against __kthread_bind(),
++ * sched_setaffinity() is not guaranteed to observe the flag.
++ */
++ if ((flags & SCA_CHECK) && (p->flags & PF_NO_SETAFFINITY)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (cpumask_equal(&p->cpus_mask, new_mask))
++ goto out;
++
++ dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask);
++ if (dest_cpu >= nr_cpu_ids) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ __do_set_cpus_allowed(p, new_mask);
++
++ if (flags & SCA_USER)
++ user_mask = clear_user_cpus_ptr(p);
++
++ ret = affine_move_task(rq, p, dest_cpu, lock, irq_flags);
++
++ kfree(user_mask);
++
++ return ret;
++
++out:
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags);
++
++ return ret;
++}
++
++/*
++ * Change a given task's CPU affinity. Migrate the thread to a
++ * proper CPU and schedule it away if the CPU it's executing on
++ * is removed from the allowed bitmask.
++ *
++ * NOTE: the caller must have a valid reference to the task, the
++ * task must not exit() & deallocate itself prematurely. The
++ * call is not atomic; no spinlocks may be held.
++ */
++static int __set_cpus_allowed_ptr(struct task_struct *p,
++ const struct cpumask *new_mask, u32 flags)
++{
++ unsigned long irq_flags;
++ struct rq *rq;
++ raw_spinlock_t *lock;
++
++ raw_spin_lock_irqsave(&p->pi_lock, irq_flags);
++ rq = __task_access_lock(p, &lock);
++
++ return __set_cpus_allowed_ptr_locked(p, new_mask, flags, rq, lock, irq_flags);
++}
++
++int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
++{
++ return __set_cpus_allowed_ptr(p, new_mask, 0);
++}
++EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
++
++/*
++ * Change a given task's CPU affinity to the intersection of its current
++ * affinity mask and @subset_mask, writing the resulting mask to @new_mask
++ * and pointing @p->user_cpus_ptr to a copy of the old mask.
++ * If the resulting mask is empty, leave the affinity unchanged and return
++ * -EINVAL.
++ */
++static int restrict_cpus_allowed_ptr(struct task_struct *p,
++ struct cpumask *new_mask,
++ const struct cpumask *subset_mask)
++{
++ struct cpumask *user_mask = NULL;
++ unsigned long irq_flags;
++ raw_spinlock_t *lock;
++ struct rq *rq;
++ int err;
++
++ if (!p->user_cpus_ptr) {
++ user_mask = kmalloc(cpumask_size(), GFP_KERNEL);
++ if (!user_mask)
++ return -ENOMEM;
++ }
++
++ raw_spin_lock_irqsave(&p->pi_lock, irq_flags);
++ rq = __task_access_lock(p, &lock);
++
++ if (!cpumask_and(new_mask, &p->cpus_mask, subset_mask)) {
++ err = -EINVAL;
++ goto err_unlock;
++ }
++
++ /*
++ * We're about to butcher the task affinity, so keep track of what
++ * the user asked for in case we're able to restore it later on.
++ */
++ if (user_mask) {
++ cpumask_copy(user_mask, p->cpus_ptr);
++ p->user_cpus_ptr = user_mask;
++ }
++
++ /*return __set_cpus_allowed_ptr_locked(p, new_mask, 0, rq, &rf);*/
++ return __set_cpus_allowed_ptr_locked(p, new_mask, 0, rq, lock, irq_flags);
++
++err_unlock:
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags);
++ kfree(user_mask);
++ return err;
++}
++
++/*
++ * Restrict the CPU affinity of task @p so that it is a subset of
++ * task_cpu_possible_mask() and point @p->user_cpu_ptr to a copy of the
++ * old affinity mask. If the resulting mask is empty, we warn and walk
++ * up the cpuset hierarchy until we find a suitable mask.
++ */
++void force_compatible_cpus_allowed_ptr(struct task_struct *p)
++{
++ cpumask_var_t new_mask;
++ const struct cpumask *override_mask = task_cpu_possible_mask(p);
++
++ alloc_cpumask_var(&new_mask, GFP_KERNEL);
++
++ /*
++ * __migrate_task() can fail silently in the face of concurrent
++ * offlining of the chosen destination CPU, so take the hotplug
++ * lock to ensure that the migration succeeds.
++ */
++ cpus_read_lock();
++ if (!cpumask_available(new_mask))
++ goto out_set_mask;
++
++ if (!restrict_cpus_allowed_ptr(p, new_mask, override_mask))
++ goto out_free_mask;
++
++ /*
++ * We failed to find a valid subset of the affinity mask for the
++ * task, so override it based on its cpuset hierarchy.
++ */
++ cpuset_cpus_allowed(p, new_mask);
++ override_mask = new_mask;
++
++out_set_mask:
++ if (printk_ratelimit()) {
++ printk_deferred("Overriding affinity for process %d (%s) to CPUs %*pbl\n",
++ task_pid_nr(p), p->comm,
++ cpumask_pr_args(override_mask));
++ }
++
++ WARN_ON(set_cpus_allowed_ptr(p, override_mask));
++out_free_mask:
++ cpus_read_unlock();
++ free_cpumask_var(new_mask);
++}
++
++static int
++__sched_setaffinity(struct task_struct *p, const struct cpumask *mask);
++
++/*
++ * Restore the affinity of a task @p which was previously restricted by a
++ * call to force_compatible_cpus_allowed_ptr(). This will clear (and free)
++ * @p->user_cpus_ptr.
++ *
++ * It is the caller's responsibility to serialise this with any calls to
++ * force_compatible_cpus_allowed_ptr(@p).
++ */
++void relax_compatible_cpus_allowed_ptr(struct task_struct *p)
++{
++ struct cpumask *user_mask = p->user_cpus_ptr;
++ unsigned long flags;
++
++ /*
++ * Try to restore the old affinity mask. If this fails, then
++ * we free the mask explicitly to avoid it being inherited across
++ * a subsequent fork().
++ */
++ if (!user_mask || !__sched_setaffinity(p, user_mask))
++ return;
++
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ user_mask = clear_user_cpus_ptr(p);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++
++ kfree(user_mask);
++}
++
++#else /* CONFIG_SMP */
++
++static inline int select_task_rq(struct task_struct *p)
++{
++ return 0;
++}
++
++static inline int
++__set_cpus_allowed_ptr(struct task_struct *p,
++ const struct cpumask *new_mask, u32 flags)
++{
++ return set_cpus_allowed_ptr(p, new_mask);
++}
++
++static inline bool rq_has_pinned_tasks(struct rq *rq)
++{
++ return false;
++}
++
++#endif /* !CONFIG_SMP */
++
++static void
++ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
++{
++ struct rq *rq;
++
++ if (!schedstat_enabled())
++ return;
++
++ rq = this_rq();
++
++#ifdef CONFIG_SMP
++ if (cpu == rq->cpu)
++ __schedstat_inc(rq->ttwu_local);
++ else {
++ /** Alt schedule FW ToDo:
++ * How to do ttwu_wake_remote
++ */
++ }
++#endif /* CONFIG_SMP */
++
++ __schedstat_inc(rq->ttwu_count);
++}
++
++/*
++ * Mark the task runnable and perform wakeup-preemption.
++ */
++static inline void
++ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
++{
++ check_preempt_curr(rq);
++ WRITE_ONCE(p->__state, TASK_RUNNING);
++ trace_sched_wakeup(p);
++}
++
++static inline void
++ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags)
++{
++ if (p->sched_contributes_to_load)
++ rq->nr_uninterruptible--;
++
++ if (
++#ifdef CONFIG_SMP
++ !(wake_flags & WF_MIGRATED) &&
++#endif
++ p->in_iowait) {
++ delayacct_blkio_end(p);
++ atomic_dec(&task_rq(p)->nr_iowait);
++ }
++
++ activate_task(p, rq);
++ ttwu_do_wakeup(rq, p, 0);
++}
++
++/*
++ * Consider @p being inside a wait loop:
++ *
++ * for (;;) {
++ * set_current_state(TASK_UNINTERRUPTIBLE);
++ *
++ * if (CONDITION)
++ * break;
++ *
++ * schedule();
++ * }
++ * __set_current_state(TASK_RUNNING);
++ *
++ * between set_current_state() and schedule(). In this case @p is still
++ * runnable, so all that needs doing is change p->state back to TASK_RUNNING in
++ * an atomic manner.
++ *
++ * By taking task_rq(p)->lock we serialize against schedule(), if @p->on_rq
++ * then schedule() must still happen and p->state can be changed to
++ * TASK_RUNNING. Otherwise we lost the race, schedule() has happened, and we
++ * need to do a full wakeup with enqueue.
++ *
++ * Returns: %true when the wakeup is done,
++ * %false otherwise.
++ */
++static int ttwu_runnable(struct task_struct *p, int wake_flags)
++{
++ struct rq *rq;
++ raw_spinlock_t *lock;
++ int ret = 0;
++
++ rq = __task_access_lock(p, &lock);
++ if (task_on_rq_queued(p)) {
++ /* check_preempt_curr() may use rq clock */
++ update_rq_clock(rq);
++ ttwu_do_wakeup(rq, p, wake_flags);
++ ret = 1;
++ }
++ __task_access_unlock(p, lock);
++
++ return ret;
++}
++
++#ifdef CONFIG_SMP
++void sched_ttwu_pending(void *arg)
++{
++ struct llist_node *llist = arg;
++ struct rq *rq = this_rq();
++ struct task_struct *p, *t;
++ struct rq_flags rf;
++
++ if (!llist)
++ return;
++
++ /*
++ * rq::ttwu_pending racy indication of out-standing wakeups.
++ * Races such that false-negatives are possible, since they
++ * are shorter lived that false-positives would be.
++ */
++ WRITE_ONCE(rq->ttwu_pending, 0);
++
++ rq_lock_irqsave(rq, &rf);
++ update_rq_clock(rq);
++
++ llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
++ if (WARN_ON_ONCE(p->on_cpu))
++ smp_cond_load_acquire(&p->on_cpu, !VAL);
++
++ if (WARN_ON_ONCE(task_cpu(p) != cpu_of(rq)))
++ set_task_cpu(p, cpu_of(rq));
++
++ ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0);
++ }
++
++ rq_unlock_irqrestore(rq, &rf);
++}
++
++void send_call_function_single_ipi(int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ if (!set_nr_if_polling(rq->idle))
++ arch_send_call_function_single_ipi(cpu);
++ else
++ trace_sched_wake_idle_without_ipi(cpu);
++}
++
++/*
++ * Queue a task on the target CPUs wake_list and wake the CPU via IPI if
++ * necessary. The wakee CPU on receipt of the IPI will queue the task
++ * via sched_ttwu_wakeup() for activation so the wakee incurs the cost
++ * of the wakeup instead of the waker.
++ */
++static void __ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED);
++
++ WRITE_ONCE(rq->ttwu_pending, 1);
++ __smp_call_single_queue(cpu, &p->wake_entry.llist);
++}
++
++static inline bool ttwu_queue_cond(int cpu, int wake_flags)
++{
++ /*
++ * Do not complicate things with the async wake_list while the CPU is
++ * in hotplug state.
++ */
++ if (!cpu_active(cpu))
++ return false;
++
++ /*
++ * If the CPU does not share cache, then queue the task on the
++ * remote rqs wakelist to avoid accessing remote data.
++ */
++ if (!cpus_share_cache(smp_processor_id(), cpu))
++ return true;
++
++ /*
++ * If the task is descheduling and the only running task on the
++ * CPU then use the wakelist to offload the task activation to
++ * the soon-to-be-idle CPU as the current CPU is likely busy.
++ * nr_running is checked to avoid unnecessary task stacking.
++ */
++ if ((wake_flags & WF_ON_CPU) && cpu_rq(cpu)->nr_running <= 1)
++ return true;
++
++ return false;
++}
++
++static bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
++{
++ if (__is_defined(ALT_SCHED_TTWU_QUEUE) && ttwu_queue_cond(cpu, wake_flags)) {
++ if (WARN_ON_ONCE(cpu == smp_processor_id()))
++ return false;
++
++ sched_clock_cpu(cpu); /* Sync clocks across CPUs */
++ __ttwu_queue_wakelist(p, cpu, wake_flags);
++ return true;
++ }
++
++ return false;
++}
++
++void wake_up_if_idle(int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++
++ rcu_read_lock();
++
++ if (!is_idle_task(rcu_dereference(rq->curr)))
++ goto out;
++
++ if (set_nr_if_polling(rq->idle)) {
++ trace_sched_wake_idle_without_ipi(cpu);
++ } else {
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ if (is_idle_task(rq->curr))
++ smp_send_reschedule(cpu);
++ /* Else CPU is not idle, do nothing here */
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++ }
++
++out:
++ rcu_read_unlock();
++}
++
++bool cpus_share_cache(int this_cpu, int that_cpu)
++{
++ return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
++}
++#else /* !CONFIG_SMP */
++
++static inline bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
++{
++ return false;
++}
++
++#endif /* CONFIG_SMP */
++
++static inline void ttwu_queue(struct task_struct *p, int cpu, int wake_flags)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ if (ttwu_queue_wakelist(p, cpu, wake_flags))
++ return;
++
++ raw_spin_lock(&rq->lock);
++ update_rq_clock(rq);
++ ttwu_do_activate(rq, p, wake_flags);
++ raw_spin_unlock(&rq->lock);
++}
++
++/*
++ * Invoked from try_to_wake_up() to check whether the task can be woken up.
++ *
++ * The caller holds p::pi_lock if p != current or has preemption
++ * disabled when p == current.
++ *
++ * The rules of PREEMPT_RT saved_state:
++ *
++ * The related locking code always holds p::pi_lock when updating
++ * p::saved_state, which means the code is fully serialized in both cases.
++ *
++ * The lock wait and lock wakeups happen via TASK_RTLOCK_WAIT. No other
++ * bits set. This allows to distinguish all wakeup scenarios.
++ */
++static __always_inline
++bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
++{
++ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)) {
++ WARN_ON_ONCE((state & TASK_RTLOCK_WAIT) &&
++ state != TASK_RTLOCK_WAIT);
++ }
++
++ if (READ_ONCE(p->__state) & state) {
++ *success = 1;
++ return true;
++ }
++
++#ifdef CONFIG_PREEMPT_RT
++ /*
++ * Saved state preserves the task state across blocking on
++ * an RT lock. If the state matches, set p::saved_state to
++ * TASK_RUNNING, but do not wake the task because it waits
++ * for a lock wakeup. Also indicate success because from
++ * the regular waker's point of view this has succeeded.
++ *
++ * After acquiring the lock the task will restore p::__state
++ * from p::saved_state which ensures that the regular
++ * wakeup is not lost. The restore will also set
++ * p::saved_state to TASK_RUNNING so any further tests will
++ * not result in false positives vs. @success
++ */
++ if (p->saved_state & state) {
++ p->saved_state = TASK_RUNNING;
++ *success = 1;
++ }
++#endif
++ return false;
++}
++
++/*
++ * Notes on Program-Order guarantees on SMP systems.
++ *
++ * MIGRATION
++ *
++ * The basic program-order guarantee on SMP systems is that when a task [t]
++ * migrates, all its activity on its old CPU [c0] happens-before any subsequent
++ * execution on its new CPU [c1].
++ *
++ * For migration (of runnable tasks) this is provided by the following means:
++ *
++ * A) UNLOCK of the rq(c0)->lock scheduling out task t
++ * B) migration for t is required to synchronize *both* rq(c0)->lock and
++ * rq(c1)->lock (if not at the same time, then in that order).
++ * C) LOCK of the rq(c1)->lock scheduling in task
++ *
++ * Transitivity guarantees that B happens after A and C after B.
++ * Note: we only require RCpc transitivity.
++ * Note: the CPU doing B need not be c0 or c1
++ *
++ * Example:
++ *
++ * CPU0 CPU1 CPU2
++ *
++ * LOCK rq(0)->lock
++ * sched-out X
++ * sched-in Y
++ * UNLOCK rq(0)->lock
++ *
++ * LOCK rq(0)->lock // orders against CPU0
++ * dequeue X
++ * UNLOCK rq(0)->lock
++ *
++ * LOCK rq(1)->lock
++ * enqueue X
++ * UNLOCK rq(1)->lock
++ *
++ * LOCK rq(1)->lock // orders against CPU2
++ * sched-out Z
++ * sched-in X
++ * UNLOCK rq(1)->lock
++ *
++ *
++ * BLOCKING -- aka. SLEEP + WAKEUP
++ *
++ * For blocking we (obviously) need to provide the same guarantee as for
++ * migration. However the means are completely different as there is no lock
++ * chain to provide order. Instead we do:
++ *
++ * 1) smp_store_release(X->on_cpu, 0) -- finish_task()
++ * 2) smp_cond_load_acquire(!X->on_cpu) -- try_to_wake_up()
++ *
++ * Example:
++ *
++ * CPU0 (schedule) CPU1 (try_to_wake_up) CPU2 (schedule)
++ *
++ * LOCK rq(0)->lock LOCK X->pi_lock
++ * dequeue X
++ * sched-out X
++ * smp_store_release(X->on_cpu, 0);
++ *
++ * smp_cond_load_acquire(&X->on_cpu, !VAL);
++ * X->state = WAKING
++ * set_task_cpu(X,2)
++ *
++ * LOCK rq(2)->lock
++ * enqueue X
++ * X->state = RUNNING
++ * UNLOCK rq(2)->lock
++ *
++ * LOCK rq(2)->lock // orders against CPU1
++ * sched-out Z
++ * sched-in X
++ * UNLOCK rq(2)->lock
++ *
++ * UNLOCK X->pi_lock
++ * UNLOCK rq(0)->lock
++ *
++ *
++ * However; for wakeups there is a second guarantee we must provide, namely we
++ * must observe the state that lead to our wakeup. That is, not only must our
++ * task observe its own prior state, it must also observe the stores prior to
++ * its wakeup.
++ *
++ * This means that any means of doing remote wakeups must order the CPU doing
++ * the wakeup against the CPU the task is going to end up running on. This,
++ * however, is already required for the regular Program-Order guarantee above,
++ * since the waking CPU is the one issueing the ACQUIRE (smp_cond_load_acquire).
++ *
++ */
++
++/**
++ * try_to_wake_up - wake up a thread
++ * @p: the thread to be awakened
++ * @state: the mask of task states that can be woken
++ * @wake_flags: wake modifier flags (WF_*)
++ *
++ * Conceptually does:
++ *
++ * If (@state & @p->state) @p->state = TASK_RUNNING.
++ *
++ * If the task was not queued/runnable, also place it back on a runqueue.
++ *
++ * This function is atomic against schedule() which would dequeue the task.
++ *
++ * It issues a full memory barrier before accessing @p->state, see the comment
++ * with set_current_state().
++ *
++ * Uses p->pi_lock to serialize against concurrent wake-ups.
++ *
++ * Relies on p->pi_lock stabilizing:
++ * - p->sched_class
++ * - p->cpus_ptr
++ * - p->sched_task_group
++ * in order to do migration, see its use of select_task_rq()/set_task_cpu().
++ *
++ * Tries really hard to only take one task_rq(p)->lock for performance.
++ * Takes rq->lock in:
++ * - ttwu_runnable() -- old rq, unavoidable, see comment there;
++ * - ttwu_queue() -- new rq, for enqueue of the task;
++ * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us.
++ *
++ * As a consequence we race really badly with just about everything. See the
++ * many memory barriers and their comments for details.
++ *
++ * Return: %true if @p->state changes (an actual wakeup was done),
++ * %false otherwise.
++ */
++static int try_to_wake_up(struct task_struct *p, unsigned int state,
++ int wake_flags)
++{
++ unsigned long flags;
++ int cpu, success = 0;
++
++ preempt_disable();
++ if (p == current) {
++ /*
++ * We're waking current, this means 'p->on_rq' and 'task_cpu(p)
++ * == smp_processor_id()'. Together this means we can special
++ * case the whole 'p->on_rq && ttwu_runnable()' case below
++ * without taking any locks.
++ *
++ * In particular:
++ * - we rely on Program-Order guarantees for all the ordering,
++ * - we're serialized against set_special_state() by virtue of
++ * it disabling IRQs (this allows not taking ->pi_lock).
++ */
++ if (!ttwu_state_match(p, state, &success))
++ goto out;
++
++ trace_sched_waking(p);
++ WRITE_ONCE(p->__state, TASK_RUNNING);
++ trace_sched_wakeup(p);
++ goto out;
++ }
++
++ /*
++ * If we are going to wake up a thread waiting for CONDITION we
++ * need to ensure that CONDITION=1 done by the caller can not be
++ * reordered with p->state check below. This pairs with smp_store_mb()
++ * in set_current_state() that the waiting thread does.
++ */
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ smp_mb__after_spinlock();
++ if (!ttwu_state_match(p, state, &success))
++ goto unlock;
++
++ trace_sched_waking(p);
++
++ /*
++ * Ensure we load p->on_rq _after_ p->state, otherwise it would
++ * be possible to, falsely, observe p->on_rq == 0 and get stuck
++ * in smp_cond_load_acquire() below.
++ *
++ * sched_ttwu_pending() try_to_wake_up()
++ * STORE p->on_rq = 1 LOAD p->state
++ * UNLOCK rq->lock
++ *
++ * __schedule() (switch to task 'p')
++ * LOCK rq->lock smp_rmb();
++ * smp_mb__after_spinlock();
++ * UNLOCK rq->lock
++ *
++ * [task p]
++ * STORE p->state = UNINTERRUPTIBLE LOAD p->on_rq
++ *
++ * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
++ * __schedule(). See the comment for smp_mb__after_spinlock().
++ *
++ * A similar smb_rmb() lives in try_invoke_on_locked_down_task().
++ */
++ smp_rmb();
++ if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags))
++ goto unlock;
++
++#ifdef CONFIG_SMP
++ /*
++ * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
++ * possible to, falsely, observe p->on_cpu == 0.
++ *
++ * One must be running (->on_cpu == 1) in order to remove oneself
++ * from the runqueue.
++ *
++ * __schedule() (switch to task 'p') try_to_wake_up()
++ * STORE p->on_cpu = 1 LOAD p->on_rq
++ * UNLOCK rq->lock
++ *
++ * __schedule() (put 'p' to sleep)
++ * LOCK rq->lock smp_rmb();
++ * smp_mb__after_spinlock();
++ * STORE p->on_rq = 0 LOAD p->on_cpu
++ *
++ * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
++ * __schedule(). See the comment for smp_mb__after_spinlock().
++ *
++ * Form a control-dep-acquire with p->on_rq == 0 above, to ensure
++ * schedule()'s deactivate_task() has 'happened' and p will no longer
++ * care about it's own p->state. See the comment in __schedule().
++ */
++ smp_acquire__after_ctrl_dep();
++
++ /*
++ * We're doing the wakeup (@success == 1), they did a dequeue (p->on_rq
++ * == 0), which means we need to do an enqueue, change p->state to
++ * TASK_WAKING such that we can unlock p->pi_lock before doing the
++ * enqueue, such as ttwu_queue_wakelist().
++ */
++ WRITE_ONCE(p->__state, TASK_WAKING);
++
++ /*
++ * If the owning (remote) CPU is still in the middle of schedule() with
++ * this task as prev, considering queueing p on the remote CPUs wake_list
++ * which potentially sends an IPI instead of spinning on p->on_cpu to
++ * let the waker make forward progress. This is safe because IRQs are
++ * disabled and the IPI will deliver after on_cpu is cleared.
++ *
++ * Ensure we load task_cpu(p) after p->on_cpu:
++ *
++ * set_task_cpu(p, cpu);
++ * STORE p->cpu = @cpu
++ * __schedule() (switch to task 'p')
++ * LOCK rq->lock
++ * smp_mb__after_spin_lock() smp_cond_load_acquire(&p->on_cpu)
++ * STORE p->on_cpu = 1 LOAD p->cpu
++ *
++ * to ensure we observe the correct CPU on which the task is currently
++ * scheduling.
++ */
++ if (smp_load_acquire(&p->on_cpu) &&
++ ttwu_queue_wakelist(p, task_cpu(p), wake_flags | WF_ON_CPU))
++ goto unlock;
++
++ /*
++ * If the owning (remote) CPU is still in the middle of schedule() with
++ * this task as prev, wait until it's done referencing the task.
++ *
++ * Pairs with the smp_store_release() in finish_task().
++ *
++ * This ensures that tasks getting woken will be fully ordered against
++ * their previous state and preserve Program Order.
++ */
++ smp_cond_load_acquire(&p->on_cpu, !VAL);
++
++ sched_task_ttwu(p);
++
++ cpu = select_task_rq(p);
++
++ if (cpu != task_cpu(p)) {
++ if (p->in_iowait) {
++ delayacct_blkio_end(p);
++ atomic_dec(&task_rq(p)->nr_iowait);
++ }
++
++ wake_flags |= WF_MIGRATED;
++ psi_ttwu_dequeue(p);
++ set_task_cpu(p, cpu);
++ }
++#else
++ cpu = task_cpu(p);
++#endif /* CONFIG_SMP */
++
++ ttwu_queue(p, cpu, wake_flags);
++unlock:
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++out:
++ if (success)
++ ttwu_stat(p, task_cpu(p), wake_flags);
++ preempt_enable();
++
++ return success;
++}
++
++/**
++ * try_invoke_on_locked_down_task - Invoke a function on task in fixed state
++ * @p: Process for which the function is to be invoked, can be @current.
++ * @func: Function to invoke.
++ * @arg: Argument to function.
++ *
++ * If the specified task can be quickly locked into a definite state
++ * (either sleeping or on a given runqueue), arrange to keep it in that
++ * state while invoking @func(@arg). This function can use ->on_rq and
++ * task_curr() to work out what the state is, if required. Given that
++ * @func can be invoked with a runqueue lock held, it had better be quite
++ * lightweight.
++ *
++ * Returns:
++ * @false if the task slipped out from under the locks.
++ * @true if the task was locked onto a runqueue or is sleeping.
++ * However, @func can override this by returning @false.
++ */
++bool try_invoke_on_locked_down_task(struct task_struct *p, bool (*func)(struct task_struct *t, void *arg), void *arg)
++{
++ struct rq_flags rf;
++ bool ret = false;
++ struct rq *rq;
++
++ raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
++ if (p->on_rq) {
++ rq = __task_rq_lock(p, &rf);
++ if (task_rq(p) == rq)
++ ret = func(p, arg);
++ __task_rq_unlock(rq, &rf);
++ } else {
++ switch (READ_ONCE(p->__state)) {
++ case TASK_RUNNING:
++ case TASK_WAKING:
++ break;
++ default:
++ smp_rmb(); // See smp_rmb() comment in try_to_wake_up().
++ if (!p->on_rq)
++ ret = func(p, arg);
++ }
++ }
++ raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
++ return ret;
++}
++
++/**
++ * wake_up_process - Wake up a specific process
++ * @p: The process to be woken up.
++ *
++ * Attempt to wake up the nominated process and move it to the set of runnable
++ * processes.
++ *
++ * Return: 1 if the process was woken up, 0 if it was already running.
++ *
++ * This function executes a full memory barrier before accessing the task state.
++ */
++int wake_up_process(struct task_struct *p)
++{
++ return try_to_wake_up(p, TASK_NORMAL, 0);
++}
++EXPORT_SYMBOL(wake_up_process);
++
++int wake_up_state(struct task_struct *p, unsigned int state)
++{
++ return try_to_wake_up(p, state, 0);
++}
++
++/*
++ * Perform scheduler related setup for a newly forked process p.
++ * p is forked by current.
++ *
++ * __sched_fork() is basic setup used by init_idle() too:
++ */
++static inline void __sched_fork(unsigned long clone_flags, struct task_struct *p)
++{
++ p->on_rq = 0;
++ p->on_cpu = 0;
++ p->utime = 0;
++ p->stime = 0;
++ p->sched_time = 0;
++
++#ifdef CONFIG_PREEMPT_NOTIFIERS
++ INIT_HLIST_HEAD(&p->preempt_notifiers);
++#endif
++
++#ifdef CONFIG_COMPACTION
++ p->capture_control = NULL;
++#endif
++#ifdef CONFIG_SMP
++ p->wake_entry.u_flags = CSD_TYPE_TTWU;
++#endif
++}
++
++/*
++ * fork()/clone()-time setup:
++ */
++int sched_fork(unsigned long clone_flags, struct task_struct *p)
++{
++ __sched_fork(clone_flags, p);
++ /*
++ * We mark the process as NEW here. This guarantees that
++ * nobody will actually run it, and a signal or other external
++ * event cannot wake it up and insert it on the runqueue either.
++ */
++ p->__state = TASK_NEW;
++
++ /*
++ * Make sure we do not leak PI boosting priority to the child.
++ */
++ p->prio = current->normal_prio;
++
++ /*
++ * Revert to default priority/policy on fork if requested.
++ */
++ if (unlikely(p->sched_reset_on_fork)) {
++ if (task_has_rt_policy(p)) {
++ p->policy = SCHED_NORMAL;
++ p->static_prio = NICE_TO_PRIO(0);
++ p->rt_priority = 0;
++ } else if (PRIO_TO_NICE(p->static_prio) < 0)
++ p->static_prio = NICE_TO_PRIO(0);
++
++ p->prio = p->normal_prio = p->static_prio;
++
++ /*
++ * We don't need the reset flag anymore after the fork. It has
++ * fulfilled its duty:
++ */
++ p->sched_reset_on_fork = 0;
++ }
++
++#ifdef CONFIG_SCHED_INFO
++ if (unlikely(sched_info_on()))
++ memset(&p->sched_info, 0, sizeof(p->sched_info));
++#endif
++ init_task_preempt_count(p);
++
++ return 0;
++}
++
++void sched_post_fork(struct task_struct *p, struct kernel_clone_args *kargs)
++{
++ unsigned long flags;
++ struct rq *rq;
++
++ /*
++ * The child is not yet in the pid-hash so no cgroup attach races,
++ * and the cgroup is pinned to this child due to cgroup_fork()
++ * is ran before sched_fork().
++ *
++ * Silence PROVE_RCU.
++ */
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ /*
++ * Share the timeslice between parent and child, thus the
++ * total amount of pending timeslices in the system doesn't change,
++ * resulting in more scheduling fairness.
++ */
++ rq = this_rq();
++ raw_spin_lock(&rq->lock);
++
++ rq->curr->time_slice /= 2;
++ p->time_slice = rq->curr->time_slice;
++#ifdef CONFIG_SCHED_HRTICK
++ hrtick_start(rq, rq->curr->time_slice);
++#endif
++
++ if (p->time_slice < RESCHED_NS) {
++ p->time_slice = sched_timeslice_ns;
++ resched_curr(rq);
++ }
++ sched_task_fork(p, rq);
++ raw_spin_unlock(&rq->lock);
++
++ rseq_migrate(p);
++ /*
++ * We're setting the CPU for the first time, we don't migrate,
++ * so use __set_task_cpu().
++ */
++ __set_task_cpu(p, smp_processor_id());
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++}
++
++#ifdef CONFIG_SCHEDSTATS
++
++DEFINE_STATIC_KEY_FALSE(sched_schedstats);
++
++static void set_schedstats(bool enabled)
++{
++ if (enabled)
++ static_branch_enable(&sched_schedstats);
++ else
++ static_branch_disable(&sched_schedstats);
++}
++
++void force_schedstat_enabled(void)
++{
++ if (!schedstat_enabled()) {
++ pr_info("kernel profiling enabled schedstats, disable via kernel.sched_schedstats.\n");
++ static_branch_enable(&sched_schedstats);
++ }
++}
++
++static int __init setup_schedstats(char *str)
++{
++ int ret = 0;
++ if (!str)
++ goto out;
++
++ if (!strcmp(str, "enable")) {
++ set_schedstats(true);
++ ret = 1;
++ } else if (!strcmp(str, "disable")) {
++ set_schedstats(false);
++ ret = 1;
++ }
++out:
++ if (!ret)
++ pr_warn("Unable to parse schedstats=\n");
++
++ return ret;
++}
++__setup("schedstats=", setup_schedstats);
++
++#ifdef CONFIG_PROC_SYSCTL
++int sysctl_schedstats(struct ctl_table *table, int write,
++ void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++ struct ctl_table t;
++ int err;
++ int state = static_branch_likely(&sched_schedstats);
++
++ if (write && !capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ t = *table;
++ t.data = &state;
++ err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
++ if (err < 0)
++ return err;
++ if (write)
++ set_schedstats(state);
++ return err;
++}
++#endif /* CONFIG_PROC_SYSCTL */
++#endif /* CONFIG_SCHEDSTATS */
++
++/*
++ * wake_up_new_task - wake up a newly created task for the first time.
++ *
++ * This function will do some initial scheduler statistics housekeeping
++ * that must be done for every newly created context, then puts the task
++ * on the runqueue and wakes it.
++ */
++void wake_up_new_task(struct task_struct *p)
++{
++ unsigned long flags;
++ struct rq *rq;
++
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ WRITE_ONCE(p->__state, TASK_RUNNING);
++ rq = cpu_rq(select_task_rq(p));
++#ifdef CONFIG_SMP
++ rseq_migrate(p);
++ /*
++ * Fork balancing, do it here and not earlier because:
++ * - cpus_ptr can change in the fork path
++ * - any previously selected CPU might disappear through hotplug
++ *
++ * Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq,
++ * as we're not fully set-up yet.
++ */
++ __set_task_cpu(p, cpu_of(rq));
++#endif
++
++ raw_spin_lock(&rq->lock);
++ update_rq_clock(rq);
++
++ activate_task(p, rq);
++ trace_sched_wakeup_new(p);
++ check_preempt_curr(rq);
++
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++}
++
++#ifdef CONFIG_PREEMPT_NOTIFIERS
++
++static DEFINE_STATIC_KEY_FALSE(preempt_notifier_key);
++
++void preempt_notifier_inc(void)
++{
++ static_branch_inc(&preempt_notifier_key);
++}
++EXPORT_SYMBOL_GPL(preempt_notifier_inc);
++
++void preempt_notifier_dec(void)
++{
++ static_branch_dec(&preempt_notifier_key);
++}
++EXPORT_SYMBOL_GPL(preempt_notifier_dec);
++
++/**
++ * preempt_notifier_register - tell me when current is being preempted & rescheduled
++ * @notifier: notifier struct to register
++ */
++void preempt_notifier_register(struct preempt_notifier *notifier)
++{
++ if (!static_branch_unlikely(&preempt_notifier_key))
++ WARN(1, "registering preempt_notifier while notifiers disabled\n");
++
++ hlist_add_head(&notifier->link, &current->preempt_notifiers);
++}
++EXPORT_SYMBOL_GPL(preempt_notifier_register);
++
++/**
++ * preempt_notifier_unregister - no longer interested in preemption notifications
++ * @notifier: notifier struct to unregister
++ *
++ * This is *not* safe to call from within a preemption notifier.
++ */
++void preempt_notifier_unregister(struct preempt_notifier *notifier)
++{
++ hlist_del(&notifier->link);
++}
++EXPORT_SYMBOL_GPL(preempt_notifier_unregister);
++
++static void __fire_sched_in_preempt_notifiers(struct task_struct *curr)
++{
++ struct preempt_notifier *notifier;
++
++ hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
++ notifier->ops->sched_in(notifier, raw_smp_processor_id());
++}
++
++static __always_inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
++{
++ if (static_branch_unlikely(&preempt_notifier_key))
++ __fire_sched_in_preempt_notifiers(curr);
++}
++
++static void
++__fire_sched_out_preempt_notifiers(struct task_struct *curr,
++ struct task_struct *next)
++{
++ struct preempt_notifier *notifier;
++
++ hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
++ notifier->ops->sched_out(notifier, next);
++}
++
++static __always_inline void
++fire_sched_out_preempt_notifiers(struct task_struct *curr,
++ struct task_struct *next)
++{
++ if (static_branch_unlikely(&preempt_notifier_key))
++ __fire_sched_out_preempt_notifiers(curr, next);
++}
++
++#else /* !CONFIG_PREEMPT_NOTIFIERS */
++
++static inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
++{
++}
++
++static inline void
++fire_sched_out_preempt_notifiers(struct task_struct *curr,
++ struct task_struct *next)
++{
++}
++
++#endif /* CONFIG_PREEMPT_NOTIFIERS */
++
++static inline void prepare_task(struct task_struct *next)
++{
++ /*
++ * Claim the task as running, we do this before switching to it
++ * such that any running task will have this set.
++ *
++ * See the ttwu() WF_ON_CPU case and its ordering comment.
++ */
++ WRITE_ONCE(next->on_cpu, 1);
++}
++
++static inline void finish_task(struct task_struct *prev)
++{
++#ifdef CONFIG_SMP
++ /*
++ * This must be the very last reference to @prev from this CPU. After
++ * p->on_cpu is cleared, the task can be moved to a different CPU. We
++ * must ensure this doesn't happen until the switch is completely
++ * finished.
++ *
++ * In particular, the load of prev->state in finish_task_switch() must
++ * happen before this.
++ *
++ * Pairs with the smp_cond_load_acquire() in try_to_wake_up().
++ */
++ smp_store_release(&prev->on_cpu, 0);
++#else
++ prev->on_cpu = 0;
++#endif
++}
++
++#ifdef CONFIG_SMP
++
++static void do_balance_callbacks(struct rq *rq, struct callback_head *head)
++{
++ void (*func)(struct rq *rq);
++ struct callback_head *next;
++
++ lockdep_assert_held(&rq->lock);
++
++ while (head) {
++ func = (void (*)(struct rq *))head->func;
++ next = head->next;
++ head->next = NULL;
++ head = next;
++
++ func(rq);
++ }
++}
++
++static void balance_push(struct rq *rq);
++
++struct callback_head balance_push_callback = {
++ .next = NULL,
++ .func = (void (*)(struct callback_head *))balance_push,
++};
++
++static inline struct callback_head *splice_balance_callbacks(struct rq *rq)
++{
++ struct callback_head *head = rq->balance_callback;
++
++ if (head) {
++ lockdep_assert_held(&rq->lock);
++ rq->balance_callback = NULL;
++ }
++
++ return head;
++}
++
++static void __balance_callbacks(struct rq *rq)
++{
++ do_balance_callbacks(rq, splice_balance_callbacks(rq));
++}
++
++static inline void balance_callbacks(struct rq *rq, struct callback_head *head)
++{
++ unsigned long flags;
++
++ if (unlikely(head)) {
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ do_balance_callbacks(rq, head);
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++ }
++}
++
++#else
++
++static inline void __balance_callbacks(struct rq *rq)
++{
++}
++
++static inline struct callback_head *splice_balance_callbacks(struct rq *rq)
++{
++ return NULL;
++}
++
++static inline void balance_callbacks(struct rq *rq, struct callback_head *head)
++{
++}
++
++#endif
++
++static inline void
++prepare_lock_switch(struct rq *rq, struct task_struct *next)
++{
++ /*
++ * Since the runqueue lock will be released by the next
++ * task (which is an invalid locking op but in the case
++ * of the scheduler it's an obvious special-case), so we
++ * do an early lockdep release here:
++ */
++ spin_release(&rq->lock.dep_map, _THIS_IP_);
++#ifdef CONFIG_DEBUG_SPINLOCK
++ /* this is a valid case when another task releases the spinlock */
++ rq->lock.owner = next;
++#endif
++}
++
++static inline void finish_lock_switch(struct rq *rq)
++{
++ /*
++ * If we are tracking spinlock dependencies then we have to
++ * fix up the runqueue lock - which gets 'carried over' from
++ * prev into current:
++ */
++ spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
++ __balance_callbacks(rq);
++ raw_spin_unlock_irq(&rq->lock);
++}
++
++/*
++ * NOP if the arch has not defined these:
++ */
++
++#ifndef prepare_arch_switch
++# define prepare_arch_switch(next) do { } while (0)
++#endif
++
++#ifndef finish_arch_post_lock_switch
++# define finish_arch_post_lock_switch() do { } while (0)
++#endif
++
++static inline void kmap_local_sched_out(void)
++{
++#ifdef CONFIG_KMAP_LOCAL
++ if (unlikely(current->kmap_ctrl.idx))
++ __kmap_local_sched_out();
++#endif
++}
++
++static inline void kmap_local_sched_in(void)
++{
++#ifdef CONFIG_KMAP_LOCAL
++ if (unlikely(current->kmap_ctrl.idx))
++ __kmap_local_sched_in();
++#endif
++}
++
++/**
++ * prepare_task_switch - prepare to switch tasks
++ * @rq: the runqueue preparing to switch
++ * @next: the task we are going to switch to.
++ *
++ * This is called with the rq lock held and interrupts off. It must
++ * be paired with a subsequent finish_task_switch after the context
++ * switch.
++ *
++ * prepare_task_switch sets up locking and calls architecture specific
++ * hooks.
++ */
++static inline void
++prepare_task_switch(struct rq *rq, struct task_struct *prev,
++ struct task_struct *next)
++{
++ kcov_prepare_switch(prev);
++ sched_info_switch(rq, prev, next);
++ perf_event_task_sched_out(prev, next);
++ rseq_preempt(prev);
++ fire_sched_out_preempt_notifiers(prev, next);
++ kmap_local_sched_out();
++ prepare_task(next);
++ prepare_arch_switch(next);
++}
++
++/**
++ * finish_task_switch - clean up after a task-switch
++ * @rq: runqueue associated with task-switch
++ * @prev: the thread we just switched away from.
++ *
++ * finish_task_switch must be called after the context switch, paired
++ * with a prepare_task_switch call before the context switch.
++ * finish_task_switch will reconcile locking set up by prepare_task_switch,
++ * and do any other architecture-specific cleanup actions.
++ *
++ * Note that we may have delayed dropping an mm in context_switch(). If
++ * so, we finish that here outside of the runqueue lock. (Doing it
++ * with the lock held can cause deadlocks; see schedule() for
++ * details.)
++ *
++ * The context switch have flipped the stack from under us and restored the
++ * local variables which were saved when this task called schedule() in the
++ * past. prev == current is still correct but we need to recalculate this_rq
++ * because prev may have moved to another CPU.
++ */
++static struct rq *finish_task_switch(struct task_struct *prev)
++ __releases(rq->lock)
++{
++ struct rq *rq = this_rq();
++ struct mm_struct *mm = rq->prev_mm;
++ long prev_state;
++
++ /*
++ * The previous task will have left us with a preempt_count of 2
++ * because it left us after:
++ *
++ * schedule()
++ * preempt_disable(); // 1
++ * __schedule()
++ * raw_spin_lock_irq(&rq->lock) // 2
++ *
++ * Also, see FORK_PREEMPT_COUNT.
++ */
++ if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
++ "corrupted preempt_count: %s/%d/0x%x\n",
++ current->comm, current->pid, preempt_count()))
++ preempt_count_set(FORK_PREEMPT_COUNT);
++
++ rq->prev_mm = NULL;
++
++ /*
++ * A task struct has one reference for the use as "current".
++ * If a task dies, then it sets TASK_DEAD in tsk->state and calls
++ * schedule one last time. The schedule call will never return, and
++ * the scheduled task must drop that reference.
++ *
++ * We must observe prev->state before clearing prev->on_cpu (in
++ * finish_task), otherwise a concurrent wakeup can get prev
++ * running on another CPU and we could rave with its RUNNING -> DEAD
++ * transition, resulting in a double drop.
++ */
++ prev_state = READ_ONCE(prev->__state);
++ vtime_task_switch(prev);
++ perf_event_task_sched_in(prev, current);
++ finish_task(prev);
++ tick_nohz_task_switch();
++ finish_lock_switch(rq);
++ finish_arch_post_lock_switch();
++ kcov_finish_switch(current);
++ /*
++ * kmap_local_sched_out() is invoked with rq::lock held and
++ * interrupts disabled. There is no requirement for that, but the
++ * sched out code does not have an interrupt enabled section.
++ * Restoring the maps on sched in does not require interrupts being
++ * disabled either.
++ */
++ kmap_local_sched_in();
++
++ fire_sched_in_preempt_notifiers(current);
++ /*
++ * When switching through a kernel thread, the loop in
++ * membarrier_{private,global}_expedited() may have observed that
++ * kernel thread and not issued an IPI. It is therefore possible to
++ * schedule between user->kernel->user threads without passing though
++ * switch_mm(). Membarrier requires a barrier after storing to
++ * rq->curr, before returning to userspace, so provide them here:
++ *
++ * - a full memory barrier for {PRIVATE,GLOBAL}_EXPEDITED, implicitly
++ * provided by mmdrop(),
++ * - a sync_core for SYNC_CORE.
++ */
++ if (mm) {
++ membarrier_mm_sync_core_before_usermode(mm);
++ mmdrop(mm);
++ }
++ if (unlikely(prev_state == TASK_DEAD)) {
++ /*
++ * Remove function-return probe instances associated with this
++ * task and put them back on the free list.
++ */
++ kprobe_flush_task(prev);
++
++ /* Task is done with its stack. */
++ put_task_stack(prev);
++
++ put_task_struct_rcu_user(prev);
++ }
++
++ return rq;
++}
++
++/**
++ * schedule_tail - first thing a freshly forked thread must call.
++ * @prev: the thread we just switched away from.
++ */
++asmlinkage __visible void schedule_tail(struct task_struct *prev)
++ __releases(rq->lock)
++{
++ /*
++ * New tasks start with FORK_PREEMPT_COUNT, see there and
++ * finish_task_switch() for details.
++ *
++ * finish_task_switch() will drop rq->lock() and lower preempt_count
++ * and the preempt_enable() will end up enabling preemption (on
++ * PREEMPT_COUNT kernels).
++ */
++
++ finish_task_switch(prev);
++ preempt_enable();
++
++ if (current->set_child_tid)
++ put_user(task_pid_vnr(current), current->set_child_tid);
++
++ calculate_sigpending();
++}
++
++/*
++ * context_switch - switch to the new MM and the new thread's register state.
++ */
++static __always_inline struct rq *
++context_switch(struct rq *rq, struct task_struct *prev,
++ struct task_struct *next)
++{
++ prepare_task_switch(rq, prev, next);
++
++ /*
++ * For paravirt, this is coupled with an exit in switch_to to
++ * combine the page table reload and the switch backend into
++ * one hypercall.
++ */
++ arch_start_context_switch(prev);
++
++ /*
++ * kernel -> kernel lazy + transfer active
++ * user -> kernel lazy + mmgrab() active
++ *
++ * kernel -> user switch + mmdrop() active
++ * user -> user switch
++ */
++ if (!next->mm) { // to kernel
++ enter_lazy_tlb(prev->active_mm, next);
++
++ next->active_mm = prev->active_mm;
++ if (prev->mm) // from user
++ mmgrab(prev->active_mm);
++ else
++ prev->active_mm = NULL;
++ } else { // to user
++ membarrier_switch_mm(rq, prev->active_mm, next->mm);
++ /*
++ * sys_membarrier() requires an smp_mb() between setting
++ * rq->curr / membarrier_switch_mm() and returning to userspace.
++ *
++ * The below provides this either through switch_mm(), or in
++ * case 'prev->active_mm == next->mm' through
++ * finish_task_switch()'s mmdrop().
++ */
++ switch_mm_irqs_off(prev->active_mm, next->mm, next);
++
++ if (!prev->mm) { // from kernel
++ /* will mmdrop() in finish_task_switch(). */
++ rq->prev_mm = prev->active_mm;
++ prev->active_mm = NULL;
++ }
++ }
++
++ prepare_lock_switch(rq, next);
++
++ /* Here we just switch the register state and the stack. */
++ switch_to(prev, next, prev);
++ barrier();
++
++ return finish_task_switch(prev);
++}
++
++/*
++ * nr_running, nr_uninterruptible and nr_context_switches:
++ *
++ * externally visible scheduler statistics: current number of runnable
++ * threads, total number of context switches performed since bootup.
++ */
++unsigned int nr_running(void)
++{
++ unsigned int i, sum = 0;
++
++ for_each_online_cpu(i)
++ sum += cpu_rq(i)->nr_running;
++
++ return sum;
++}
++
++/*
++ * Check if only the current task is running on the CPU.
++ *
++ * Caution: this function does not check that the caller has disabled
++ * preemption, thus the result might have a time-of-check-to-time-of-use
++ * race. The caller is responsible to use it correctly, for example:
++ *
++ * - from a non-preemptible section (of course)
++ *
++ * - from a thread that is bound to a single CPU
++ *
++ * - in a loop with very short iterations (e.g. a polling loop)
++ */
++bool single_task_running(void)
++{
++ return raw_rq()->nr_running == 1;
++}
++EXPORT_SYMBOL(single_task_running);
++
++unsigned long long nr_context_switches(void)
++{
++ int i;
++ unsigned long long sum = 0;
++
++ for_each_possible_cpu(i)
++ sum += cpu_rq(i)->nr_switches;
++
++ return sum;
++}
++
++/*
++ * Consumers of these two interfaces, like for example the cpuidle menu
++ * governor, are using nonsensical data. Preferring shallow idle state selection
++ * for a CPU that has IO-wait which might not even end up running the task when
++ * it does become runnable.
++ */
++
++unsigned int nr_iowait_cpu(int cpu)
++{
++ return atomic_read(&cpu_rq(cpu)->nr_iowait);
++}
++
++/*
++ * IO-wait accounting, and how it's mostly bollocks (on SMP).
++ *
++ * The idea behind IO-wait account is to account the idle time that we could
++ * have spend running if it were not for IO. That is, if we were to improve the
++ * storage performance, we'd have a proportional reduction in IO-wait time.
++ *
++ * This all works nicely on UP, where, when a task blocks on IO, we account
++ * idle time as IO-wait, because if the storage were faster, it could've been
++ * running and we'd not be idle.
++ *
++ * This has been extended to SMP, by doing the same for each CPU. This however
++ * is broken.
++ *
++ * Imagine for instance the case where two tasks block on one CPU, only the one
++ * CPU will have IO-wait accounted, while the other has regular idle. Even
++ * though, if the storage were faster, both could've ran at the same time,
++ * utilising both CPUs.
++ *
++ * This means, that when looking globally, the current IO-wait accounting on
++ * SMP is a lower bound, by reason of under accounting.
++ *
++ * Worse, since the numbers are provided per CPU, they are sometimes
++ * interpreted per CPU, and that is nonsensical. A blocked task isn't strictly
++ * associated with any one particular CPU, it can wake to another CPU than it
++ * blocked on. This means the per CPU IO-wait number is meaningless.
++ *
++ * Task CPU affinities can make all that even more 'interesting'.
++ */
++
++unsigned int nr_iowait(void)
++{
++ unsigned int i, sum = 0;
++
++ for_each_possible_cpu(i)
++ sum += nr_iowait_cpu(i);
++
++ return sum;
++}
++
++#ifdef CONFIG_SMP
++
++/*
++ * sched_exec - execve() is a valuable balancing opportunity, because at
++ * this point the task has the smallest effective memory and cache
++ * footprint.
++ */
++void sched_exec(void)
++{
++ struct task_struct *p = current;
++ unsigned long flags;
++ int dest_cpu;
++
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ dest_cpu = cpumask_any(p->cpus_ptr);
++ if (dest_cpu == smp_processor_id())
++ goto unlock;
++
++ if (likely(cpu_active(dest_cpu))) {
++ struct migration_arg arg = { p, dest_cpu };
++
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++ stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg);
++ return;
++ }
++unlock:
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++}
++
++#endif
++
++DEFINE_PER_CPU(struct kernel_stat, kstat);
++DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
++
++EXPORT_PER_CPU_SYMBOL(kstat);
++EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
++
++static inline void update_curr(struct rq *rq, struct task_struct *p)
++{
++ s64 ns = rq->clock_task - p->last_ran;
++
++ p->sched_time += ns;
++ cgroup_account_cputime(p, ns);
++ account_group_exec_runtime(p, ns);
++
++ p->time_slice -= ns;
++ p->last_ran = rq->clock_task;
++}
++
++/*
++ * Return accounted runtime for the task.
++ * Return separately the current's pending runtime that have not been
++ * accounted yet.
++ */
++unsigned long long task_sched_runtime(struct task_struct *p)
++{
++ unsigned long flags;
++ struct rq *rq;
++ raw_spinlock_t *lock;
++ u64 ns;
++
++#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
++ /*
++ * 64-bit doesn't need locks to atomically read a 64-bit value.
++ * So we have a optimization chance when the task's delta_exec is 0.
++ * Reading ->on_cpu is racy, but this is ok.
++ *
++ * If we race with it leaving CPU, we'll take a lock. So we're correct.
++ * If we race with it entering CPU, unaccounted time is 0. This is
++ * indistinguishable from the read occurring a few cycles earlier.
++ * If we see ->on_cpu without ->on_rq, the task is leaving, and has
++ * been accounted, so we're correct here as well.
++ */
++ if (!p->on_cpu || !task_on_rq_queued(p))
++ return tsk_seruntime(p);
++#endif
++
++ rq = task_access_lock_irqsave(p, &lock, &flags);
++ /*
++ * Must be ->curr _and_ ->on_rq. If dequeued, we would
++ * project cycles that may never be accounted to this
++ * thread, breaking clock_gettime().
++ */
++ if (p == rq->curr && task_on_rq_queued(p)) {
++ update_rq_clock(rq);
++ update_curr(rq, p);
++ }
++ ns = tsk_seruntime(p);
++ task_access_unlock_irqrestore(p, lock, &flags);
++
++ return ns;
++}
++
++/* This manages tasks that have run out of timeslice during a scheduler_tick */
++static inline void scheduler_task_tick(struct rq *rq)
++{
++ struct task_struct *p = rq->curr;
++
++ if (is_idle_task(p))
++ return;
++
++ update_curr(rq, p);
++ cpufreq_update_util(rq, 0);
++
++ /*
++ * Tasks have less than RESCHED_NS of time slice left they will be
++ * rescheduled.
++ */
++ if (p->time_slice >= RESCHED_NS)
++ return;
++ set_tsk_need_resched(p);
++ set_preempt_need_resched();
++}
++
++#ifdef CONFIG_SCHED_DEBUG
++static u64 cpu_resched_latency(struct rq *rq)
++{
++ int latency_warn_ms = READ_ONCE(sysctl_resched_latency_warn_ms);
++ u64 resched_latency, now = rq_clock(rq);
++ static bool warned_once;
++
++ if (sysctl_resched_latency_warn_once && warned_once)
++ return 0;
++
++ if (!need_resched() || !latency_warn_ms)
++ return 0;
++
++ if (system_state == SYSTEM_BOOTING)
++ return 0;
++
++ if (!rq->last_seen_need_resched_ns) {
++ rq->last_seen_need_resched_ns = now;
++ rq->ticks_without_resched = 0;
++ return 0;
++ }
++
++ rq->ticks_without_resched++;
++ resched_latency = now - rq->last_seen_need_resched_ns;
++ if (resched_latency <= latency_warn_ms * NSEC_PER_MSEC)
++ return 0;
++
++ warned_once = true;
++
++ return resched_latency;
++}
++
++static int __init setup_resched_latency_warn_ms(char *str)
++{
++ long val;
++
++ if ((kstrtol(str, 0, &val))) {
++ pr_warn("Unable to set resched_latency_warn_ms\n");
++ return 1;
++ }
++
++ sysctl_resched_latency_warn_ms = val;
++ return 1;
++}
++__setup("resched_latency_warn_ms=", setup_resched_latency_warn_ms);
++#else
++static inline u64 cpu_resched_latency(struct rq *rq) { return 0; }
++#endif /* CONFIG_SCHED_DEBUG */
++
++/*
++ * This function gets called by the timer code, with HZ frequency.
++ * We call it with interrupts disabled.
++ */
++void scheduler_tick(void)
++{
++ int cpu __maybe_unused = smp_processor_id();
++ struct rq *rq = cpu_rq(cpu);
++ u64 resched_latency;
++
++ arch_scale_freq_tick();
++ sched_clock_tick();
++
++ raw_spin_lock(&rq->lock);
++ update_rq_clock(rq);
++
++ scheduler_task_tick(rq);
++ if (sched_feat(LATENCY_WARN))
++ resched_latency = cpu_resched_latency(rq);
++ calc_global_load_tick(rq);
++
++ rq->last_tick = rq->clock;
++ raw_spin_unlock(&rq->lock);
++
++ if (sched_feat(LATENCY_WARN) && resched_latency)
++ resched_latency_warn(cpu, resched_latency);
++
++ perf_event_task_tick();
++}
++
++#ifdef CONFIG_SCHED_SMT
++static inline int active_load_balance_cpu_stop(void *data)
++{
++ struct rq *rq = this_rq();
++ struct task_struct *p = data;
++ cpumask_t tmp;
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ raw_spin_lock(&p->pi_lock);
++ raw_spin_lock(&rq->lock);
++
++ rq->active_balance = 0;
++ /* _something_ may have changed the task, double check again */
++ if (task_on_rq_queued(p) && task_rq(p) == rq &&
++ cpumask_and(&tmp, p->cpus_ptr, &sched_sg_idle_mask) &&
++ !is_migration_disabled(p)) {
++ int cpu = cpu_of(rq);
++ int dcpu = __best_mask_cpu(&tmp, per_cpu(sched_cpu_llc_mask, cpu));
++ rq = move_queued_task(rq, p, dcpu);
++ }
++
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock(&p->pi_lock);
++
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++/* sg_balance_trigger - trigger slibing group balance for @cpu */
++static inline int sg_balance_trigger(const int cpu)
++{
++ struct rq *rq= cpu_rq(cpu);
++ unsigned long flags;
++ struct task_struct *curr;
++ int res;
++
++ if (!raw_spin_trylock_irqsave(&rq->lock, flags))
++ return 0;
++ curr = rq->curr;
++ res = (!is_idle_task(curr)) && (1 == rq->nr_running) &&\
++ cpumask_intersects(curr->cpus_ptr, &sched_sg_idle_mask) &&\
++ !is_migration_disabled(curr) && (!rq->active_balance);
++
++ if (res)
++ rq->active_balance = 1;
++
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++
++ if (res)
++ stop_one_cpu_nowait(cpu, active_load_balance_cpu_stop,
++ curr, &rq->active_balance_work);
++ return res;
++}
++
++/*
++ * sg_balance_check - slibing group balance check for run queue @rq
++ */
++static inline void sg_balance_check(struct rq *rq)
++{
++ cpumask_t chk;
++ int cpu = cpu_of(rq);
++
++ /* exit when cpu is offline */
++ if (unlikely(!rq->online))
++ return;
++
++ /*
++ * Only cpu in slibing idle group will do the checking and then
++ * find potential cpus which can migrate the current running task
++ */
++ if (cpumask_test_cpu(cpu, &sched_sg_idle_mask) &&
++ cpumask_andnot(&chk, cpu_online_mask, sched_rq_watermark) &&
++ cpumask_andnot(&chk, &chk, &sched_rq_pending_mask)) {
++ int i;
++
++ for_each_cpu_wrap(i, &chk, cpu) {
++ if (cpumask_subset(cpu_smt_mask(i), &chk) &&
++ sg_balance_trigger(i))
++ return;
++ }
++ }
++}
++#endif /* CONFIG_SCHED_SMT */
++
++#ifdef CONFIG_NO_HZ_FULL
++
++struct tick_work {
++ int cpu;
++ atomic_t state;
++ struct delayed_work work;
++};
++/* Values for ->state, see diagram below. */
++#define TICK_SCHED_REMOTE_OFFLINE 0
++#define TICK_SCHED_REMOTE_OFFLINING 1
++#define TICK_SCHED_REMOTE_RUNNING 2
++
++/*
++ * State diagram for ->state:
++ *
++ *
++ * TICK_SCHED_REMOTE_OFFLINE
++ * | ^
++ * | |
++ * | | sched_tick_remote()
++ * | |
++ * | |
++ * +--TICK_SCHED_REMOTE_OFFLINING
++ * | ^
++ * | |
++ * sched_tick_start() | | sched_tick_stop()
++ * | |
++ * V |
++ * TICK_SCHED_REMOTE_RUNNING
++ *
++ *
++ * Other transitions get WARN_ON_ONCE(), except that sched_tick_remote()
++ * and sched_tick_start() are happy to leave the state in RUNNING.
++ */
++
++static struct tick_work __percpu *tick_work_cpu;
++
++static void sched_tick_remote(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct tick_work *twork = container_of(dwork, struct tick_work, work);
++ int cpu = twork->cpu;
++ struct rq *rq = cpu_rq(cpu);
++ struct task_struct *curr;
++ unsigned long flags;
++ u64 delta;
++ int os;
++
++ /*
++ * Handle the tick only if it appears the remote CPU is running in full
++ * dynticks mode. The check is racy by nature, but missing a tick or
++ * having one too much is no big deal because the scheduler tick updates
++ * statistics and checks timeslices in a time-independent way, regardless
++ * of when exactly it is running.
++ */
++ if (!tick_nohz_tick_stopped_cpu(cpu))
++ goto out_requeue;
++
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ curr = rq->curr;
++ if (cpu_is_offline(cpu))
++ goto out_unlock;
++
++ update_rq_clock(rq);
++ if (!is_idle_task(curr)) {
++ /*
++ * Make sure the next tick runs within a reasonable
++ * amount of time.
++ */
++ delta = rq_clock_task(rq) - curr->last_ran;
++ WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 3);
++ }
++ scheduler_task_tick(rq);
++
++ calc_load_nohz_remote(rq);
++out_unlock:
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++
++out_requeue:
++ /*
++ * Run the remote tick once per second (1Hz). This arbitrary
++ * frequency is large enough to avoid overload but short enough
++ * to keep scheduler internal stats reasonably up to date. But
++ * first update state to reflect hotplug activity if required.
++ */
++ os = atomic_fetch_add_unless(&twork->state, -1, TICK_SCHED_REMOTE_RUNNING);
++ WARN_ON_ONCE(os == TICK_SCHED_REMOTE_OFFLINE);
++ if (os == TICK_SCHED_REMOTE_RUNNING)
++ queue_delayed_work(system_unbound_wq, dwork, HZ);
++}
++
++static void sched_tick_start(int cpu)
++{
++ int os;
++ struct tick_work *twork;
++
++ if (housekeeping_cpu(cpu, HK_FLAG_TICK))
++ return;
++
++ WARN_ON_ONCE(!tick_work_cpu);
++
++ twork = per_cpu_ptr(tick_work_cpu, cpu);
++ os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_RUNNING);
++ WARN_ON_ONCE(os == TICK_SCHED_REMOTE_RUNNING);
++ if (os == TICK_SCHED_REMOTE_OFFLINE) {
++ twork->cpu = cpu;
++ INIT_DELAYED_WORK(&twork->work, sched_tick_remote);
++ queue_delayed_work(system_unbound_wq, &twork->work, HZ);
++ }
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static void sched_tick_stop(int cpu)
++{
++ struct tick_work *twork;
++
++ if (housekeeping_cpu(cpu, HK_FLAG_TICK))
++ return;
++
++ WARN_ON_ONCE(!tick_work_cpu);
++
++ twork = per_cpu_ptr(tick_work_cpu, cpu);
++ cancel_delayed_work_sync(&twork->work);
++}
++#endif /* CONFIG_HOTPLUG_CPU */
++
++int __init sched_tick_offload_init(void)
++{
++ tick_work_cpu = alloc_percpu(struct tick_work);
++ BUG_ON(!tick_work_cpu);
++ return 0;
++}
++
++#else /* !CONFIG_NO_HZ_FULL */
++static inline void sched_tick_start(int cpu) { }
++static inline void sched_tick_stop(int cpu) { }
++#endif
++
++#if defined(CONFIG_PREEMPTION) && (defined(CONFIG_DEBUG_PREEMPT) || \
++ defined(CONFIG_PREEMPT_TRACER))
++/*
++ * If the value passed in is equal to the current preempt count
++ * then we just disabled preemption. Start timing the latency.
++ */
++static inline void preempt_latency_start(int val)
++{
++ if (preempt_count() == val) {
++ unsigned long ip = get_lock_parent_ip();
++#ifdef CONFIG_DEBUG_PREEMPT
++ current->preempt_disable_ip = ip;
++#endif
++ trace_preempt_off(CALLER_ADDR0, ip);
++ }
++}
++
++void preempt_count_add(int val)
++{
++#ifdef CONFIG_DEBUG_PREEMPT
++ /*
++ * Underflow?
++ */
++ if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0)))
++ return;
++#endif
++ __preempt_count_add(val);
++#ifdef CONFIG_DEBUG_PREEMPT
++ /*
++ * Spinlock count overflowing soon?
++ */
++ DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
++ PREEMPT_MASK - 10);
++#endif
++ preempt_latency_start(val);
++}
++EXPORT_SYMBOL(preempt_count_add);
++NOKPROBE_SYMBOL(preempt_count_add);
++
++/*
++ * If the value passed in equals to the current preempt count
++ * then we just enabled preemption. Stop timing the latency.
++ */
++static inline void preempt_latency_stop(int val)
++{
++ if (preempt_count() == val)
++ trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip());
++}
++
++void preempt_count_sub(int val)
++{
++#ifdef CONFIG_DEBUG_PREEMPT
++ /*
++ * Underflow?
++ */
++ if (DEBUG_LOCKS_WARN_ON(val > preempt_count()))
++ return;
++ /*
++ * Is the spinlock portion underflowing?
++ */
++ if (DEBUG_LOCKS_WARN_ON((val < PREEMPT_MASK) &&
++ !(preempt_count() & PREEMPT_MASK)))
++ return;
++#endif
++
++ preempt_latency_stop(val);
++ __preempt_count_sub(val);
++}
++EXPORT_SYMBOL(preempt_count_sub);
++NOKPROBE_SYMBOL(preempt_count_sub);
++
++#else
++static inline void preempt_latency_start(int val) { }
++static inline void preempt_latency_stop(int val) { }
++#endif
++
++static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
++{
++#ifdef CONFIG_DEBUG_PREEMPT
++ return p->preempt_disable_ip;
++#else
++ return 0;
++#endif
++}
++
++/*
++ * Print scheduling while atomic bug:
++ */
++static noinline void __schedule_bug(struct task_struct *prev)
++{
++ /* Save this before calling printk(), since that will clobber it */
++ unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
++
++ if (oops_in_progress)
++ return;
++
++ printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",
++ prev->comm, prev->pid, preempt_count());
++
++ debug_show_held_locks(prev);
++ print_modules();
++ if (irqs_disabled())
++ print_irqtrace_events(prev);
++ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
++ && in_atomic_preempt_off()) {
++ pr_err("Preemption disabled at:");
++ print_ip_sym(KERN_ERR, preempt_disable_ip);
++ }
++ if (panic_on_warn)
++ panic("scheduling while atomic\n");
++
++ dump_stack();
++ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
++}
++
++/*
++ * Various schedule()-time debugging checks and statistics:
++ */
++static inline void schedule_debug(struct task_struct *prev, bool preempt)
++{
++#ifdef CONFIG_SCHED_STACK_END_CHECK
++ if (task_stack_end_corrupted(prev))
++ panic("corrupted stack end detected inside scheduler\n");
++
++ if (task_scs_end_corrupted(prev))
++ panic("corrupted shadow stack detected inside scheduler\n");
++#endif
++
++#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
++ if (!preempt && READ_ONCE(prev->__state) && prev->non_block_count) {
++ printk(KERN_ERR "BUG: scheduling in a non-blocking section: %s/%d/%i\n",
++ prev->comm, prev->pid, prev->non_block_count);
++ dump_stack();
++ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
++ }
++#endif
++
++ if (unlikely(in_atomic_preempt_off())) {
++ __schedule_bug(prev);
++ preempt_count_set(PREEMPT_DISABLED);
++ }
++ rcu_sleep_check();
++ SCHED_WARN_ON(ct_state() == CONTEXT_USER);
++
++ profile_hit(SCHED_PROFILING, __builtin_return_address(0));
++
++ schedstat_inc(this_rq()->sched_count);
++}
++
++/*
++ * Compile time debug macro
++ * #define ALT_SCHED_DEBUG
++ */
++
++#ifdef ALT_SCHED_DEBUG
++void alt_sched_debug(void)
++{
++ printk(KERN_INFO "sched: pending: 0x%04lx, idle: 0x%04lx, sg_idle: 0x%04lx\n",
++ sched_rq_pending_mask.bits[0],
++ sched_rq_watermark[0].bits[0],
++ sched_sg_idle_mask.bits[0]);
++}
++#else
++inline void alt_sched_debug(void) {}
++#endif
++
++#ifdef CONFIG_SMP
++
++#define SCHED_RQ_NR_MIGRATION (32U)
++/*
++ * Migrate pending tasks in @rq to @dest_cpu
++ * Will try to migrate mininal of half of @rq nr_running tasks and
++ * SCHED_RQ_NR_MIGRATION to @dest_cpu
++ */
++static inline int
++migrate_pending_tasks(struct rq *rq, struct rq *dest_rq, const int dest_cpu)
++{
++ struct task_struct *p, *skip = rq->curr;
++ int nr_migrated = 0;
++ int nr_tries = min(rq->nr_running / 2, SCHED_RQ_NR_MIGRATION);
++
++ while (skip != rq->idle && nr_tries &&
++ (p = sched_rq_next_task(skip, rq)) != rq->idle) {
++ skip = sched_rq_next_task(p, rq);
++ if (cpumask_test_cpu(dest_cpu, p->cpus_ptr)) {
++ __SCHED_DEQUEUE_TASK(p, rq, 0, );
++ set_task_cpu(p, dest_cpu);
++ sched_task_sanity_check(p, dest_rq);
++ __SCHED_ENQUEUE_TASK(p, dest_rq, 0);
++ nr_migrated++;
++ }
++ nr_tries--;
++ }
++
++ return nr_migrated;
++}
++
++static inline int take_other_rq_tasks(struct rq *rq, int cpu)
++{
++ struct cpumask *topo_mask, *end_mask;
++
++ if (unlikely(!rq->online))
++ return 0;
++
++ if (cpumask_empty(&sched_rq_pending_mask))
++ return 0;
++
++ topo_mask = per_cpu(sched_cpu_topo_masks, cpu) + 1;
++ end_mask = per_cpu(sched_cpu_topo_end_mask, cpu);
++ do {
++ int i;
++ for_each_cpu_and(i, &sched_rq_pending_mask, topo_mask) {
++ int nr_migrated;
++ struct rq *src_rq;
++
++ src_rq = cpu_rq(i);
++ if (!do_raw_spin_trylock(&src_rq->lock))
++ continue;
++ spin_acquire(&src_rq->lock.dep_map,
++ SINGLE_DEPTH_NESTING, 1, _RET_IP_);
++
++ if ((nr_migrated = migrate_pending_tasks(src_rq, rq, cpu))) {
++ src_rq->nr_running -= nr_migrated;
++ if (src_rq->nr_running < 2)
++ cpumask_clear_cpu(i, &sched_rq_pending_mask);
++
++ rq->nr_running += nr_migrated;
++ if (rq->nr_running > 1)
++ cpumask_set_cpu(cpu, &sched_rq_pending_mask);
++
++ update_sched_rq_watermark(rq);
++ cpufreq_update_util(rq, 0);
++
++ spin_release(&src_rq->lock.dep_map, _RET_IP_);
++ do_raw_spin_unlock(&src_rq->lock);
++
++ return 1;
++ }
++
++ spin_release(&src_rq->lock.dep_map, _RET_IP_);
++ do_raw_spin_unlock(&src_rq->lock);
++ }
++ } while (++topo_mask < end_mask);
++
++ return 0;
++}
++#endif
++
++/*
++ * Timeslices below RESCHED_NS are considered as good as expired as there's no
++ * point rescheduling when there's so little time left.
++ */
++static inline void check_curr(struct task_struct *p, struct rq *rq)
++{
++ if (unlikely(rq->idle == p))
++ return;
++
++ update_curr(rq, p);
++
++ if (p->time_slice < RESCHED_NS)
++ time_slice_expired(p, rq);
++}
++
++static inline struct task_struct *
++choose_next_task(struct rq *rq, int cpu, struct task_struct *prev)
++{
++ struct task_struct *next;
++
++ if (unlikely(rq->skip)) {
++ next = rq_runnable_task(rq);
++ if (next == rq->idle) {
++#ifdef CONFIG_SMP
++ if (!take_other_rq_tasks(rq, cpu)) {
++#endif
++ rq->skip = NULL;
++ schedstat_inc(rq->sched_goidle);
++ return next;
++#ifdef CONFIG_SMP
++ }
++ next = rq_runnable_task(rq);
++#endif
++ }
++ rq->skip = NULL;
++#ifdef CONFIG_HIGH_RES_TIMERS
++ hrtick_start(rq, next->time_slice);
++#endif
++ return next;
++ }
++
++ next = sched_rq_first_task(rq);
++ if (next == rq->idle) {
++#ifdef CONFIG_SMP
++ if (!take_other_rq_tasks(rq, cpu)) {
++#endif
++ schedstat_inc(rq->sched_goidle);
++ /*printk(KERN_INFO "sched: choose_next_task(%d) idle %px\n", cpu, next);*/
++ return next;
++#ifdef CONFIG_SMP
++ }
++ next = sched_rq_first_task(rq);
++#endif
++ }
++#ifdef CONFIG_HIGH_RES_TIMERS
++ hrtick_start(rq, next->time_slice);
++#endif
++ /*printk(KERN_INFO "sched: choose_next_task(%d) next %px\n", cpu,
++ * next);*/
++ return next;
++}
++
++/*
++ * Constants for the sched_mode argument of __schedule().
++ *
++ * The mode argument allows RT enabled kernels to differentiate a
++ * preemption from blocking on an 'sleeping' spin/rwlock. Note that
++ * SM_MASK_PREEMPT for !RT has all bits set, which allows the compiler to
++ * optimize the AND operation out and just check for zero.
++ */
++#define SM_NONE 0x0
++#define SM_PREEMPT 0x1
++#define SM_RTLOCK_WAIT 0x2
++
++#ifndef CONFIG_PREEMPT_RT
++# define SM_MASK_PREEMPT (~0U)
++#else
++# define SM_MASK_PREEMPT SM_PREEMPT
++#endif
++
++/*
++ * schedule() is the main scheduler function.
++ *
++ * The main means of driving the scheduler and thus entering this function are:
++ *
++ * 1. Explicit blocking: mutex, semaphore, waitqueue, etc.
++ *
++ * 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
++ * paths. For example, see arch/x86/entry_64.S.
++ *
++ * To drive preemption between tasks, the scheduler sets the flag in timer
++ * interrupt handler scheduler_tick().
++ *
++ * 3. Wakeups don't really cause entry into schedule(). They add a
++ * task to the run-queue and that's it.
++ *
++ * Now, if the new task added to the run-queue preempts the current
++ * task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
++ * called on the nearest possible occasion:
++ *
++ * - If the kernel is preemptible (CONFIG_PREEMPTION=y):
++ *
++ * - in syscall or exception context, at the next outmost
++ * preempt_enable(). (this might be as soon as the wake_up()'s
++ * spin_unlock()!)
++ *
++ * - in IRQ context, return from interrupt-handler to
++ * preemptible context
++ *
++ * - If the kernel is not preemptible (CONFIG_PREEMPTION is not set)
++ * then at the next:
++ *
++ * - cond_resched() call
++ * - explicit schedule() call
++ * - return from syscall or exception to user-space
++ * - return from interrupt-handler to user-space
++ *
++ * WARNING: must be called with preemption disabled!
++ */
++static void __sched notrace __schedule(unsigned int sched_mode)
++{
++ struct task_struct *prev, *next;
++ unsigned long *switch_count;
++ unsigned long prev_state;
++ struct rq *rq;
++ int cpu;
++
++ cpu = smp_processor_id();
++ rq = cpu_rq(cpu);
++ prev = rq->curr;
++
++ schedule_debug(prev, !!sched_mode);
++
++ /* by passing sched_feat(HRTICK) checking which Alt schedule FW doesn't support */
++ hrtick_clear(rq);
++
++ local_irq_disable();
++ rcu_note_context_switch(!!sched_mode);
++
++ /*
++ * Make sure that signal_pending_state()->signal_pending() below
++ * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
++ * done by the caller to avoid the race with signal_wake_up():
++ *
++ * __set_current_state(@state) signal_wake_up()
++ * schedule() set_tsk_thread_flag(p, TIF_SIGPENDING)
++ * wake_up_state(p, state)
++ * LOCK rq->lock LOCK p->pi_state
++ * smp_mb__after_spinlock() smp_mb__after_spinlock()
++ * if (signal_pending_state()) if (p->state & @state)
++ *
++ * Also, the membarrier system call requires a full memory barrier
++ * after coming from user-space, before storing to rq->curr.
++ */
++ raw_spin_lock(&rq->lock);
++ smp_mb__after_spinlock();
++
++ update_rq_clock(rq);
++
++ switch_count = &prev->nivcsw;
++ /*
++ * We must load prev->state once (task_struct::state is volatile), such
++ * that:
++ *
++ * - we form a control dependency vs deactivate_task() below.
++ * - ptrace_{,un}freeze_traced() can change ->state underneath us.
++ */
++ prev_state = READ_ONCE(prev->__state);
++ if (!(sched_mode & SM_MASK_PREEMPT) && prev_state) {
++ if (signal_pending_state(prev_state, prev)) {
++ WRITE_ONCE(prev->__state, TASK_RUNNING);
++ } else {
++ prev->sched_contributes_to_load =
++ (prev_state & TASK_UNINTERRUPTIBLE) &&
++ !(prev_state & TASK_NOLOAD) &&
++ !(prev->flags & PF_FROZEN);
++
++ if (prev->sched_contributes_to_load)
++ rq->nr_uninterruptible++;
++
++ /*
++ * __schedule() ttwu()
++ * prev_state = prev->state; if (p->on_rq && ...)
++ * if (prev_state) goto out;
++ * p->on_rq = 0; smp_acquire__after_ctrl_dep();
++ * p->state = TASK_WAKING
++ *
++ * Where __schedule() and ttwu() have matching control dependencies.
++ *
++ * After this, schedule() must not care about p->state any more.
++ */
++ sched_task_deactivate(prev, rq);
++ deactivate_task(prev, rq);
++
++ if (prev->in_iowait) {
++ atomic_inc(&rq->nr_iowait);
++ delayacct_blkio_start();
++ }
++ }
++ switch_count = &prev->nvcsw;
++ }
++
++ check_curr(prev, rq);
++
++ next = choose_next_task(rq, cpu, prev);
++ clear_tsk_need_resched(prev);
++ clear_preempt_need_resched();
++#ifdef CONFIG_SCHED_DEBUG
++ rq->last_seen_need_resched_ns = 0;
++#endif
++
++ if (likely(prev != next)) {
++ next->last_ran = rq->clock_task;
++ rq->last_ts_switch = rq->clock;
++
++ rq->nr_switches++;
++ /*
++ * RCU users of rcu_dereference(rq->curr) may not see
++ * changes to task_struct made by pick_next_task().
++ */
++ RCU_INIT_POINTER(rq->curr, next);
++ /*
++ * The membarrier system call requires each architecture
++ * to have a full memory barrier after updating
++ * rq->curr, before returning to user-space.
++ *
++ * Here are the schemes providing that barrier on the
++ * various architectures:
++ * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC.
++ * switch_mm() rely on membarrier_arch_switch_mm() on PowerPC.
++ * - finish_lock_switch() for weakly-ordered
++ * architectures where spin_unlock is a full barrier,
++ * - switch_to() for arm64 (weakly-ordered, spin_unlock
++ * is a RELEASE barrier),
++ */
++ ++*switch_count;
++
++ psi_sched_switch(prev, next, !task_on_rq_queued(prev));
++
++ trace_sched_switch(sched_mode & SM_MASK_PREEMPT, prev, next);
++
++ /* Also unlocks the rq: */
++ rq = context_switch(rq, prev, next);
++ } else {
++ __balance_callbacks(rq);
++ raw_spin_unlock_irq(&rq->lock);
++ }
++
++#ifdef CONFIG_SCHED_SMT
++ sg_balance_check(rq);
++#endif
++}
++
++void __noreturn do_task_dead(void)
++{
++ /* Causes final put_task_struct in finish_task_switch(): */
++ set_special_state(TASK_DEAD);
++
++ /* Tell freezer to ignore us: */
++ current->flags |= PF_NOFREEZE;
++
++ __schedule(SM_NONE);
++ BUG();
++
++ /* Avoid "noreturn function does return" - but don't continue if BUG() is a NOP: */
++ for (;;)
++ cpu_relax();
++}
++
++static inline void sched_submit_work(struct task_struct *tsk)
++{
++ unsigned int task_flags;
++
++ if (task_is_running(tsk))
++ return;
++
++ task_flags = tsk->flags;
++ /*
++ * If a worker went to sleep, notify and ask workqueue whether
++ * it wants to wake up a task to maintain concurrency.
++ * As this function is called inside the schedule() context,
++ * we disable preemption to avoid it calling schedule() again
++ * in the possible wakeup of a kworker and because wq_worker_sleeping()
++ * requires it.
++ */
++ if (task_flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
++ preempt_disable();
++ if (task_flags & PF_WQ_WORKER)
++ wq_worker_sleeping(tsk);
++ else
++ io_wq_worker_sleeping(tsk);
++ preempt_enable_no_resched();
++ }
++
++ if (tsk_is_pi_blocked(tsk))
++ return;
++
++ /*
++ * If we are going to sleep and we have plugged IO queued,
++ * make sure to submit it to avoid deadlocks.
++ */
++ if (blk_needs_flush_plug(tsk))
++ blk_schedule_flush_plug(tsk);
++}
++
++static void sched_update_worker(struct task_struct *tsk)
++{
++ if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
++ if (tsk->flags & PF_WQ_WORKER)
++ wq_worker_running(tsk);
++ else
++ io_wq_worker_running(tsk);
++ }
++}
++
++asmlinkage __visible void __sched schedule(void)
++{
++ struct task_struct *tsk = current;
++
++ sched_submit_work(tsk);
++ do {
++ preempt_disable();
++ __schedule(SM_NONE);
++ sched_preempt_enable_no_resched();
++ } while (need_resched());
++ sched_update_worker(tsk);
++}
++EXPORT_SYMBOL(schedule);
++
++/*
++ * synchronize_rcu_tasks() makes sure that no task is stuck in preempted
++ * state (have scheduled out non-voluntarily) by making sure that all
++ * tasks have either left the run queue or have gone into user space.
++ * As idle tasks do not do either, they must not ever be preempted
++ * (schedule out non-voluntarily).
++ *
++ * schedule_idle() is similar to schedule_preempt_disable() except that it
++ * never enables preemption because it does not call sched_submit_work().
++ */
++void __sched schedule_idle(void)
++{
++ /*
++ * As this skips calling sched_submit_work(), which the idle task does
++ * regardless because that function is a nop when the task is in a
++ * TASK_RUNNING state, make sure this isn't used someplace that the
++ * current task can be in any other state. Note, idle is always in the
++ * TASK_RUNNING state.
++ */
++ WARN_ON_ONCE(current->__state);
++ do {
++ __schedule(SM_NONE);
++ } while (need_resched());
++}
++
++#if defined(CONFIG_CONTEXT_TRACKING) && !defined(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK)
++asmlinkage __visible void __sched schedule_user(void)
++{
++ /*
++ * If we come here after a random call to set_need_resched(),
++ * or we have been woken up remotely but the IPI has not yet arrived,
++ * we haven't yet exited the RCU idle mode. Do it here manually until
++ * we find a better solution.
++ *
++ * NB: There are buggy callers of this function. Ideally we
++ * should warn if prev_state != CONTEXT_USER, but that will trigger
++ * too frequently to make sense yet.
++ */
++ enum ctx_state prev_state = exception_enter();
++ schedule();
++ exception_exit(prev_state);
++}
++#endif
++
++/**
++ * schedule_preempt_disabled - called with preemption disabled
++ *
++ * Returns with preemption disabled. Note: preempt_count must be 1
++ */
++void __sched schedule_preempt_disabled(void)
++{
++ sched_preempt_enable_no_resched();
++ schedule();
++ preempt_disable();
++}
++
++#ifdef CONFIG_PREEMPT_RT
++void __sched notrace schedule_rtlock(void)
++{
++ do {
++ preempt_disable();
++ __schedule(SM_RTLOCK_WAIT);
++ sched_preempt_enable_no_resched();
++ } while (need_resched());
++}
++NOKPROBE_SYMBOL(schedule_rtlock);
++#endif
++
++static void __sched notrace preempt_schedule_common(void)
++{
++ do {
++ /*
++ * Because the function tracer can trace preempt_count_sub()
++ * and it also uses preempt_enable/disable_notrace(), if
++ * NEED_RESCHED is set, the preempt_enable_notrace() called
++ * by the function tracer will call this function again and
++ * cause infinite recursion.
++ *
++ * Preemption must be disabled here before the function
++ * tracer can trace. Break up preempt_disable() into two
++ * calls. One to disable preemption without fear of being
++ * traced. The other to still record the preemption latency,
++ * which can also be traced by the function tracer.
++ */
++ preempt_disable_notrace();
++ preempt_latency_start(1);
++ __schedule(SM_PREEMPT);
++ preempt_latency_stop(1);
++ preempt_enable_no_resched_notrace();
++
++ /*
++ * Check again in case we missed a preemption opportunity
++ * between schedule and now.
++ */
++ } while (need_resched());
++}
++
++#ifdef CONFIG_PREEMPTION
++/*
++ * This is the entry point to schedule() from in-kernel preemption
++ * off of preempt_enable.
++ */
++asmlinkage __visible void __sched notrace preempt_schedule(void)
++{
++ /*
++ * If there is a non-zero preempt_count or interrupts are disabled,
++ * we do not want to preempt the current task. Just return..
++ */
++ if (likely(!preemptible()))
++ return;
++
++ preempt_schedule_common();
++}
++NOKPROBE_SYMBOL(preempt_schedule);
++EXPORT_SYMBOL(preempt_schedule);
++
++#ifdef CONFIG_PREEMPT_DYNAMIC
++DEFINE_STATIC_CALL(preempt_schedule, __preempt_schedule_func);
++EXPORT_STATIC_CALL_TRAMP(preempt_schedule);
++#endif
++
++
++/**
++ * preempt_schedule_notrace - preempt_schedule called by tracing
++ *
++ * The tracing infrastructure uses preempt_enable_notrace to prevent
++ * recursion and tracing preempt enabling caused by the tracing
++ * infrastructure itself. But as tracing can happen in areas coming
++ * from userspace or just about to enter userspace, a preempt enable
++ * can occur before user_exit() is called. This will cause the scheduler
++ * to be called when the system is still in usermode.
++ *
++ * To prevent this, the preempt_enable_notrace will use this function
++ * instead of preempt_schedule() to exit user context if needed before
++ * calling the scheduler.
++ */
++asmlinkage __visible void __sched notrace preempt_schedule_notrace(void)
++{
++ enum ctx_state prev_ctx;
++
++ if (likely(!preemptible()))
++ return;
++
++ do {
++ /*
++ * Because the function tracer can trace preempt_count_sub()
++ * and it also uses preempt_enable/disable_notrace(), if
++ * NEED_RESCHED is set, the preempt_enable_notrace() called
++ * by the function tracer will call this function again and
++ * cause infinite recursion.
++ *
++ * Preemption must be disabled here before the function
++ * tracer can trace. Break up preempt_disable() into two
++ * calls. One to disable preemption without fear of being
++ * traced. The other to still record the preemption latency,
++ * which can also be traced by the function tracer.
++ */
++ preempt_disable_notrace();
++ preempt_latency_start(1);
++ /*
++ * Needs preempt disabled in case user_exit() is traced
++ * and the tracer calls preempt_enable_notrace() causing
++ * an infinite recursion.
++ */
++ prev_ctx = exception_enter();
++ __schedule(SM_PREEMPT);
++ exception_exit(prev_ctx);
++
++ preempt_latency_stop(1);
++ preempt_enable_no_resched_notrace();
++ } while (need_resched());
++}
++EXPORT_SYMBOL_GPL(preempt_schedule_notrace);
++
++#ifdef CONFIG_PREEMPT_DYNAMIC
++DEFINE_STATIC_CALL(preempt_schedule_notrace, __preempt_schedule_notrace_func);
++EXPORT_STATIC_CALL_TRAMP(preempt_schedule_notrace);
++#endif
++
++#endif /* CONFIG_PREEMPTION */
++
++#ifdef CONFIG_PREEMPT_DYNAMIC
++
++#include <linux/entry-common.h>
++
++/*
++ * SC:cond_resched
++ * SC:might_resched
++ * SC:preempt_schedule
++ * SC:preempt_schedule_notrace
++ * SC:irqentry_exit_cond_resched
++ *
++ *
++ * NONE:
++ * cond_resched <- __cond_resched
++ * might_resched <- RET0
++ * preempt_schedule <- NOP
++ * preempt_schedule_notrace <- NOP
++ * irqentry_exit_cond_resched <- NOP
++ *
++ * VOLUNTARY:
++ * cond_resched <- __cond_resched
++ * might_resched <- __cond_resched
++ * preempt_schedule <- NOP
++ * preempt_schedule_notrace <- NOP
++ * irqentry_exit_cond_resched <- NOP
++ *
++ * FULL:
++ * cond_resched <- RET0
++ * might_resched <- RET0
++ * preempt_schedule <- preempt_schedule
++ * preempt_schedule_notrace <- preempt_schedule_notrace
++ * irqentry_exit_cond_resched <- irqentry_exit_cond_resched
++ */
++
++enum {
++ preempt_dynamic_none = 0,
++ preempt_dynamic_voluntary,
++ preempt_dynamic_full,
++};
++
++int preempt_dynamic_mode = preempt_dynamic_full;
++
++int sched_dynamic_mode(const char *str)
++{
++ if (!strcmp(str, "none"))
++ return preempt_dynamic_none;
++
++ if (!strcmp(str, "voluntary"))
++ return preempt_dynamic_voluntary;
++
++ if (!strcmp(str, "full"))
++ return preempt_dynamic_full;
++
++ return -EINVAL;
++}
++
++void sched_dynamic_update(int mode)
++{
++ /*
++ * Avoid {NONE,VOLUNTARY} -> FULL transitions from ever ending up in
++ * the ZERO state, which is invalid.
++ */
++ static_call_update(cond_resched, __cond_resched);
++ static_call_update(might_resched, __cond_resched);
++ static_call_update(preempt_schedule, __preempt_schedule_func);
++ static_call_update(preempt_schedule_notrace, __preempt_schedule_notrace_func);
++ static_call_update(irqentry_exit_cond_resched, irqentry_exit_cond_resched);
++
++ switch (mode) {
++ case preempt_dynamic_none:
++ static_call_update(cond_resched, __cond_resched);
++ static_call_update(might_resched, (void *)&__static_call_return0);
++ static_call_update(preempt_schedule, NULL);
++ static_call_update(preempt_schedule_notrace, NULL);
++ static_call_update(irqentry_exit_cond_resched, NULL);
++ pr_info("Dynamic Preempt: none\n");
++ break;
++
++ case preempt_dynamic_voluntary:
++ static_call_update(cond_resched, __cond_resched);
++ static_call_update(might_resched, __cond_resched);
++ static_call_update(preempt_schedule, NULL);
++ static_call_update(preempt_schedule_notrace, NULL);
++ static_call_update(irqentry_exit_cond_resched, NULL);
++ pr_info("Dynamic Preempt: voluntary\n");
++ break;
++
++ case preempt_dynamic_full:
++ static_call_update(cond_resched, (void *)&__static_call_return0);
++ static_call_update(might_resched, (void *)&__static_call_return0);
++ static_call_update(preempt_schedule, __preempt_schedule_func);
++ static_call_update(preempt_schedule_notrace, __preempt_schedule_notrace_func);
++ static_call_update(irqentry_exit_cond_resched, irqentry_exit_cond_resched);
++ pr_info("Dynamic Preempt: full\n");
++ break;
++ }
++
++ preempt_dynamic_mode = mode;
++}
++
++static int __init setup_preempt_mode(char *str)
++{
++ int mode = sched_dynamic_mode(str);
++ if (mode < 0) {
++ pr_warn("Dynamic Preempt: unsupported mode: %s\n", str);
++ return 1;
++ }
++
++ sched_dynamic_update(mode);
++ return 0;
++}
++__setup("preempt=", setup_preempt_mode);
++
++#endif /* CONFIG_PREEMPT_DYNAMIC */
++
++/*
++ * This is the entry point to schedule() from kernel preemption
++ * off of irq context.
++ * Note, that this is called and return with irqs disabled. This will
++ * protect us against recursive calling from irq.
++ */
++asmlinkage __visible void __sched preempt_schedule_irq(void)
++{
++ enum ctx_state prev_state;
++
++ /* Catch callers which need to be fixed */
++ BUG_ON(preempt_count() || !irqs_disabled());
++
++ prev_state = exception_enter();
++
++ do {
++ preempt_disable();
++ local_irq_enable();
++ __schedule(SM_PREEMPT);
++ local_irq_disable();
++ sched_preempt_enable_no_resched();
++ } while (need_resched());
++
++ exception_exit(prev_state);
++}
++
++int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
++ void *key)
++{
++ WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC);
++ return try_to_wake_up(curr->private, mode, wake_flags);
++}
++EXPORT_SYMBOL(default_wake_function);
++
++static inline void check_task_changed(struct task_struct *p, struct rq *rq)
++{
++ /* Trigger resched if task sched_prio has been modified. */
++ if (task_on_rq_queued(p) && task_sched_prio_idx(p, rq) != p->sq_idx) {
++ requeue_task(p, rq);
++ check_preempt_curr(rq);
++ }
++}
++
++static void __setscheduler_prio(struct task_struct *p, int prio)
++{
++ p->prio = prio;
++}
++
++#ifdef CONFIG_RT_MUTEXES
++
++static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
++{
++ if (pi_task)
++ prio = min(prio, pi_task->prio);
++
++ return prio;
++}
++
++static inline int rt_effective_prio(struct task_struct *p, int prio)
++{
++ struct task_struct *pi_task = rt_mutex_get_top_task(p);
++
++ return __rt_effective_prio(pi_task, prio);
++}
++
++/*
++ * rt_mutex_setprio - set the current priority of a task
++ * @p: task to boost
++ * @pi_task: donor task
++ *
++ * This function changes the 'effective' priority of a task. It does
++ * not touch ->normal_prio like __setscheduler().
++ *
++ * Used by the rt_mutex code to implement priority inheritance
++ * logic. Call site only calls if the priority of the task changed.
++ */
++void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
++{
++ int prio;
++ struct rq *rq;
++ raw_spinlock_t *lock;
++
++ /* XXX used to be waiter->prio, not waiter->task->prio */
++ prio = __rt_effective_prio(pi_task, p->normal_prio);
++
++ /*
++ * If nothing changed; bail early.
++ */
++ if (p->pi_top_task == pi_task && prio == p->prio)
++ return;
++
++ rq = __task_access_lock(p, &lock);
++ /*
++ * Set under pi_lock && rq->lock, such that the value can be used under
++ * either lock.
++ *
++ * Note that there is loads of tricky to make this pointer cache work
++ * right. rt_mutex_slowunlock()+rt_mutex_postunlock() work together to
++ * ensure a task is de-boosted (pi_task is set to NULL) before the
++ * task is allowed to run again (and can exit). This ensures the pointer
++ * points to a blocked task -- which guarantees the task is present.
++ */
++ p->pi_top_task = pi_task;
++
++ /*
++ * For FIFO/RR we only need to set prio, if that matches we're done.
++ */
++ if (prio == p->prio)
++ goto out_unlock;
++
++ /*
++ * Idle task boosting is a nono in general. There is one
++ * exception, when PREEMPT_RT and NOHZ is active:
++ *
++ * The idle task calls get_next_timer_interrupt() and holds
++ * the timer wheel base->lock on the CPU and another CPU wants
++ * to access the timer (probably to cancel it). We can safely
++ * ignore the boosting request, as the idle CPU runs this code
++ * with interrupts disabled and will complete the lock
++ * protected section without being interrupted. So there is no
++ * real need to boost.
++ */
++ if (unlikely(p == rq->idle)) {
++ WARN_ON(p != rq->curr);
++ WARN_ON(p->pi_blocked_on);
++ goto out_unlock;
++ }
++
++ trace_sched_pi_setprio(p, pi_task);
++
++ __setscheduler_prio(p, prio);
++
++ check_task_changed(p, rq);
++out_unlock:
++ /* Avoid rq from going away on us: */
++ preempt_disable();
++
++ __balance_callbacks(rq);
++ __task_access_unlock(p, lock);
++
++ preempt_enable();
++}
++#else
++static inline int rt_effective_prio(struct task_struct *p, int prio)
++{
++ return prio;
++}
++#endif
++
++void set_user_nice(struct task_struct *p, long nice)
++{
++ unsigned long flags;
++ struct rq *rq;
++ raw_spinlock_t *lock;
++
++ if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
++ return;
++ /*
++ * We have to be careful, if called from sys_setpriority(),
++ * the task might be in the middle of scheduling on another CPU.
++ */
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++ rq = __task_access_lock(p, &lock);
++
++ p->static_prio = NICE_TO_PRIO(nice);
++ /*
++ * The RT priorities are set via sched_setscheduler(), but we still
++ * allow the 'normal' nice value to be set - but as expected
++ * it won't have any effect on scheduling until the task is
++ * not SCHED_NORMAL/SCHED_BATCH:
++ */
++ if (task_has_rt_policy(p))
++ goto out_unlock;
++
++ p->prio = effective_prio(p);
++
++ check_task_changed(p, rq);
++out_unlock:
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++}
++EXPORT_SYMBOL(set_user_nice);
++
++/*
++ * can_nice - check if a task can reduce its nice value
++ * @p: task
++ * @nice: nice value
++ */
++int can_nice(const struct task_struct *p, const int nice)
++{
++ /* Convert nice value [19,-20] to rlimit style value [1,40] */
++ int nice_rlim = nice_to_rlimit(nice);
++
++ return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
++ capable(CAP_SYS_NICE));
++}
++
++#ifdef __ARCH_WANT_SYS_NICE
++
++/*
++ * sys_nice - change the priority of the current process.
++ * @increment: priority increment
++ *
++ * sys_setpriority is a more generic, but much slower function that
++ * does similar things.
++ */
++SYSCALL_DEFINE1(nice, int, increment)
++{
++ long nice, retval;
++
++ /*
++ * Setpriority might change our priority at the same moment.
++ * We don't have to worry. Conceptually one call occurs first
++ * and we have a single winner.
++ */
++
++ increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH);
++ nice = task_nice(current) + increment;
++
++ nice = clamp_val(nice, MIN_NICE, MAX_NICE);
++ if (increment < 0 && !can_nice(current, nice))
++ return -EPERM;
++
++ retval = security_task_setnice(current, nice);
++ if (retval)
++ return retval;
++
++ set_user_nice(current, nice);
++ return 0;
++}
++
++#endif
++
++/**
++ * task_prio - return the priority value of a given task.
++ * @p: the task in question.
++ *
++ * Return: The priority value as seen by users in /proc.
++ *
++ * sched policy return value kernel prio user prio/nice
++ *
++ * (BMQ)normal, batch, idle[0 ... 53] [100 ... 139] 0/[-20 ... 19]/[-7 ... 7]
++ * (PDS)normal, batch, idle[0 ... 39] 100 0/[-20 ... 19]
++ * fifo, rr [-1 ... -100] [99 ... 0] [0 ... 99]
++ */
++int task_prio(const struct task_struct *p)
++{
++ return (p->prio < MAX_RT_PRIO) ? p->prio - MAX_RT_PRIO :
++ task_sched_prio_normal(p, task_rq(p));
++}
++
++/**
++ * idle_cpu - is a given CPU idle currently?
++ * @cpu: the processor in question.
++ *
++ * Return: 1 if the CPU is currently idle. 0 otherwise.
++ */
++int idle_cpu(int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ if (rq->curr != rq->idle)
++ return 0;
++
++ if (rq->nr_running)
++ return 0;
++
++#ifdef CONFIG_SMP
++ if (rq->ttwu_pending)
++ return 0;
++#endif
++
++ return 1;
++}
++
++/**
++ * idle_task - return the idle task for a given CPU.
++ * @cpu: the processor in question.
++ *
++ * Return: The idle task for the cpu @cpu.
++ */
++struct task_struct *idle_task(int cpu)
++{
++ return cpu_rq(cpu)->idle;
++}
++
++/**
++ * find_process_by_pid - find a process with a matching PID value.
++ * @pid: the pid in question.
++ *
++ * The task of @pid, if found. %NULL otherwise.
++ */
++static inline struct task_struct *find_process_by_pid(pid_t pid)
++{
++ return pid ? find_task_by_vpid(pid) : current;
++}
++
++/*
++ * sched_setparam() passes in -1 for its policy, to let the functions
++ * it calls know not to change it.
++ */
++#define SETPARAM_POLICY -1
++
++static void __setscheduler_params(struct task_struct *p,
++ const struct sched_attr *attr)
++{
++ int policy = attr->sched_policy;
++
++ if (policy == SETPARAM_POLICY)
++ policy = p->policy;
++
++ p->policy = policy;
++
++ /*
++ * allow normal nice value to be set, but will not have any
++ * effect on scheduling until the task not SCHED_NORMAL/
++ * SCHED_BATCH
++ */
++ p->static_prio = NICE_TO_PRIO(attr->sched_nice);
++
++ /*
++ * __sched_setscheduler() ensures attr->sched_priority == 0 when
++ * !rt_policy. Always setting this ensures that things like
++ * getparam()/getattr() don't report silly values for !rt tasks.
++ */
++ p->rt_priority = attr->sched_priority;
++ p->normal_prio = normal_prio(p);
++}
++
++/*
++ * check the target process has a UID that matches the current process's
++ */
++static bool check_same_owner(struct task_struct *p)
++{
++ const struct cred *cred = current_cred(), *pcred;
++ bool match;
++
++ rcu_read_lock();
++ pcred = __task_cred(p);
++ match = (uid_eq(cred->euid, pcred->euid) ||
++ uid_eq(cred->euid, pcred->uid));
++ rcu_read_unlock();
++ return match;
++}
++
++static int __sched_setscheduler(struct task_struct *p,
++ const struct sched_attr *attr,
++ bool user, bool pi)
++{
++ const struct sched_attr dl_squash_attr = {
++ .size = sizeof(struct sched_attr),
++ .sched_policy = SCHED_FIFO,
++ .sched_nice = 0,
++ .sched_priority = 99,
++ };
++ int oldpolicy = -1, policy = attr->sched_policy;
++ int retval, newprio;
++ struct callback_head *head;
++ unsigned long flags;
++ struct rq *rq;
++ int reset_on_fork;
++ raw_spinlock_t *lock;
++
++ /* The pi code expects interrupts enabled */
++ BUG_ON(pi && in_interrupt());
++
++ /*
++ * Alt schedule FW supports SCHED_DEADLINE by squash it as prio 0 SCHED_FIFO
++ */
++ if (unlikely(SCHED_DEADLINE == policy)) {
++ attr = &dl_squash_attr;
++ policy = attr->sched_policy;
++ }
++recheck:
++ /* Double check policy once rq lock held */
++ if (policy < 0) {
++ reset_on_fork = p->sched_reset_on_fork;
++ policy = oldpolicy = p->policy;
++ } else {
++ reset_on_fork = !!(attr->sched_flags & SCHED_RESET_ON_FORK);
++
++ if (policy > SCHED_IDLE)
++ return -EINVAL;
++ }
++
++ if (attr->sched_flags & ~(SCHED_FLAG_ALL))
++ return -EINVAL;
++
++ /*
++ * Valid priorities for SCHED_FIFO and SCHED_RR are
++ * 1..MAX_RT_PRIO-1, valid priority for SCHED_NORMAL and
++ * SCHED_BATCH and SCHED_IDLE is 0.
++ */
++ if (attr->sched_priority < 0 ||
++ (p->mm && attr->sched_priority > MAX_RT_PRIO - 1) ||
++ (!p->mm && attr->sched_priority > MAX_RT_PRIO - 1))
++ return -EINVAL;
++ if ((SCHED_RR == policy || SCHED_FIFO == policy) !=
++ (attr->sched_priority != 0))
++ return -EINVAL;
++
++ /*
++ * Allow unprivileged RT tasks to decrease priority:
++ */
++ if (user && !capable(CAP_SYS_NICE)) {
++ if (SCHED_FIFO == policy || SCHED_RR == policy) {
++ unsigned long rlim_rtprio =
++ task_rlimit(p, RLIMIT_RTPRIO);
++
++ /* Can't set/change the rt policy */
++ if (policy != p->policy && !rlim_rtprio)
++ return -EPERM;
++
++ /* Can't increase priority */
++ if (attr->sched_priority > p->rt_priority &&
++ attr->sched_priority > rlim_rtprio)
++ return -EPERM;
++ }
++
++ /* Can't change other user's priorities */
++ if (!check_same_owner(p))
++ return -EPERM;
++
++ /* Normal users shall not reset the sched_reset_on_fork flag */
++ if (p->sched_reset_on_fork && !reset_on_fork)
++ return -EPERM;
++ }
++
++ if (user) {
++ retval = security_task_setscheduler(p);
++ if (retval)
++ return retval;
++ }
++
++ if (pi)
++ cpuset_read_lock();
++
++ /*
++ * Make sure no PI-waiters arrive (or leave) while we are
++ * changing the priority of the task:
++ */
++ raw_spin_lock_irqsave(&p->pi_lock, flags);
++
++ /*
++ * To be able to change p->policy safely, task_access_lock()
++ * must be called.
++ * IF use task_access_lock() here:
++ * For the task p which is not running, reading rq->stop is
++ * racy but acceptable as ->stop doesn't change much.
++ * An enhancemnet can be made to read rq->stop saftly.
++ */
++ rq = __task_access_lock(p, &lock);
++
++ /*
++ * Changing the policy of the stop threads its a very bad idea
++ */
++ if (p == rq->stop) {
++ retval = -EINVAL;
++ goto unlock;
++ }
++
++ /*
++ * If not changing anything there's no need to proceed further:
++ */
++ if (unlikely(policy == p->policy)) {
++ if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
++ goto change;
++ if (!rt_policy(policy) &&
++ NICE_TO_PRIO(attr->sched_nice) != p->static_prio)
++ goto change;
++
++ p->sched_reset_on_fork = reset_on_fork;
++ retval = 0;
++ goto unlock;
++ }
++change:
++
++ /* Re-check policy now with rq lock held */
++ if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
++ policy = oldpolicy = -1;
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++ if (pi)
++ cpuset_read_unlock();
++ goto recheck;
++ }
++
++ p->sched_reset_on_fork = reset_on_fork;
++
++ newprio = __normal_prio(policy, attr->sched_priority, NICE_TO_PRIO(attr->sched_nice));
++ if (pi) {
++ /*
++ * Take priority boosted tasks into account. If the new
++ * effective priority is unchanged, we just store the new
++ * normal parameters and do not touch the scheduler class and
++ * the runqueue. This will be done when the task deboost
++ * itself.
++ */
++ newprio = rt_effective_prio(p, newprio);
++ }
++
++ if (!(attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)) {
++ __setscheduler_params(p, attr);
++ __setscheduler_prio(p, newprio);
++ }
++
++ check_task_changed(p, rq);
++
++ /* Avoid rq from going away on us: */
++ preempt_disable();
++ head = splice_balance_callbacks(rq);
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++
++ if (pi) {
++ cpuset_read_unlock();
++ rt_mutex_adjust_pi(p);
++ }
++
++ /* Run balance callbacks after we've adjusted the PI chain: */
++ balance_callbacks(rq, head);
++ preempt_enable();
++
++ return 0;
++
++unlock:
++ __task_access_unlock(p, lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
++ if (pi)
++ cpuset_read_unlock();
++ return retval;
++}
++
++static int _sched_setscheduler(struct task_struct *p, int policy,
++ const struct sched_param *param, bool check)
++{
++ struct sched_attr attr = {
++ .sched_policy = policy,
++ .sched_priority = param->sched_priority,
++ .sched_nice = PRIO_TO_NICE(p->static_prio),
++ };
++
++ /* Fixup the legacy SCHED_RESET_ON_FORK hack. */
++ if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) {
++ attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
++ policy &= ~SCHED_RESET_ON_FORK;
++ attr.sched_policy = policy;
++ }
++
++ return __sched_setscheduler(p, &attr, check, true);
++}
++
++/**
++ * sched_setscheduler - change the scheduling policy and/or RT priority of a thread.
++ * @p: the task in question.
++ * @policy: new policy.
++ * @param: structure containing the new RT priority.
++ *
++ * Use sched_set_fifo(), read its comment.
++ *
++ * Return: 0 on success. An error code otherwise.
++ *
++ * NOTE that the task may be already dead.
++ */
++int sched_setscheduler(struct task_struct *p, int policy,
++ const struct sched_param *param)
++{
++ return _sched_setscheduler(p, policy, param, true);
++}
++
++int sched_setattr(struct task_struct *p, const struct sched_attr *attr)
++{
++ return __sched_setscheduler(p, attr, true, true);
++}
++
++int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
++{
++ return __sched_setscheduler(p, attr, false, true);
++}
++EXPORT_SYMBOL_GPL(sched_setattr_nocheck);
++
++/**
++ * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
++ * @p: the task in question.
++ * @policy: new policy.
++ * @param: structure containing the new RT priority.
++ *
++ * Just like sched_setscheduler, only don't bother checking if the
++ * current context has permission. For example, this is needed in
++ * stop_machine(): we create temporary high priority worker threads,
++ * but our caller might not have that capability.
++ *
++ * Return: 0 on success. An error code otherwise.
++ */
++int sched_setscheduler_nocheck(struct task_struct *p, int policy,
++ const struct sched_param *param)
++{
++ return _sched_setscheduler(p, policy, param, false);
++}
++
++/*
++ * SCHED_FIFO is a broken scheduler model; that is, it is fundamentally
++ * incapable of resource management, which is the one thing an OS really should
++ * be doing.
++ *
++ * This is of course the reason it is limited to privileged users only.
++ *
++ * Worse still; it is fundamentally impossible to compose static priority
++ * workloads. You cannot take two correctly working static prio workloads
++ * and smash them together and still expect them to work.
++ *
++ * For this reason 'all' FIFO tasks the kernel creates are basically at:
++ *
++ * MAX_RT_PRIO / 2
++ *
++ * The administrator _MUST_ configure the system, the kernel simply doesn't
++ * know enough information to make a sensible choice.
++ */
++void sched_set_fifo(struct task_struct *p)
++{
++ struct sched_param sp = { .sched_priority = MAX_RT_PRIO / 2 };
++ WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
++}
++EXPORT_SYMBOL_GPL(sched_set_fifo);
++
++/*
++ * For when you don't much care about FIFO, but want to be above SCHED_NORMAL.
++ */
++void sched_set_fifo_low(struct task_struct *p)
++{
++ struct sched_param sp = { .sched_priority = 1 };
++ WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
++}
++EXPORT_SYMBOL_GPL(sched_set_fifo_low);
++
++void sched_set_normal(struct task_struct *p, int nice)
++{
++ struct sched_attr attr = {
++ .sched_policy = SCHED_NORMAL,
++ .sched_nice = nice,
++ };
++ WARN_ON_ONCE(sched_setattr_nocheck(p, &attr) != 0);
++}
++EXPORT_SYMBOL_GPL(sched_set_normal);
++
++static int
++do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
++{
++ struct sched_param lparam;
++ struct task_struct *p;
++ int retval;
++
++ if (!param || pid < 0)
++ return -EINVAL;
++ if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
++ return -EFAULT;
++
++ rcu_read_lock();
++ retval = -ESRCH;
++ p = find_process_by_pid(pid);
++ if (likely(p))
++ get_task_struct(p);
++ rcu_read_unlock();
++
++ if (likely(p)) {
++ retval = sched_setscheduler(p, policy, &lparam);
++ put_task_struct(p);
++ }
++
++ return retval;
++}
++
++/*
++ * Mimics kernel/events/core.c perf_copy_attr().
++ */
++static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *attr)
++{
++ u32 size;
++ int ret;
++
++ /* Zero the full structure, so that a short copy will be nice: */
++ memset(attr, 0, sizeof(*attr));
++
++ ret = get_user(size, &uattr->size);
++ if (ret)
++ return ret;
++
++ /* ABI compatibility quirk: */
++ if (!size)
++ size = SCHED_ATTR_SIZE_VER0;
++
++ if (size < SCHED_ATTR_SIZE_VER0 || size > PAGE_SIZE)
++ goto err_size;
++
++ ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size);
++ if (ret) {
++ if (ret == -E2BIG)
++ goto err_size;
++ return ret;
++ }
++
++ /*
++ * XXX: Do we want to be lenient like existing syscalls; or do we want
++ * to be strict and return an error on out-of-bounds values?
++ */
++ attr->sched_nice = clamp(attr->sched_nice, -20, 19);
++
++ /* sched/core.c uses zero here but we already know ret is zero */
++ return 0;
++
++err_size:
++ put_user(sizeof(*attr), &uattr->size);
++ return -E2BIG;
++}
++
++/**
++ * sys_sched_setscheduler - set/change the scheduler policy and RT priority
++ * @pid: the pid in question.
++ * @policy: new policy.
++ *
++ * Return: 0 on success. An error code otherwise.
++ * @param: structure containing the new RT priority.
++ */
++SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param)
++{
++ if (policy < 0)
++ return -EINVAL;
++
++ return do_sched_setscheduler(pid, policy, param);
++}
++
++/**
++ * sys_sched_setparam - set/change the RT priority of a thread
++ * @pid: the pid in question.
++ * @param: structure containing the new RT priority.
++ *
++ * Return: 0 on success. An error code otherwise.
++ */
++SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
++{
++ return do_sched_setscheduler(pid, SETPARAM_POLICY, param);
++}
++
++/**
++ * sys_sched_setattr - same as above, but with extended sched_attr
++ * @pid: the pid in question.
++ * @uattr: structure containing the extended parameters.
++ */
++SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
++ unsigned int, flags)
++{
++ struct sched_attr attr;
++ struct task_struct *p;
++ int retval;
++
++ if (!uattr || pid < 0 || flags)
++ return -EINVAL;
++
++ retval = sched_copy_attr(uattr, &attr);
++ if (retval)
++ return retval;
++
++ if ((int)attr.sched_policy < 0)
++ return -EINVAL;
++
++ rcu_read_lock();
++ retval = -ESRCH;
++ p = find_process_by_pid(pid);
++ if (likely(p))
++ get_task_struct(p);
++ rcu_read_unlock();
++
++ if (likely(p)) {
++ retval = sched_setattr(p, &attr);
++ put_task_struct(p);
++ }
++
++ return retval;
++}
++
++/**
++ * sys_sched_getscheduler - get the policy (scheduling class) of a thread
++ * @pid: the pid in question.
++ *
++ * Return: On success, the policy of the thread. Otherwise, a negative error
++ * code.
++ */
++SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
++{
++ struct task_struct *p;
++ int retval = -EINVAL;
++
++ if (pid < 0)
++ goto out_nounlock;
++
++ retval = -ESRCH;
++ rcu_read_lock();
++ p = find_process_by_pid(pid);
++ if (p) {
++ retval = security_task_getscheduler(p);
++ if (!retval)
++ retval = p->policy;
++ }
++ rcu_read_unlock();
++
++out_nounlock:
++ return retval;
++}
++
++/**
++ * sys_sched_getscheduler - get the RT priority of a thread
++ * @pid: the pid in question.
++ * @param: structure containing the RT priority.
++ *
++ * Return: On success, 0 and the RT priority is in @param. Otherwise, an error
++ * code.
++ */
++SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)
++{
++ struct sched_param lp = { .sched_priority = 0 };
++ struct task_struct *p;
++ int retval = -EINVAL;
++
++ if (!param || pid < 0)
++ goto out_nounlock;
++
++ rcu_read_lock();
++ p = find_process_by_pid(pid);
++ retval = -ESRCH;
++ if (!p)
++ goto out_unlock;
++
++ retval = security_task_getscheduler(p);
++ if (retval)
++ goto out_unlock;
++
++ if (task_has_rt_policy(p))
++ lp.sched_priority = p->rt_priority;
++ rcu_read_unlock();
++
++ /*
++ * This one might sleep, we cannot do it with a spinlock held ...
++ */
++ retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
++
++out_nounlock:
++ return retval;
++
++out_unlock:
++ rcu_read_unlock();
++ return retval;
++}
++
++/*
++ * Copy the kernel size attribute structure (which might be larger
++ * than what user-space knows about) to user-space.
++ *
++ * Note that all cases are valid: user-space buffer can be larger or
++ * smaller than the kernel-space buffer. The usual case is that both
++ * have the same size.
++ */
++static int
++sched_attr_copy_to_user(struct sched_attr __user *uattr,
++ struct sched_attr *kattr,
++ unsigned int usize)
++{
++ unsigned int ksize = sizeof(*kattr);
++
++ if (!access_ok(uattr, usize))
++ return -EFAULT;
++
++ /*
++ * sched_getattr() ABI forwards and backwards compatibility:
++ *
++ * If usize == ksize then we just copy everything to user-space and all is good.
++ *
++ * If usize < ksize then we only copy as much as user-space has space for,
++ * this keeps ABI compatibility as well. We skip the rest.
++ *
++ * If usize > ksize then user-space is using a newer version of the ABI,
++ * which part the kernel doesn't know about. Just ignore it - tooling can
++ * detect the kernel's knowledge of attributes from the attr->size value
++ * which is set to ksize in this case.
++ */
++ kattr->size = min(usize, ksize);
++
++ if (copy_to_user(uattr, kattr, kattr->size))
++ return -EFAULT;
++
++ return 0;
++}
++
++/**
++ * sys_sched_getattr - similar to sched_getparam, but with sched_attr
++ * @pid: the pid in question.
++ * @uattr: structure containing the extended parameters.
++ * @usize: sizeof(attr) for fwd/bwd comp.
++ * @flags: for future extension.
++ */
++SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
++ unsigned int, usize, unsigned int, flags)
++{
++ struct sched_attr kattr = { };
++ struct task_struct *p;
++ int retval;
++
++ if (!uattr || pid < 0 || usize > PAGE_SIZE ||
++ usize < SCHED_ATTR_SIZE_VER0 || flags)
++ return -EINVAL;
++
++ rcu_read_lock();
++ p = find_process_by_pid(pid);
++ retval = -ESRCH;
++ if (!p)
++ goto out_unlock;
++
++ retval = security_task_getscheduler(p);
++ if (retval)
++ goto out_unlock;
++
++ kattr.sched_policy = p->policy;
++ if (p->sched_reset_on_fork)
++ kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
++ if (task_has_rt_policy(p))
++ kattr.sched_priority = p->rt_priority;
++ else
++ kattr.sched_nice = task_nice(p);
++ kattr.sched_flags &= SCHED_FLAG_ALL;
++
++#ifdef CONFIG_UCLAMP_TASK
++ kattr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value;
++ kattr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value;
++#endif
++
++ rcu_read_unlock();
++
++ return sched_attr_copy_to_user(uattr, &kattr, usize);
++
++out_unlock:
++ rcu_read_unlock();
++ return retval;
++}
++
++static int
++__sched_setaffinity(struct task_struct *p, const struct cpumask *mask)
++{
++ int retval;
++ cpumask_var_t cpus_allowed, new_mask;
++
++ if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL))
++ return -ENOMEM;
++
++ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
++ retval = -ENOMEM;
++ goto out_free_cpus_allowed;
++ }
++
++ cpuset_cpus_allowed(p, cpus_allowed);
++ cpumask_and(new_mask, mask, cpus_allowed);
++again:
++ retval = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK | SCA_USER);
++ if (retval)
++ goto out_free_new_mask;
++
++ cpuset_cpus_allowed(p, cpus_allowed);
++ if (!cpumask_subset(new_mask, cpus_allowed)) {
++ /*
++ * We must have raced with a concurrent cpuset
++ * update. Just reset the cpus_allowed to the
++ * cpuset's cpus_allowed
++ */
++ cpumask_copy(new_mask, cpus_allowed);
++ goto again;
++ }
++
++out_free_new_mask:
++ free_cpumask_var(new_mask);
++out_free_cpus_allowed:
++ free_cpumask_var(cpus_allowed);
++ return retval;
++}
++
++long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
++{
++ struct task_struct *p;
++ int retval;
++
++ rcu_read_lock();
++
++ p = find_process_by_pid(pid);
++ if (!p) {
++ rcu_read_unlock();
++ return -ESRCH;
++ }
++
++ /* Prevent p going away */
++ get_task_struct(p);
++ rcu_read_unlock();
++
++ if (p->flags & PF_NO_SETAFFINITY) {
++ retval = -EINVAL;
++ goto out_put_task;
++ }
++
++ if (!check_same_owner(p)) {
++ rcu_read_lock();
++ if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
++ rcu_read_unlock();
++ retval = -EPERM;
++ goto out_put_task;
++ }
++ rcu_read_unlock();
++ }
++
++ retval = security_task_setscheduler(p);
++ if (retval)
++ goto out_put_task;
++
++ retval = __sched_setaffinity(p, in_mask);
++out_put_task:
++ put_task_struct(p);
++ return retval;
++}
++
++static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len,
++ struct cpumask *new_mask)
++{
++ if (len < cpumask_size())
++ cpumask_clear(new_mask);
++ else if (len > cpumask_size())
++ len = cpumask_size();
++
++ return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0;
++}
++
++/**
++ * sys_sched_setaffinity - set the CPU affinity of a process
++ * @pid: pid of the process
++ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
++ * @user_mask_ptr: user-space pointer to the new CPU mask
++ *
++ * Return: 0 on success. An error code otherwise.
++ */
++SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
++ unsigned long __user *, user_mask_ptr)
++{
++ cpumask_var_t new_mask;
++ int retval;
++
++ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
++ return -ENOMEM;
++
++ retval = get_user_cpu_mask(user_mask_ptr, len, new_mask);
++ if (retval == 0)
++ retval = sched_setaffinity(pid, new_mask);
++ free_cpumask_var(new_mask);
++ return retval;
++}
++
++long sched_getaffinity(pid_t pid, cpumask_t *mask)
++{
++ struct task_struct *p;
++ raw_spinlock_t *lock;
++ unsigned long flags;
++ int retval;
++
++ rcu_read_lock();
++
++ retval = -ESRCH;
++ p = find_process_by_pid(pid);
++ if (!p)
++ goto out_unlock;
++
++ retval = security_task_getscheduler(p);
++ if (retval)
++ goto out_unlock;
++
++ task_access_lock_irqsave(p, &lock, &flags);
++ cpumask_and(mask, &p->cpus_mask, cpu_active_mask);
++ task_access_unlock_irqrestore(p, lock, &flags);
++
++out_unlock:
++ rcu_read_unlock();
++
++ return retval;
++}
++
++/**
++ * sys_sched_getaffinity - get the CPU affinity of a process
++ * @pid: pid of the process
++ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
++ * @user_mask_ptr: user-space pointer to hold the current CPU mask
++ *
++ * Return: size of CPU mask copied to user_mask_ptr on success. An
++ * error code otherwise.
++ */
++SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
++ unsigned long __user *, user_mask_ptr)
++{
++ int ret;
++ cpumask_var_t mask;
++
++ if ((len * BITS_PER_BYTE) < nr_cpu_ids)
++ return -EINVAL;
++ if (len & (sizeof(unsigned long)-1))
++ return -EINVAL;
++
++ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
++ return -ENOMEM;
++
++ ret = sched_getaffinity(pid, mask);
++ if (ret == 0) {
++ unsigned int retlen = min_t(size_t, len, cpumask_size());
++
++ if (copy_to_user(user_mask_ptr, mask, retlen))
++ ret = -EFAULT;
++ else
++ ret = retlen;
++ }
++ free_cpumask_var(mask);
++
++ return ret;
++}
++
++static void do_sched_yield(void)
++{
++ struct rq *rq;
++ struct rq_flags rf;
++
++ if (!sched_yield_type)
++ return;
++
++ rq = this_rq_lock_irq(&rf);
++
++ schedstat_inc(rq->yld_count);
++
++ if (1 == sched_yield_type) {
++ if (!rt_task(current))
++ do_sched_yield_type_1(current, rq);
++ } else if (2 == sched_yield_type) {
++ if (rq->nr_running > 1)
++ rq->skip = current;
++ }
++
++ preempt_disable();
++ raw_spin_unlock_irq(&rq->lock);
++ sched_preempt_enable_no_resched();
++
++ schedule();
++}
++
++/**
++ * sys_sched_yield - yield the current processor to other threads.
++ *
++ * This function yields the current CPU to other tasks. If there are no
++ * other threads running on this CPU then this function will return.
++ *
++ * Return: 0.
++ */
++SYSCALL_DEFINE0(sched_yield)
++{
++ do_sched_yield();
++ return 0;
++}
++
++#if !defined(CONFIG_PREEMPTION) || defined(CONFIG_PREEMPT_DYNAMIC)
++int __sched __cond_resched(void)
++{
++ if (should_resched(0)) {
++ preempt_schedule_common();
++ return 1;
++ }
++ /*
++ * In preemptible kernels, ->rcu_read_lock_nesting tells the tick
++ * whether the current CPU is in an RCU read-side critical section,
++ * so the tick can report quiescent states even for CPUs looping
++ * in kernel context. In contrast, in non-preemptible kernels,
++ * RCU readers leave no in-memory hints, which means that CPU-bound
++ * processes executing in kernel context might never report an
++ * RCU quiescent state. Therefore, the following code causes
++ * cond_resched() to report a quiescent state, but only when RCU
++ * is in urgent need of one.
++ */
++#ifndef CONFIG_PREEMPT_RCU
++ rcu_all_qs();
++#endif
++ return 0;
++}
++EXPORT_SYMBOL(__cond_resched);
++#endif
++
++#ifdef CONFIG_PREEMPT_DYNAMIC
++DEFINE_STATIC_CALL_RET0(cond_resched, __cond_resched);
++EXPORT_STATIC_CALL_TRAMP(cond_resched);
++
++DEFINE_STATIC_CALL_RET0(might_resched, __cond_resched);
++EXPORT_STATIC_CALL_TRAMP(might_resched);
++#endif
++
++/*
++ * __cond_resched_lock() - if a reschedule is pending, drop the given lock,
++ * call schedule, and on return reacquire the lock.
++ *
++ * This works OK both with and without CONFIG_PREEMPTION. We do strange low-level
++ * operations here to prevent schedule() from being called twice (once via
++ * spin_unlock(), once by hand).
++ */
++int __cond_resched_lock(spinlock_t *lock)
++{
++ int resched = should_resched(PREEMPT_LOCK_OFFSET);
++ int ret = 0;
++
++ lockdep_assert_held(lock);
++
++ if (spin_needbreak(lock) || resched) {
++ spin_unlock(lock);
++ if (resched)
++ preempt_schedule_common();
++ else
++ cpu_relax();
++ ret = 1;
++ spin_lock(lock);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(__cond_resched_lock);
++
++int __cond_resched_rwlock_read(rwlock_t *lock)
++{
++ int resched = should_resched(PREEMPT_LOCK_OFFSET);
++ int ret = 0;
++
++ lockdep_assert_held_read(lock);
++
++ if (rwlock_needbreak(lock) || resched) {
++ read_unlock(lock);
++ if (resched)
++ preempt_schedule_common();
++ else
++ cpu_relax();
++ ret = 1;
++ read_lock(lock);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(__cond_resched_rwlock_read);
++
++int __cond_resched_rwlock_write(rwlock_t *lock)
++{
++ int resched = should_resched(PREEMPT_LOCK_OFFSET);
++ int ret = 0;
++
++ lockdep_assert_held_write(lock);
++
++ if (rwlock_needbreak(lock) || resched) {
++ write_unlock(lock);
++ if (resched)
++ preempt_schedule_common();
++ else
++ cpu_relax();
++ ret = 1;
++ write_lock(lock);
++ }
++ return ret;
++}
++EXPORT_SYMBOL(__cond_resched_rwlock_write);
++
++/**
++ * yield - yield the current processor to other threads.
++ *
++ * Do not ever use this function, there's a 99% chance you're doing it wrong.
++ *
++ * The scheduler is at all times free to pick the calling task as the most
++ * eligible task to run, if removing the yield() call from your code breaks
++ * it, it's already broken.
++ *
++ * Typical broken usage is:
++ *
++ * while (!event)
++ * yield();
++ *
++ * where one assumes that yield() will let 'the other' process run that will
++ * make event true. If the current task is a SCHED_FIFO task that will never
++ * happen. Never use yield() as a progress guarantee!!
++ *
++ * If you want to use yield() to wait for something, use wait_event().
++ * If you want to use yield() to be 'nice' for others, use cond_resched().
++ * If you still want to use yield(), do not!
++ */
++void __sched yield(void)
++{
++ set_current_state(TASK_RUNNING);
++ do_sched_yield();
++}
++EXPORT_SYMBOL(yield);
++
++/**
++ * yield_to - yield the current processor to another thread in
++ * your thread group, or accelerate that thread toward the
++ * processor it's on.
++ * @p: target task
++ * @preempt: whether task preemption is allowed or not
++ *
++ * It's the caller's job to ensure that the target task struct
++ * can't go away on us before we can do any checks.
++ *
++ * In Alt schedule FW, yield_to is not supported.
++ *
++ * Return:
++ * true (>0) if we indeed boosted the target task.
++ * false (0) if we failed to boost the target.
++ * -ESRCH if there's no task to yield to.
++ */
++int __sched yield_to(struct task_struct *p, bool preempt)
++{
++ return 0;
++}
++EXPORT_SYMBOL_GPL(yield_to);
++
++int io_schedule_prepare(void)
++{
++ int old_iowait = current->in_iowait;
++
++ current->in_iowait = 1;
++ blk_schedule_flush_plug(current);
++
++ return old_iowait;
++}
++
++void io_schedule_finish(int token)
++{
++ current->in_iowait = token;
++}
++
++/*
++ * This task is about to go to sleep on IO. Increment rq->nr_iowait so
++ * that process accounting knows that this is a task in IO wait state.
++ *
++ * But don't do that if it is a deliberate, throttling IO wait (this task
++ * has set its backing_dev_info: the queue against which it should throttle)
++ */
++
++long __sched io_schedule_timeout(long timeout)
++{
++ int token;
++ long ret;
++
++ token = io_schedule_prepare();
++ ret = schedule_timeout(timeout);
++ io_schedule_finish(token);
++
++ return ret;
++}
++EXPORT_SYMBOL(io_schedule_timeout);
++
++void __sched io_schedule(void)
++{
++ int token;
++
++ token = io_schedule_prepare();
++ schedule();
++ io_schedule_finish(token);
++}
++EXPORT_SYMBOL(io_schedule);
++
++/**
++ * sys_sched_get_priority_max - return maximum RT priority.
++ * @policy: scheduling class.
++ *
++ * Return: On success, this syscall returns the maximum
++ * rt_priority that can be used by a given scheduling class.
++ * On failure, a negative error code is returned.
++ */
++SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
++{
++ int ret = -EINVAL;
++
++ switch (policy) {
++ case SCHED_FIFO:
++ case SCHED_RR:
++ ret = MAX_RT_PRIO - 1;
++ break;
++ case SCHED_NORMAL:
++ case SCHED_BATCH:
++ case SCHED_IDLE:
++ ret = 0;
++ break;
++ }
++ return ret;
++}
++
++/**
++ * sys_sched_get_priority_min - return minimum RT priority.
++ * @policy: scheduling class.
++ *
++ * Return: On success, this syscall returns the minimum
++ * rt_priority that can be used by a given scheduling class.
++ * On failure, a negative error code is returned.
++ */
++SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
++{
++ int ret = -EINVAL;
++
++ switch (policy) {
++ case SCHED_FIFO:
++ case SCHED_RR:
++ ret = 1;
++ break;
++ case SCHED_NORMAL:
++ case SCHED_BATCH:
++ case SCHED_IDLE:
++ ret = 0;
++ break;
++ }
++ return ret;
++}
++
++static int sched_rr_get_interval(pid_t pid, struct timespec64 *t)
++{
++ struct task_struct *p;
++ int retval;
++
++ alt_sched_debug();
++
++ if (pid < 0)
++ return -EINVAL;
++
++ retval = -ESRCH;
++ rcu_read_lock();
++ p = find_process_by_pid(pid);
++ if (!p)
++ goto out_unlock;
++
++ retval = security_task_getscheduler(p);
++ if (retval)
++ goto out_unlock;
++ rcu_read_unlock();
++
++ *t = ns_to_timespec64(sched_timeslice_ns);
++ return 0;
++
++out_unlock:
++ rcu_read_unlock();
++ return retval;
++}
++
++/**
++ * sys_sched_rr_get_interval - return the default timeslice of a process.
++ * @pid: pid of the process.
++ * @interval: userspace pointer to the timeslice value.
++ *
++ *
++ * Return: On success, 0 and the timeslice is in @interval. Otherwise,
++ * an error code.
++ */
++SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
++ struct __kernel_timespec __user *, interval)
++{
++ struct timespec64 t;
++ int retval = sched_rr_get_interval(pid, &t);
++
++ if (retval == 0)
++ retval = put_timespec64(&t, interval);
++
++ return retval;
++}
++
++#ifdef CONFIG_COMPAT_32BIT_TIME
++SYSCALL_DEFINE2(sched_rr_get_interval_time32, pid_t, pid,
++ struct old_timespec32 __user *, interval)
++{
++ struct timespec64 t;
++ int retval = sched_rr_get_interval(pid, &t);
++
++ if (retval == 0)
++ retval = put_old_timespec32(&t, interval);
++ return retval;
++}
++#endif
++
++void sched_show_task(struct task_struct *p)
++{
++ unsigned long free = 0;
++ int ppid;
++
++ if (!try_get_task_stack(p))
++ return;
++
++ pr_info("task:%-15.15s state:%c", p->comm, task_state_to_char(p));
++
++ if (task_is_running(p))
++ pr_cont(" running task ");
++#ifdef CONFIG_DEBUG_STACK_USAGE
++ free = stack_not_used(p);
++#endif
++ ppid = 0;
++ rcu_read_lock();
++ if (pid_alive(p))
++ ppid = task_pid_nr(rcu_dereference(p->real_parent));
++ rcu_read_unlock();
++ pr_cont(" stack:%5lu pid:%5d ppid:%6d flags:0x%08lx\n",
++ free, task_pid_nr(p), ppid,
++ (unsigned long)task_thread_info(p)->flags);
++
++ print_worker_info(KERN_INFO, p);
++ print_stop_info(KERN_INFO, p);
++ show_stack(p, NULL, KERN_INFO);
++ put_task_stack(p);
++}
++EXPORT_SYMBOL_GPL(sched_show_task);
++
++static inline bool
++state_filter_match(unsigned long state_filter, struct task_struct *p)
++{
++ unsigned int state = READ_ONCE(p->__state);
++
++ /* no filter, everything matches */
++ if (!state_filter)
++ return true;
++
++ /* filter, but doesn't match */
++ if (!(state & state_filter))
++ return false;
++
++ /*
++ * When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
++ * TASK_KILLABLE).
++ */
++ if (state_filter == TASK_UNINTERRUPTIBLE && state == TASK_IDLE)
++ return false;
++
++ return true;
++}
++
++
++void show_state_filter(unsigned int state_filter)
++{
++ struct task_struct *g, *p;
++
++ rcu_read_lock();
++ for_each_process_thread(g, p) {
++ /*
++ * reset the NMI-timeout, listing all files on a slow
++ * console might take a lot of time:
++ * Also, reset softlockup watchdogs on all CPUs, because
++ * another CPU might be blocked waiting for us to process
++ * an IPI.
++ */
++ touch_nmi_watchdog();
++ touch_all_softlockup_watchdogs();
++ if (state_filter_match(state_filter, p))
++ sched_show_task(p);
++ }
++
++#ifdef CONFIG_SCHED_DEBUG
++ /* TODO: Alt schedule FW should support this
++ if (!state_filter)
++ sysrq_sched_debug_show();
++ */
++#endif
++ rcu_read_unlock();
++ /*
++ * Only show locks if all tasks are dumped:
++ */
++ if (!state_filter)
++ debug_show_all_locks();
++}
++
++void dump_cpu_task(int cpu)
++{
++ pr_info("Task dump for CPU %d:\n", cpu);
++ sched_show_task(cpu_curr(cpu));
++}
++
++/**
++ * init_idle - set up an idle thread for a given CPU
++ * @idle: task in question
++ * @cpu: CPU the idle task belongs to
++ *
++ * NOTE: this function does not set the idle thread's NEED_RESCHED
++ * flag, to make booting more robust.
++ */
++void __init init_idle(struct task_struct *idle, int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++
++ __sched_fork(0, idle);
++
++ /*
++ * The idle task doesn't need the kthread struct to function, but it
++ * is dressed up as a per-CPU kthread and thus needs to play the part
++ * if we want to avoid special-casing it in code that deals with per-CPU
++ * kthreads.
++ */
++ set_kthread_struct(idle);
++
++ raw_spin_lock_irqsave(&idle->pi_lock, flags);
++ raw_spin_lock(&rq->lock);
++ update_rq_clock(rq);
++
++ idle->last_ran = rq->clock_task;
++ idle->__state = TASK_RUNNING;
++ /*
++ * PF_KTHREAD should already be set at this point; regardless, make it
++ * look like a proper per-CPU kthread.
++ */
++ idle->flags |= PF_IDLE | PF_KTHREAD | PF_NO_SETAFFINITY;
++ kthread_set_per_cpu(idle, cpu);
++
++ sched_queue_init_idle(&rq->queue, idle);
++
++ scs_task_reset(idle);
++ kasan_unpoison_task_stack(idle);
++
++#ifdef CONFIG_SMP
++ /*
++ * It's possible that init_idle() gets called multiple times on a task,
++ * in that case do_set_cpus_allowed() will not do the right thing.
++ *
++ * And since this is boot we can forgo the serialisation.
++ */
++ set_cpus_allowed_common(idle, cpumask_of(cpu));
++#endif
++
++ /* Silence PROVE_RCU */
++ rcu_read_lock();
++ __set_task_cpu(idle, cpu);
++ rcu_read_unlock();
++
++ rq->idle = idle;
++ rcu_assign_pointer(rq->curr, idle);
++ idle->on_cpu = 1;
++
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock_irqrestore(&idle->pi_lock, flags);
++
++ /* Set the preempt count _outside_ the spinlocks! */
++ init_idle_preempt_count(idle, cpu);
++
++ ftrace_graph_init_idle_task(idle, cpu);
++ vtime_init_idle(idle, cpu);
++#ifdef CONFIG_SMP
++ sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
++#endif
++}
++
++#ifdef CONFIG_SMP
++
++int cpuset_cpumask_can_shrink(const struct cpumask __maybe_unused *cur,
++ const struct cpumask __maybe_unused *trial)
++{
++ return 1;
++}
++
++int task_can_attach(struct task_struct *p,
++ const struct cpumask *cs_cpus_allowed)
++{
++ int ret = 0;
++
++ /*
++ * Kthreads which disallow setaffinity shouldn't be moved
++ * to a new cpuset; we don't want to change their CPU
++ * affinity and isolating such threads by their set of
++ * allowed nodes is unnecessary. Thus, cpusets are not
++ * applicable for such threads. This prevents checking for
++ * success of set_cpus_allowed_ptr() on all attached tasks
++ * before cpus_mask may be changed.
++ */
++ if (p->flags & PF_NO_SETAFFINITY)
++ ret = -EINVAL;
++
++ return ret;
++}
++
++bool sched_smp_initialized __read_mostly;
++
++#ifdef CONFIG_HOTPLUG_CPU
++/*
++ * Ensures that the idle task is using init_mm right before its CPU goes
++ * offline.
++ */
++void idle_task_exit(void)
++{
++ struct mm_struct *mm = current->active_mm;
++
++ BUG_ON(current != this_rq()->idle);
++
++ if (mm != &init_mm) {
++ switch_mm(mm, &init_mm, current);
++ finish_arch_post_lock_switch();
++ }
++
++ scs_task_reset(current);
++ /* finish_cpu(), as ran on the BP, will clean up the active_mm state */
++}
++
++static int __balance_push_cpu_stop(void *arg)
++{
++ struct task_struct *p = arg;
++ struct rq *rq = this_rq();
++ struct rq_flags rf;
++ int cpu;
++
++ raw_spin_lock_irq(&p->pi_lock);
++ rq_lock(rq, &rf);
++
++ update_rq_clock(rq);
++
++ if (task_rq(p) == rq && task_on_rq_queued(p)) {
++ cpu = select_fallback_rq(rq->cpu, p);
++ rq = __migrate_task(rq, p, cpu);
++ }
++
++ rq_unlock(rq, &rf);
++ raw_spin_unlock_irq(&p->pi_lock);
++
++ put_task_struct(p);
++
++ return 0;
++}
++
++static DEFINE_PER_CPU(struct cpu_stop_work, push_work);
++
++/*
++ * This is enabled below SCHED_AP_ACTIVE; when !cpu_active(), but only
++ * effective when the hotplug motion is down.
++ */
++static void balance_push(struct rq *rq)
++{
++ struct task_struct *push_task = rq->curr;
++
++ lockdep_assert_held(&rq->lock);
++
++ /*
++ * Ensure the thing is persistent until balance_push_set(.on = false);
++ */
++ rq->balance_callback = &balance_push_callback;
++
++ /*
++ * Only active while going offline and when invoked on the outgoing
++ * CPU.
++ */
++ if (!cpu_dying(rq->cpu) || rq != this_rq())
++ return;
++
++ /*
++ * Both the cpu-hotplug and stop task are in this case and are
++ * required to complete the hotplug process.
++ */
++ if (kthread_is_per_cpu(push_task) ||
++ is_migration_disabled(push_task)) {
++
++ /*
++ * If this is the idle task on the outgoing CPU try to wake
++ * up the hotplug control thread which might wait for the
++ * last task to vanish. The rcuwait_active() check is
++ * accurate here because the waiter is pinned on this CPU
++ * and can't obviously be running in parallel.
++ *
++ * On RT kernels this also has to check whether there are
++ * pinned and scheduled out tasks on the runqueue. They
++ * need to leave the migrate disabled section first.
++ */
++ if (!rq->nr_running && !rq_has_pinned_tasks(rq) &&
++ rcuwait_active(&rq->hotplug_wait)) {
++ raw_spin_unlock(&rq->lock);
++ rcuwait_wake_up(&rq->hotplug_wait);
++ raw_spin_lock(&rq->lock);
++ }
++ return;
++ }
++
++ get_task_struct(push_task);
++ /*
++ * Temporarily drop rq->lock such that we can wake-up the stop task.
++ * Both preemption and IRQs are still disabled.
++ */
++ raw_spin_unlock(&rq->lock);
++ stop_one_cpu_nowait(rq->cpu, __balance_push_cpu_stop, push_task,
++ this_cpu_ptr(&push_work));
++ /*
++ * At this point need_resched() is true and we'll take the loop in
++ * schedule(). The next pick is obviously going to be the stop task
++ * which kthread_is_per_cpu() and will push this task away.
++ */
++ raw_spin_lock(&rq->lock);
++}
++
++static void balance_push_set(int cpu, bool on)
++{
++ struct rq *rq = cpu_rq(cpu);
++ struct rq_flags rf;
++
++ rq_lock_irqsave(rq, &rf);
++ if (on) {
++ WARN_ON_ONCE(rq->balance_callback);
++ rq->balance_callback = &balance_push_callback;
++ } else if (rq->balance_callback == &balance_push_callback) {
++ rq->balance_callback = NULL;
++ }
++ rq_unlock_irqrestore(rq, &rf);
++}
++
++/*
++ * Invoked from a CPUs hotplug control thread after the CPU has been marked
++ * inactive. All tasks which are not per CPU kernel threads are either
++ * pushed off this CPU now via balance_push() or placed on a different CPU
++ * during wakeup. Wait until the CPU is quiescent.
++ */
++static void balance_hotplug_wait(void)
++{
++ struct rq *rq = this_rq();
++
++ rcuwait_wait_event(&rq->hotplug_wait,
++ rq->nr_running == 1 && !rq_has_pinned_tasks(rq),
++ TASK_UNINTERRUPTIBLE);
++}
++
++#else
++
++static void balance_push(struct rq *rq)
++{
++}
++
++static void balance_push_set(int cpu, bool on)
++{
++}
++
++static inline void balance_hotplug_wait(void)
++{
++}
++#endif /* CONFIG_HOTPLUG_CPU */
++
++static void set_rq_offline(struct rq *rq)
++{
++ if (rq->online)
++ rq->online = false;
++}
++
++static void set_rq_online(struct rq *rq)
++{
++ if (!rq->online)
++ rq->online = true;
++}
++
++/*
++ * used to mark begin/end of suspend/resume:
++ */
++static int num_cpus_frozen;
++
++/*
++ * Update cpusets according to cpu_active mask. If cpusets are
++ * disabled, cpuset_update_active_cpus() becomes a simple wrapper
++ * around partition_sched_domains().
++ *
++ * If we come here as part of a suspend/resume, don't touch cpusets because we
++ * want to restore it back to its original state upon resume anyway.
++ */
++static void cpuset_cpu_active(void)
++{
++ if (cpuhp_tasks_frozen) {
++ /*
++ * num_cpus_frozen tracks how many CPUs are involved in suspend
++ * resume sequence. As long as this is not the last online
++ * operation in the resume sequence, just build a single sched
++ * domain, ignoring cpusets.
++ */
++ partition_sched_domains(1, NULL, NULL);
++ if (--num_cpus_frozen)
++ return;
++ /*
++ * This is the last CPU online operation. So fall through and
++ * restore the original sched domains by considering the
++ * cpuset configurations.
++ */
++ cpuset_force_rebuild();
++ }
++
++ cpuset_update_active_cpus();
++}
++
++static int cpuset_cpu_inactive(unsigned int cpu)
++{
++ if (!cpuhp_tasks_frozen) {
++ cpuset_update_active_cpus();
++ } else {
++ num_cpus_frozen++;
++ partition_sched_domains(1, NULL, NULL);
++ }
++ return 0;
++}
++
++int sched_cpu_activate(unsigned int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++
++ /*
++ * Clear the balance_push callback and prepare to schedule
++ * regular tasks.
++ */
++ balance_push_set(cpu, false);
++
++#ifdef CONFIG_SCHED_SMT
++ /*
++ * When going up, increment the number of cores with SMT present.
++ */
++ if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
++ static_branch_inc_cpuslocked(&sched_smt_present);
++#endif
++ set_cpu_active(cpu, true);
++
++ if (sched_smp_initialized)
++ cpuset_cpu_active();
++
++ /*
++ * Put the rq online, if not already. This happens:
++ *
++ * 1) In the early boot process, because we build the real domains
++ * after all cpus have been brought up.
++ *
++ * 2) At runtime, if cpuset_cpu_active() fails to rebuild the
++ * domains.
++ */
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ set_rq_online(rq);
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++
++ return 0;
++}
++
++int sched_cpu_deactivate(unsigned int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++ int ret;
++
++ set_cpu_active(cpu, false);
++
++ /*
++ * From this point forward, this CPU will refuse to run any task that
++ * is not: migrate_disable() or KTHREAD_IS_PER_CPU, and will actively
++ * push those tasks away until this gets cleared, see
++ * sched_cpu_dying().
++ */
++ balance_push_set(cpu, true);
++
++ /*
++ * We've cleared cpu_active_mask, wait for all preempt-disabled and RCU
++ * users of this state to go away such that all new such users will
++ * observe it.
++ *
++ * Specifically, we rely on ttwu to no longer target this CPU, see
++ * ttwu_queue_cond() and is_cpu_allowed().
++ *
++ * Do sync before park smpboot threads to take care the rcu boost case.
++ */
++ synchronize_rcu();
++
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ update_rq_clock(rq);
++ set_rq_offline(rq);
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++
++#ifdef CONFIG_SCHED_SMT
++ /*
++ * When going down, decrement the number of cores with SMT present.
++ */
++ if (cpumask_weight(cpu_smt_mask(cpu)) == 2) {
++ static_branch_dec_cpuslocked(&sched_smt_present);
++ if (!static_branch_likely(&sched_smt_present))
++ cpumask_clear(&sched_sg_idle_mask);
++ }
++#endif
++
++ if (!sched_smp_initialized)
++ return 0;
++
++ ret = cpuset_cpu_inactive(cpu);
++ if (ret) {
++ balance_push_set(cpu, false);
++ set_cpu_active(cpu, true);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void sched_rq_cpu_starting(unsigned int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++
++ rq->calc_load_update = calc_load_update;
++}
++
++int sched_cpu_starting(unsigned int cpu)
++{
++ sched_rq_cpu_starting(cpu);
++ sched_tick_start(cpu);
++ return 0;
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++
++/*
++ * Invoked immediately before the stopper thread is invoked to bring the
++ * CPU down completely. At this point all per CPU kthreads except the
++ * hotplug thread (current) and the stopper thread (inactive) have been
++ * either parked or have been unbound from the outgoing CPU. Ensure that
++ * any of those which might be on the way out are gone.
++ *
++ * If after this point a bound task is being woken on this CPU then the
++ * responsible hotplug callback has failed to do it's job.
++ * sched_cpu_dying() will catch it with the appropriate fireworks.
++ */
++int sched_cpu_wait_empty(unsigned int cpu)
++{
++ balance_hotplug_wait();
++ return 0;
++}
++
++/*
++ * Since this CPU is going 'away' for a while, fold any nr_active delta we
++ * might have. Called from the CPU stopper task after ensuring that the
++ * stopper is the last running task on the CPU, so nr_active count is
++ * stable. We need to take the teardown thread which is calling this into
++ * account, so we hand in adjust = 1 to the load calculation.
++ *
++ * Also see the comment "Global load-average calculations".
++ */
++static void calc_load_migrate(struct rq *rq)
++{
++ long delta = calc_load_fold_active(rq, 1);
++
++ if (delta)
++ atomic_long_add(delta, &calc_load_tasks);
++}
++
++static void dump_rq_tasks(struct rq *rq, const char *loglvl)
++{
++ struct task_struct *g, *p;
++ int cpu = cpu_of(rq);
++
++ lockdep_assert_held(&rq->lock);
++
++ printk("%sCPU%d enqueued tasks (%u total):\n", loglvl, cpu, rq->nr_running);
++ for_each_process_thread(g, p) {
++ if (task_cpu(p) != cpu)
++ continue;
++
++ if (!task_on_rq_queued(p))
++ continue;
++
++ printk("%s\tpid: %d, name: %s\n", loglvl, p->pid, p->comm);
++ }
++}
++
++int sched_cpu_dying(unsigned int cpu)
++{
++ struct rq *rq = cpu_rq(cpu);
++ unsigned long flags;
++
++ /* Handle pending wakeups and then migrate everything off */
++ sched_tick_stop(cpu);
++
++ raw_spin_lock_irqsave(&rq->lock, flags);
++ if (rq->nr_running != 1 || rq_has_pinned_tasks(rq)) {
++ WARN(true, "Dying CPU not properly vacated!");
++ dump_rq_tasks(rq, KERN_WARNING);
++ }
++ raw_spin_unlock_irqrestore(&rq->lock, flags);
++
++ calc_load_migrate(rq);
++ hrtick_clear(rq);
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_SMP
++static void sched_init_topology_cpumask_early(void)
++{
++ int cpu;
++ cpumask_t *tmp;
++
++ for_each_possible_cpu(cpu) {
++ /* init topo masks */
++ tmp = per_cpu(sched_cpu_topo_masks, cpu);
++
++ cpumask_copy(tmp, cpumask_of(cpu));
++ tmp++;
++ cpumask_copy(tmp, cpu_possible_mask);
++ per_cpu(sched_cpu_llc_mask, cpu) = tmp;
++ per_cpu(sched_cpu_topo_end_mask, cpu) = ++tmp;
++ /*per_cpu(sd_llc_id, cpu) = cpu;*/
++ }
++}
++
++#define TOPOLOGY_CPUMASK(name, mask, last)\
++ if (cpumask_and(topo, topo, mask)) { \
++ cpumask_copy(topo, mask); \
++ printk(KERN_INFO "sched: cpu#%02d topo: 0x%08lx - "#name, \
++ cpu, (topo++)->bits[0]); \
++ } \
++ if (!last) \
++ cpumask_complement(topo, mask)
++
++static void sched_init_topology_cpumask(void)
++{
++ int cpu;
++ cpumask_t *topo;
++
++ for_each_online_cpu(cpu) {
++ /* take chance to reset time slice for idle tasks */
++ cpu_rq(cpu)->idle->time_slice = sched_timeslice_ns;
++
++ topo = per_cpu(sched_cpu_topo_masks, cpu) + 1;
++
++ cpumask_complement(topo, cpumask_of(cpu));
++#ifdef CONFIG_SCHED_SMT
++ TOPOLOGY_CPUMASK(smt, topology_sibling_cpumask(cpu), false);
++#endif
++ per_cpu(sd_llc_id, cpu) = cpumask_first(cpu_coregroup_mask(cpu));
++ per_cpu(sched_cpu_llc_mask, cpu) = topo;
++ TOPOLOGY_CPUMASK(coregroup, cpu_coregroup_mask(cpu), false);
++
++ TOPOLOGY_CPUMASK(core, topology_core_cpumask(cpu), false);
++
++ TOPOLOGY_CPUMASK(others, cpu_online_mask, true);
++
++ per_cpu(sched_cpu_topo_end_mask, cpu) = topo;
++ printk(KERN_INFO "sched: cpu#%02d llc_id = %d, llc_mask idx = %d\n",
++ cpu, per_cpu(sd_llc_id, cpu),
++ (int) (per_cpu(sched_cpu_llc_mask, cpu) -
++ per_cpu(sched_cpu_topo_masks, cpu)));
++ }
++}
++#endif
++
++void __init sched_init_smp(void)
++{
++ /* Move init over to a non-isolated CPU */
++ if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0)
++ BUG();
++ current->flags &= ~PF_NO_SETAFFINITY;
++
++ sched_init_topology_cpumask();
++
++ sched_smp_initialized = true;
++}
++#else
++void __init sched_init_smp(void)
++{
++ cpu_rq(0)->idle->time_slice = sched_timeslice_ns;
++}
++#endif /* CONFIG_SMP */
++
++int in_sched_functions(unsigned long addr)
++{
++ return in_lock_functions(addr) ||
++ (addr >= (unsigned long)__sched_text_start
++ && addr < (unsigned long)__sched_text_end);
++}
++
++#ifdef CONFIG_CGROUP_SCHED
++/* task group related information */
++struct task_group {
++ struct cgroup_subsys_state css;
++
++ struct rcu_head rcu;
++ struct list_head list;
++
++ struct task_group *parent;
++ struct list_head siblings;
++ struct list_head children;
++#ifdef CONFIG_FAIR_GROUP_SCHED
++ unsigned long shares;
++#endif
++};
++
++/*
++ * Default task group.
++ * Every task in system belongs to this group at bootup.
++ */
++struct task_group root_task_group;
++LIST_HEAD(task_groups);
++
++/* Cacheline aligned slab cache for task_group */
++static struct kmem_cache *task_group_cache __read_mostly;
++#endif /* CONFIG_CGROUP_SCHED */
++
++void __init sched_init(void)
++{
++ int i;
++ struct rq *rq;
++
++ printk(KERN_INFO ALT_SCHED_VERSION_MSG);
++
++ wait_bit_init();
++
++#ifdef CONFIG_SMP
++ for (i = 0; i < SCHED_BITS; i++)
++ cpumask_copy(sched_rq_watermark + i, cpu_present_mask);
++#endif
++
++#ifdef CONFIG_CGROUP_SCHED
++ task_group_cache = KMEM_CACHE(task_group, 0);
++
++ list_add(&root_task_group.list, &task_groups);
++ INIT_LIST_HEAD(&root_task_group.children);
++ INIT_LIST_HEAD(&root_task_group.siblings);
++#endif /* CONFIG_CGROUP_SCHED */
++ for_each_possible_cpu(i) {
++ rq = cpu_rq(i);
++
++ sched_queue_init(&rq->queue);
++ rq->watermark = IDLE_TASK_SCHED_PRIO;
++ rq->skip = NULL;
++
++ raw_spin_lock_init(&rq->lock);
++ rq->nr_running = rq->nr_uninterruptible = 0;
++ rq->calc_load_active = 0;
++ rq->calc_load_update = jiffies + LOAD_FREQ;
++#ifdef CONFIG_SMP
++ rq->online = false;
++ rq->cpu = i;
++
++#ifdef CONFIG_SCHED_SMT
++ rq->active_balance = 0;
++#endif
++
++#ifdef CONFIG_NO_HZ_COMMON
++ INIT_CSD(&rq->nohz_csd, nohz_csd_func, rq);
++#endif
++ rq->balance_callback = &balance_push_callback;
++#ifdef CONFIG_HOTPLUG_CPU
++ rcuwait_init(&rq->hotplug_wait);
++#endif
++#endif /* CONFIG_SMP */
++ rq->nr_switches = 0;
++
++ hrtick_rq_init(rq);
++ atomic_set(&rq->nr_iowait, 0);
++ }
++#ifdef CONFIG_SMP
++ /* Set rq->online for cpu 0 */
++ cpu_rq(0)->online = true;
++#endif
++ /*
++ * The boot idle thread does lazy MMU switching as well:
++ */
++ mmgrab(&init_mm);
++ enter_lazy_tlb(&init_mm, current);
++
++ /*
++ * Make us the idle thread. Technically, schedule() should not be
++ * called from this thread, however somewhere below it might be,
++ * but because we are the idle thread, we just pick up running again
++ * when this runqueue becomes "idle".
++ */
++ init_idle(current, smp_processor_id());
++
++ calc_load_update = jiffies + LOAD_FREQ;
++
++#ifdef CONFIG_SMP
++ idle_thread_set_boot_cpu();
++ balance_push_set(smp_processor_id(), false);
++
++ sched_init_topology_cpumask_early();
++#endif /* SMP */
++
++ psi_init();
++}
++
++#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
++static inline int preempt_count_equals(int preempt_offset)
++{
++ int nested = preempt_count() + rcu_preempt_depth();
++
++ return (nested == preempt_offset);
++}
++
++void __might_sleep(const char *file, int line, int preempt_offset)
++{
++ unsigned int state = get_current_state();
++ /*
++ * Blocking primitives will set (and therefore destroy) current->state,
++ * since we will exit with TASK_RUNNING make sure we enter with it,
++ * otherwise we will destroy state.
++ */
++ WARN_ONCE(state != TASK_RUNNING && current->task_state_change,
++ "do not call blocking ops when !TASK_RUNNING; "
++ "state=%x set at [<%p>] %pS\n", state,
++ (void *)current->task_state_change,
++ (void *)current->task_state_change);
++
++ ___might_sleep(file, line, preempt_offset);
++}
++EXPORT_SYMBOL(__might_sleep);
++
++void ___might_sleep(const char *file, int line, int preempt_offset)
++{
++ /* Ratelimiting timestamp: */
++ static unsigned long prev_jiffy;
++
++ unsigned long preempt_disable_ip;
++
++ /* WARN_ON_ONCE() by default, no rate limit required: */
++ rcu_sleep_check();
++
++ if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
++ !is_idle_task(current) && !current->non_block_count) ||
++ system_state == SYSTEM_BOOTING || system_state > SYSTEM_RUNNING ||
++ oops_in_progress)
++ return;
++ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
++ return;
++ prev_jiffy = jiffies;
++
++ /* Save this before calling printk(), since that will clobber it: */
++ preempt_disable_ip = get_preempt_disable_ip(current);
++
++ printk(KERN_ERR
++ "BUG: sleeping function called from invalid context at %s:%d\n",
++ file, line);
++ printk(KERN_ERR
++ "in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n",
++ in_atomic(), irqs_disabled(), current->non_block_count,
++ current->pid, current->comm);
++
++ if (task_stack_end_corrupted(current))
++ printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
++
++ debug_show_held_locks(current);
++ if (irqs_disabled())
++ print_irqtrace_events(current);
++#ifdef CONFIG_DEBUG_PREEMPT
++ if (!preempt_count_equals(preempt_offset)) {
++ pr_err("Preemption disabled at:");
++ print_ip_sym(KERN_ERR, preempt_disable_ip);
++ }
++#endif
++ dump_stack();
++ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
++}
++EXPORT_SYMBOL(___might_sleep);
++
++void __cant_sleep(const char *file, int line, int preempt_offset)
++{
++ static unsigned long prev_jiffy;
++
++ if (irqs_disabled())
++ return;
++
++ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
++ return;
++
++ if (preempt_count() > preempt_offset)
++ return;
++
++ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
++ return;
++ prev_jiffy = jiffies;
++
++ printk(KERN_ERR "BUG: assuming atomic context at %s:%d\n", file, line);
++ printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n",
++ in_atomic(), irqs_disabled(),
++ current->pid, current->comm);
++
++ debug_show_held_locks(current);
++ dump_stack();
++ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
++}
++EXPORT_SYMBOL_GPL(__cant_sleep);
++
++#ifdef CONFIG_SMP
++void __cant_migrate(const char *file, int line)
++{
++ static unsigned long prev_jiffy;
++
++ if (irqs_disabled())
++ return;
++
++ if (is_migration_disabled(current))
++ return;
++
++ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
++ return;
++
++ if (preempt_count() > 0)
++ return;
++
++ if (current->migration_flags & MDF_FORCE_ENABLED)
++ return;
++
++ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
++ return;
++ prev_jiffy = jiffies;
++
++ pr_err("BUG: assuming non migratable context at %s:%d\n", file, line);
++ pr_err("in_atomic(): %d, irqs_disabled(): %d, migration_disabled() %u pid: %d, name: %s\n",
++ in_atomic(), irqs_disabled(), is_migration_disabled(current),
++ current->pid, current->comm);
++
++ debug_show_held_locks(current);
++ dump_stack();
++ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
++}
++EXPORT_SYMBOL_GPL(__cant_migrate);
++#endif
++#endif
++
++#ifdef CONFIG_MAGIC_SYSRQ
++void normalize_rt_tasks(void)
++{
++ struct task_struct *g, *p;
++ struct sched_attr attr = {
++ .sched_policy = SCHED_NORMAL,
++ };
++
++ read_lock(&tasklist_lock);
++ for_each_process_thread(g, p) {
++ /*
++ * Only normalize user tasks:
++ */
++ if (p->flags & PF_KTHREAD)
++ continue;
++
++ if (!rt_task(p)) {
++ /*
++ * Renice negative nice level userspace
++ * tasks back to 0:
++ */
++ if (task_nice(p) < 0)
++ set_user_nice(p, 0);
++ continue;
++ }
++
++ __sched_setscheduler(p, &attr, false, false);
++ }
++ read_unlock(&tasklist_lock);
++}
++#endif /* CONFIG_MAGIC_SYSRQ */
++
++#if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB)
++/*
++ * These functions are only useful for the IA64 MCA handling, or kdb.
++ *
++ * They can only be called when the whole system has been
++ * stopped - every CPU needs to be quiescent, and no scheduling
++ * activity can take place. Using them for anything else would
++ * be a serious bug, and as a result, they aren't even visible
++ * under any other configuration.
++ */
++
++/**
++ * curr_task - return the current task for a given CPU.
++ * @cpu: the processor in question.
++ *
++ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
++ *
++ * Return: The current task for @cpu.
++ */
++struct task_struct *curr_task(int cpu)
++{
++ return cpu_curr(cpu);
++}
++
++#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */
++
++#ifdef CONFIG_IA64
++/**
++ * ia64_set_curr_task - set the current task for a given CPU.
++ * @cpu: the processor in question.
++ * @p: the task pointer to set.
++ *
++ * Description: This function must only be used when non-maskable interrupts
++ * are serviced on a separate stack. It allows the architecture to switch the
++ * notion of the current task on a CPU in a non-blocking manner. This function
++ * must be called with all CPU's synchronised, and interrupts disabled, the
++ * and caller must save the original value of the current task (see
++ * curr_task() above) and restore that value before reenabling interrupts and
++ * re-starting the system.
++ *
++ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
++ */
++void ia64_set_curr_task(int cpu, struct task_struct *p)
++{
++ cpu_curr(cpu) = p;
++}
++
++#endif
++
++#ifdef CONFIG_CGROUP_SCHED
++static void sched_free_group(struct task_group *tg)
++{
++ kmem_cache_free(task_group_cache, tg);
++}
++
++/* allocate runqueue etc for a new task group */
++struct task_group *sched_create_group(struct task_group *parent)
++{
++ struct task_group *tg;
++
++ tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO);
++ if (!tg)
++ return ERR_PTR(-ENOMEM);
++
++ return tg;
++}
++
++void sched_online_group(struct task_group *tg, struct task_group *parent)
++{
++}
++
++/* rcu callback to free various structures associated with a task group */
++static void sched_free_group_rcu(struct rcu_head *rhp)
++{
++ /* Now it should be safe to free those cfs_rqs */
++ sched_free_group(container_of(rhp, struct task_group, rcu));
++}
++
++void sched_destroy_group(struct task_group *tg)
++{
++ /* Wait for possible concurrent references to cfs_rqs complete */
++ call_rcu(&tg->rcu, sched_free_group_rcu);
++}
++
++void sched_offline_group(struct task_group *tg)
++{
++}
++
++static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
++{
++ return css ? container_of(css, struct task_group, css) : NULL;
++}
++
++static struct cgroup_subsys_state *
++cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
++{
++ struct task_group *parent = css_tg(parent_css);
++ struct task_group *tg;
++
++ if (!parent) {
++ /* This is early initialization for the top cgroup */
++ return &root_task_group.css;
++ }
++
++ tg = sched_create_group(parent);
++ if (IS_ERR(tg))
++ return ERR_PTR(-ENOMEM);
++ return &tg->css;
++}
++
++/* Expose task group only after completing cgroup initialization */
++static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
++{
++ struct task_group *tg = css_tg(css);
++ struct task_group *parent = css_tg(css->parent);
++
++ if (parent)
++ sched_online_group(tg, parent);
++ return 0;
++}
++
++static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
++{
++ struct task_group *tg = css_tg(css);
++
++ sched_offline_group(tg);
++}
++
++static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
++{
++ struct task_group *tg = css_tg(css);
++
++ /*
++ * Relies on the RCU grace period between css_released() and this.
++ */
++ sched_free_group(tg);
++}
++
++static void cpu_cgroup_fork(struct task_struct *task)
++{
++}
++
++static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
++{
++ return 0;
++}
++
++static void cpu_cgroup_attach(struct cgroup_taskset *tset)
++{
++}
++
++#ifdef CONFIG_FAIR_GROUP_SCHED
++static DEFINE_MUTEX(shares_mutex);
++
++int sched_group_set_shares(struct task_group *tg, unsigned long shares)
++{
++ /*
++ * We can't change the weight of the root cgroup.
++ */
++ if (&root_task_group == tg)
++ return -EINVAL;
++
++ shares = clamp(shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES));
++
++ mutex_lock(&shares_mutex);
++ if (tg->shares == shares)
++ goto done;
++
++ tg->shares = shares;
++done:
++ mutex_unlock(&shares_mutex);
++ return 0;
++}
++
++static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
++ struct cftype *cftype, u64 shareval)
++{
++ if (shareval > scale_load_down(ULONG_MAX))
++ shareval = MAX_SHARES;
++ return sched_group_set_shares(css_tg(css), scale_load(shareval));
++}
++
++static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css,
++ struct cftype *cft)
++{
++ struct task_group *tg = css_tg(css);
++
++ return (u64) scale_load_down(tg->shares);
++}
++#endif
++
++static struct cftype cpu_legacy_files[] = {
++#ifdef CONFIG_FAIR_GROUP_SCHED
++ {
++ .name = "shares",
++ .read_u64 = cpu_shares_read_u64,
++ .write_u64 = cpu_shares_write_u64,
++ },
++#endif
++ { } /* Terminate */
++};
++
++
++static struct cftype cpu_files[] = {
++ { } /* terminate */
++};
++
++static int cpu_extra_stat_show(struct seq_file *sf,
++ struct cgroup_subsys_state *css)
++{
++ return 0;
++}
++
++struct cgroup_subsys cpu_cgrp_subsys = {
++ .css_alloc = cpu_cgroup_css_alloc,
++ .css_online = cpu_cgroup_css_online,
++ .css_released = cpu_cgroup_css_released,
++ .css_free = cpu_cgroup_css_free,
++ .css_extra_stat_show = cpu_extra_stat_show,
++ .fork = cpu_cgroup_fork,
++ .can_attach = cpu_cgroup_can_attach,
++ .attach = cpu_cgroup_attach,
++ .legacy_cftypes = cpu_files,
++ .legacy_cftypes = cpu_legacy_files,
++ .dfl_cftypes = cpu_files,
++ .early_init = true,
++ .threaded = true,
++};
++#endif /* CONFIG_CGROUP_SCHED */
++
++#undef CREATE_TRACE_POINTS
+diff -urN linux-5.15.3/kernel/sched/alt_debug.c linux-prjc-v5.15-prjc-r1/kernel/sched/alt_debug.c
+--- linux-5.15.3/kernel/sched/alt_debug.c 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/alt_debug.c 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,31 @@
++/*
++ * kernel/sched/alt_debug.c
++ *
++ * Print the alt scheduler debugging details
++ *
++ * Author: Alfred Chen
++ * Date : 2020
++ */
++#include "sched.h"
++
++/*
++ * This allows printing both to /proc/sched_debug and
++ * to the console
++ */
++#define SEQ_printf(m, x...) \
++ do { \
++ if (m) \
++ seq_printf(m, x); \
++ else \
++ pr_cont(x); \
++ } while (0)
++
++void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
++ struct seq_file *m)
++{
++ SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr_ns(p, ns),
++ get_nr_threads(p));
++}
++
++void proc_sched_set_task(struct task_struct *p)
++{}
+diff -urN linux-5.15.3/kernel/sched/alt_sched.h linux-prjc-v5.15-prjc-r1/kernel/sched/alt_sched.h
+--- linux-5.15.3/kernel/sched/alt_sched.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/alt_sched.h 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,666 @@
++#ifndef ALT_SCHED_H
++#define ALT_SCHED_H
++
++#include <linux/sched.h>
++
++#include <linux/sched/clock.h>
++#include <linux/sched/cpufreq.h>
++#include <linux/sched/cputime.h>
++#include <linux/sched/debug.h>
++#include <linux/sched/init.h>
++#include <linux/sched/isolation.h>
++#include <linux/sched/loadavg.h>
++#include <linux/sched/mm.h>
++#include <linux/sched/nohz.h>
++#include <linux/sched/signal.h>
++#include <linux/sched/stat.h>
++#include <linux/sched/sysctl.h>
++#include <linux/sched/task.h>
++#include <linux/sched/topology.h>
++#include <linux/sched/wake_q.h>
++
++#include <uapi/linux/sched/types.h>
++
++#include <linux/cgroup.h>
++#include <linux/cpufreq.h>
++#include <linux/cpuidle.h>
++#include <linux/cpuset.h>
++#include <linux/ctype.h>
++#include <linux/debugfs.h>
++#include <linux/kthread.h>
++#include <linux/livepatch.h>
++#include <linux/membarrier.h>
++#include <linux/proc_fs.h>
++#include <linux/psi.h>
++#include <linux/slab.h>
++#include <linux/stop_machine.h>
++#include <linux/suspend.h>
++#include <linux/swait.h>
++#include <linux/syscalls.h>
++#include <linux/tsacct_kern.h>
++
++#include <asm/tlb.h>
++
++#ifdef CONFIG_PARAVIRT
++# include <asm/paravirt.h>
++#endif
++
++#include "cpupri.h"
++
++#include <trace/events/sched.h>
++
++#ifdef CONFIG_SCHED_BMQ
++/* bits:
++ * RT(0-99), (Low prio adj range, nice width, high prio adj range) / 2, cpu idle task */
++#define SCHED_BITS (MAX_RT_PRIO + NICE_WIDTH / 2 + MAX_PRIORITY_ADJ + 1)
++#endif
++
++#ifdef CONFIG_SCHED_PDS
++/* bits: RT(0-99), reserved(100-127), NORMAL_PRIO_NUM, cpu idle task */
++#define SCHED_BITS (MIN_NORMAL_PRIO + NORMAL_PRIO_NUM + 1)
++#endif /* CONFIG_SCHED_PDS */
++
++#define IDLE_TASK_SCHED_PRIO (SCHED_BITS - 1)
++
++#ifdef CONFIG_SCHED_DEBUG
++# define SCHED_WARN_ON(x) WARN_ONCE(x, #x)
++extern void resched_latency_warn(int cpu, u64 latency);
++#else
++# define SCHED_WARN_ON(x) ({ (void)(x), 0; })
++static inline void resched_latency_warn(int cpu, u64 latency) {}
++#endif
++
++/*
++ * Increase resolution of nice-level calculations for 64-bit architectures.
++ * The extra resolution improves shares distribution and load balancing of
++ * low-weight task groups (eg. nice +19 on an autogroup), deeper taskgroup
++ * hierarchies, especially on larger systems. This is not a user-visible change
++ * and does not change the user-interface for setting shares/weights.
++ *
++ * We increase resolution only if we have enough bits to allow this increased
++ * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit
++ * are pretty high and the returns do not justify the increased costs.
++ *
++ * Really only required when CONFIG_FAIR_GROUP_SCHED=y is also set, but to
++ * increase coverage and consistency always enable it on 64-bit platforms.
++ */
++#ifdef CONFIG_64BIT
++# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT + SCHED_FIXEDPOINT_SHIFT)
++# define scale_load(w) ((w) << SCHED_FIXEDPOINT_SHIFT)
++# define scale_load_down(w) \
++({ \
++ unsigned long __w = (w); \
++ if (__w) \
++ __w = max(2UL, __w >> SCHED_FIXEDPOINT_SHIFT); \
++ __w; \
++})
++#else
++# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT)
++# define scale_load(w) (w)
++# define scale_load_down(w) (w)
++#endif
++
++#ifdef CONFIG_FAIR_GROUP_SCHED
++#define ROOT_TASK_GROUP_LOAD NICE_0_LOAD
++
++/*
++ * A weight of 0 or 1 can cause arithmetics problems.
++ * A weight of a cfs_rq is the sum of weights of which entities
++ * are queued on this cfs_rq, so a weight of a entity should not be
++ * too large, so as the shares value of a task group.
++ * (The default weight is 1024 - so there's no practical
++ * limitation from this.)
++ */
++#define MIN_SHARES (1UL << 1)
++#define MAX_SHARES (1UL << 18)
++#endif
++
++/* task_struct::on_rq states: */
++#define TASK_ON_RQ_QUEUED 1
++#define TASK_ON_RQ_MIGRATING 2
++
++static inline int task_on_rq_queued(struct task_struct *p)
++{
++ return p->on_rq == TASK_ON_RQ_QUEUED;
++}
++
++static inline int task_on_rq_migrating(struct task_struct *p)
++{
++ return READ_ONCE(p->on_rq) == TASK_ON_RQ_MIGRATING;
++}
++
++/*
++ * wake flags
++ */
++#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */
++#define WF_FORK 0x02 /* child wakeup after fork */
++#define WF_MIGRATED 0x04 /* internal use, task got migrated */
++#define WF_ON_CPU 0x08 /* Wakee is on_rq */
++
++#define SCHED_QUEUE_BITS (SCHED_BITS - 1)
++
++struct sched_queue {
++ DECLARE_BITMAP(bitmap, SCHED_QUEUE_BITS);
++ struct list_head heads[SCHED_BITS];
++};
++
++/*
++ * This is the main, per-CPU runqueue data structure.
++ * This data should only be modified by the local cpu.
++ */
++struct rq {
++ /* runqueue lock: */
++ raw_spinlock_t lock;
++
++ struct task_struct __rcu *curr;
++ struct task_struct *idle, *stop, *skip;
++ struct mm_struct *prev_mm;
++
++ struct sched_queue queue;
++#ifdef CONFIG_SCHED_PDS
++ u64 time_edge;
++#endif
++ unsigned long watermark;
++
++ /* switch count */
++ u64 nr_switches;
++
++ atomic_t nr_iowait;
++
++#ifdef CONFIG_SCHED_DEBUG
++ u64 last_seen_need_resched_ns;
++ int ticks_without_resched;
++#endif
++
++#ifdef CONFIG_MEMBARRIER
++ int membarrier_state;
++#endif
++
++#ifdef CONFIG_SMP
++ int cpu; /* cpu of this runqueue */
++ bool online;
++
++ unsigned int ttwu_pending;
++ unsigned char nohz_idle_balance;
++ unsigned char idle_balance;
++
++#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
++ struct sched_avg avg_irq;
++#endif
++
++#ifdef CONFIG_SCHED_SMT
++ int active_balance;
++ struct cpu_stop_work active_balance_work;
++#endif
++ struct callback_head *balance_callback;
++#ifdef CONFIG_HOTPLUG_CPU
++ struct rcuwait hotplug_wait;
++#endif
++ unsigned int nr_pinned;
++
++#endif /* CONFIG_SMP */
++#ifdef CONFIG_IRQ_TIME_ACCOUNTING
++ u64 prev_irq_time;
++#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
++#ifdef CONFIG_PARAVIRT
++ u64 prev_steal_time;
++#endif /* CONFIG_PARAVIRT */
++#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
++ u64 prev_steal_time_rq;
++#endif /* CONFIG_PARAVIRT_TIME_ACCOUNTING */
++
++ /* For genenal cpu load util */
++ s32 load_history;
++ u64 load_block;
++ u64 load_stamp;
++
++ /* calc_load related fields */
++ unsigned long calc_load_update;
++ long calc_load_active;
++
++ u64 clock, last_tick;
++ u64 last_ts_switch;
++ u64 clock_task;
++
++ unsigned int nr_running;
++ unsigned long nr_uninterruptible;
++
++#ifdef CONFIG_SCHED_HRTICK
++#ifdef CONFIG_SMP
++ call_single_data_t hrtick_csd;
++#endif
++ struct hrtimer hrtick_timer;
++ ktime_t hrtick_time;
++#endif
++
++#ifdef CONFIG_SCHEDSTATS
++
++ /* latency stats */
++ struct sched_info rq_sched_info;
++ unsigned long long rq_cpu_time;
++ /* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */
++
++ /* sys_sched_yield() stats */
++ unsigned int yld_count;
++
++ /* schedule() stats */
++ unsigned int sched_switch;
++ unsigned int sched_count;
++ unsigned int sched_goidle;
++
++ /* try_to_wake_up() stats */
++ unsigned int ttwu_count;
++ unsigned int ttwu_local;
++#endif /* CONFIG_SCHEDSTATS */
++
++#ifdef CONFIG_CPU_IDLE
++ /* Must be inspected within a rcu lock section */
++ struct cpuidle_state *idle_state;
++#endif
++
++#ifdef CONFIG_NO_HZ_COMMON
++#ifdef CONFIG_SMP
++ call_single_data_t nohz_csd;
++#endif
++ atomic_t nohz_flags;
++#endif /* CONFIG_NO_HZ_COMMON */
++};
++
++extern unsigned long rq_load_util(struct rq *rq, unsigned long max);
++
++extern unsigned long calc_load_update;
++extern atomic_long_t calc_load_tasks;
++
++extern void calc_global_load_tick(struct rq *this_rq);
++extern long calc_load_fold_active(struct rq *this_rq, long adjust);
++
++DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
++#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
++#define this_rq() this_cpu_ptr(&runqueues)
++#define task_rq(p) cpu_rq(task_cpu(p))
++#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
++#define raw_rq() raw_cpu_ptr(&runqueues)
++
++#ifdef CONFIG_SMP
++#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL)
++void register_sched_domain_sysctl(void);
++void unregister_sched_domain_sysctl(void);
++#else
++static inline void register_sched_domain_sysctl(void)
++{
++}
++static inline void unregister_sched_domain_sysctl(void)
++{
++}
++#endif
++
++extern bool sched_smp_initialized;
++
++enum {
++ ITSELF_LEVEL_SPACE_HOLDER,
++#ifdef CONFIG_SCHED_SMT
++ SMT_LEVEL_SPACE_HOLDER,
++#endif
++ COREGROUP_LEVEL_SPACE_HOLDER,
++ CORE_LEVEL_SPACE_HOLDER,
++ OTHER_LEVEL_SPACE_HOLDER,
++ NR_CPU_AFFINITY_LEVELS
++};
++
++DECLARE_PER_CPU(cpumask_t [NR_CPU_AFFINITY_LEVELS], sched_cpu_topo_masks);
++DECLARE_PER_CPU(cpumask_t *, sched_cpu_llc_mask);
++
++static inline int
++__best_mask_cpu(const cpumask_t *cpumask, const cpumask_t *mask)
++{
++ int cpu;
++
++ while ((cpu = cpumask_any_and(cpumask, mask)) >= nr_cpu_ids)
++ mask++;
++
++ return cpu;
++}
++
++static inline int best_mask_cpu(int cpu, const cpumask_t *mask)
++{
++ return __best_mask_cpu(mask, per_cpu(sched_cpu_topo_masks, cpu));
++}
++
++extern void flush_smp_call_function_from_idle(void);
++
++#else /* !CONFIG_SMP */
++static inline void flush_smp_call_function_from_idle(void) { }
++#endif
++
++#ifndef arch_scale_freq_tick
++static __always_inline
++void arch_scale_freq_tick(void)
++{
++}
++#endif
++
++#ifndef arch_scale_freq_capacity
++static __always_inline
++unsigned long arch_scale_freq_capacity(int cpu)
++{
++ return SCHED_CAPACITY_SCALE;
++}
++#endif
++
++static inline u64 __rq_clock_broken(struct rq *rq)
++{
++ return READ_ONCE(rq->clock);
++}
++
++static inline u64 rq_clock(struct rq *rq)
++{
++ /*
++ * Relax lockdep_assert_held() checking as in VRQ, call to
++ * sched_info_xxxx() may not held rq->lock
++ * lockdep_assert_held(&rq->lock);
++ */
++ return rq->clock;
++}
++
++static inline u64 rq_clock_task(struct rq *rq)
++{
++ /*
++ * Relax lockdep_assert_held() checking as in VRQ, call to
++ * sched_info_xxxx() may not held rq->lock
++ * lockdep_assert_held(&rq->lock);
++ */
++ return rq->clock_task;
++}
++
++/*
++ * {de,en}queue flags:
++ *
++ * DEQUEUE_SLEEP - task is no longer runnable
++ * ENQUEUE_WAKEUP - task just became runnable
++ *
++ */
++
++#define DEQUEUE_SLEEP 0x01
++
++#define ENQUEUE_WAKEUP 0x01
++
++
++/*
++ * Below are scheduler API which using in other kernel code
++ * It use the dummy rq_flags
++ * ToDo : BMQ need to support these APIs for compatibility with mainline
++ * scheduler code.
++ */
++struct rq_flags {
++ unsigned long flags;
++};
++
++struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf)
++ __acquires(rq->lock);
++
++struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
++ __acquires(p->pi_lock)
++ __acquires(rq->lock);
++
++static inline void __task_rq_unlock(struct rq *rq, struct rq_flags *rf)
++ __releases(rq->lock)
++{
++ raw_spin_unlock(&rq->lock);
++}
++
++static inline void
++task_rq_unlock(struct rq *rq, struct task_struct *p, struct rq_flags *rf)
++ __releases(rq->lock)
++ __releases(p->pi_lock)
++{
++ raw_spin_unlock(&rq->lock);
++ raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
++}
++
++static inline void
++rq_lock(struct rq *rq, struct rq_flags *rf)
++ __acquires(rq->lock)
++{
++ raw_spin_lock(&rq->lock);
++}
++
++static inline void
++rq_unlock_irq(struct rq *rq, struct rq_flags *rf)
++ __releases(rq->lock)
++{
++ raw_spin_unlock_irq(&rq->lock);
++}
++
++static inline void
++rq_unlock(struct rq *rq, struct rq_flags *rf)
++ __releases(rq->lock)
++{
++ raw_spin_unlock(&rq->lock);
++}
++
++static inline struct rq *
++this_rq_lock_irq(struct rq_flags *rf)
++ __acquires(rq->lock)
++{
++ struct rq *rq;
++
++ local_irq_disable();
++ rq = this_rq();
++ raw_spin_lock(&rq->lock);
++
++ return rq;
++}
++
++extern void raw_spin_rq_lock_nested(struct rq *rq, int subclass);
++extern void raw_spin_rq_unlock(struct rq *rq);
++
++static inline raw_spinlock_t *__rq_lockp(struct rq *rq)
++{
++ return &rq->lock;
++}
++
++static inline raw_spinlock_t *rq_lockp(struct rq *rq)
++{
++ return __rq_lockp(rq);
++}
++
++static inline void raw_spin_rq_lock(struct rq *rq)
++{
++ raw_spin_rq_lock_nested(rq, 0);
++}
++
++static inline void raw_spin_rq_lock_irq(struct rq *rq)
++{
++ local_irq_disable();
++ raw_spin_rq_lock(rq);
++}
++
++static inline void raw_spin_rq_unlock_irq(struct rq *rq)
++{
++ raw_spin_rq_unlock(rq);
++ local_irq_enable();
++}
++
++static inline int task_current(struct rq *rq, struct task_struct *p)
++{
++ return rq->curr == p;
++}
++
++static inline bool task_running(struct task_struct *p)
++{
++ return p->on_cpu;
++}
++
++extern int task_running_nice(struct task_struct *p);
++
++extern struct static_key_false sched_schedstats;
++
++#ifdef CONFIG_CPU_IDLE
++static inline void idle_set_state(struct rq *rq,
++ struct cpuidle_state *idle_state)
++{
++ rq->idle_state = idle_state;
++}
++
++static inline struct cpuidle_state *idle_get_state(struct rq *rq)
++{
++ WARN_ON(!rcu_read_lock_held());
++ return rq->idle_state;
++}
++#else
++static inline void idle_set_state(struct rq *rq,
++ struct cpuidle_state *idle_state)
++{
++}
++
++static inline struct cpuidle_state *idle_get_state(struct rq *rq)
++{
++ return NULL;
++}
++#endif
++
++static inline int cpu_of(const struct rq *rq)
++{
++#ifdef CONFIG_SMP
++ return rq->cpu;
++#else
++ return 0;
++#endif
++}
++
++#include "stats.h"
++
++#ifdef CONFIG_NO_HZ_COMMON
++#define NOHZ_BALANCE_KICK_BIT 0
++#define NOHZ_STATS_KICK_BIT 1
++
++#define NOHZ_BALANCE_KICK BIT(NOHZ_BALANCE_KICK_BIT)
++#define NOHZ_STATS_KICK BIT(NOHZ_STATS_KICK_BIT)
++
++#define NOHZ_KICK_MASK (NOHZ_BALANCE_KICK | NOHZ_STATS_KICK)
++
++#define nohz_flags(cpu) (&cpu_rq(cpu)->nohz_flags)
++
++/* TODO: needed?
++extern void nohz_balance_exit_idle(struct rq *rq);
++#else
++static inline void nohz_balance_exit_idle(struct rq *rq) { }
++*/
++#endif
++
++#ifdef CONFIG_IRQ_TIME_ACCOUNTING
++struct irqtime {
++ u64 total;
++ u64 tick_delta;
++ u64 irq_start_time;
++ struct u64_stats_sync sync;
++};
++
++DECLARE_PER_CPU(struct irqtime, cpu_irqtime);
++
++/*
++ * Returns the irqtime minus the softirq time computed by ksoftirqd.
++ * Otherwise ksoftirqd's sum_exec_runtime is substracted its own runtime
++ * and never move forward.
++ */
++static inline u64 irq_time_read(int cpu)
++{
++ struct irqtime *irqtime = &per_cpu(cpu_irqtime, cpu);
++ unsigned int seq;
++ u64 total;
++
++ do {
++ seq = __u64_stats_fetch_begin(&irqtime->sync);
++ total = irqtime->total;
++ } while (__u64_stats_fetch_retry(&irqtime->sync, seq));
++
++ return total;
++}
++#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
++
++#ifdef CONFIG_CPU_FREQ
++DECLARE_PER_CPU(struct update_util_data __rcu *, cpufreq_update_util_data);
++#endif /* CONFIG_CPU_FREQ */
++
++#ifdef CONFIG_NO_HZ_FULL
++extern int __init sched_tick_offload_init(void);
++#else
++static inline int sched_tick_offload_init(void) { return 0; }
++#endif
++
++#ifdef arch_scale_freq_capacity
++#ifndef arch_scale_freq_invariant
++#define arch_scale_freq_invariant() (true)
++#endif
++#else /* arch_scale_freq_capacity */
++#define arch_scale_freq_invariant() (false)
++#endif
++
++extern void schedule_idle(void);
++
++#define cap_scale(v, s) ((v)*(s) >> SCHED_CAPACITY_SHIFT)
++
++/*
++ * !! For sched_setattr_nocheck() (kernel) only !!
++ *
++ * This is actually gross. :(
++ *
++ * It is used to make schedutil kworker(s) higher priority than SCHED_DEADLINE
++ * tasks, but still be able to sleep. We need this on platforms that cannot
++ * atomically change clock frequency. Remove once fast switching will be
++ * available on such platforms.
++ *
++ * SUGOV stands for SchedUtil GOVernor.
++ */
++#define SCHED_FLAG_SUGOV 0x10000000
++
++#ifdef CONFIG_MEMBARRIER
++/*
++ * The scheduler provides memory barriers required by membarrier between:
++ * - prior user-space memory accesses and store to rq->membarrier_state,
++ * - store to rq->membarrier_state and following user-space memory accesses.
++ * In the same way it provides those guarantees around store to rq->curr.
++ */
++static inline void membarrier_switch_mm(struct rq *rq,
++ struct mm_struct *prev_mm,
++ struct mm_struct *next_mm)
++{
++ int membarrier_state;
++
++ if (prev_mm == next_mm)
++ return;
++
++ membarrier_state = atomic_read(&next_mm->membarrier_state);
++ if (READ_ONCE(rq->membarrier_state) == membarrier_state)
++ return;
++
++ WRITE_ONCE(rq->membarrier_state, membarrier_state);
++}
++#else
++static inline void membarrier_switch_mm(struct rq *rq,
++ struct mm_struct *prev_mm,
++ struct mm_struct *next_mm)
++{
++}
++#endif
++
++#ifdef CONFIG_NUMA
++extern int sched_numa_find_closest(const struct cpumask *cpus, int cpu);
++#else
++static inline int sched_numa_find_closest(const struct cpumask *cpus, int cpu)
++{
++ return nr_cpu_ids;
++}
++#endif
++
++extern void swake_up_all_locked(struct swait_queue_head *q);
++extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
++
++#ifdef CONFIG_PREEMPT_DYNAMIC
++extern int preempt_dynamic_mode;
++extern int sched_dynamic_mode(const char *str);
++extern void sched_dynamic_update(int mode);
++#endif
++
++static inline void nohz_run_idle_balance(int cpu) { }
++#endif /* ALT_SCHED_H */
+diff -urN linux-5.15.3/kernel/sched/bmq.h linux-prjc-v5.15-prjc-r1/kernel/sched/bmq.h
+--- linux-5.15.3/kernel/sched/bmq.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/bmq.h 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,111 @@
++#define ALT_SCHED_VERSION_MSG "sched/bmq: BMQ CPU Scheduler "ALT_SCHED_VERSION" by Alfred Chen.\n"
++
++/*
++ * BMQ only routines
++ */
++#define rq_switch_time(rq) ((rq)->clock - (rq)->last_ts_switch)
++#define boost_threshold(p) (sched_timeslice_ns >>\
++ (15 - MAX_PRIORITY_ADJ - (p)->boost_prio))
++
++static inline void boost_task(struct task_struct *p)
++{
++ int limit;
++
++ switch (p->policy) {
++ case SCHED_NORMAL:
++ limit = -MAX_PRIORITY_ADJ;
++ break;
++ case SCHED_BATCH:
++ case SCHED_IDLE:
++ limit = 0;
++ break;
++ default:
++ return;
++ }
++
++ if (p->boost_prio > limit)
++ p->boost_prio--;
++}
++
++static inline void deboost_task(struct task_struct *p)
++{
++ if (p->boost_prio < MAX_PRIORITY_ADJ)
++ p->boost_prio++;
++}
++
++/*
++ * Common interfaces
++ */
++static inline void sched_timeslice_imp(const int timeslice_ms) {}
++
++static inline int
++task_sched_prio_normal(const struct task_struct *p, const struct rq *rq)
++{
++ return p->prio + p->boost_prio - MAX_RT_PRIO;
++}
++
++static inline int task_sched_prio(const struct task_struct *p)
++{
++ return (p->prio < MAX_RT_PRIO)? p->prio : MAX_RT_PRIO / 2 + (p->prio + p->boost_prio) / 2;
++}
++
++static inline int
++task_sched_prio_idx(const struct task_struct *p, const struct rq *rq)
++{
++ return task_sched_prio(p);
++}
++
++static inline int sched_prio2idx(int prio, struct rq *rq)
++{
++ return prio;
++}
++
++static inline int sched_idx2prio(int idx, struct rq *rq)
++{
++ return idx;
++}
++
++static inline void time_slice_expired(struct task_struct *p, struct rq *rq)
++{
++ p->time_slice = sched_timeslice_ns;
++
++ if (SCHED_FIFO != p->policy && task_on_rq_queued(p)) {
++ if (SCHED_RR != p->policy)
++ deboost_task(p);
++ requeue_task(p, rq);
++ }
++}
++
++static inline void sched_task_sanity_check(struct task_struct *p, struct rq *rq) {}
++
++inline int task_running_nice(struct task_struct *p)
++{
++ return (p->prio + p->boost_prio > DEFAULT_PRIO + MAX_PRIORITY_ADJ);
++}
++
++static void sched_task_fork(struct task_struct *p, struct rq *rq)
++{
++ p->boost_prio = (p->boost_prio < 0) ?
++ p->boost_prio + MAX_PRIORITY_ADJ : MAX_PRIORITY_ADJ;
++}
++
++static inline void do_sched_yield_type_1(struct task_struct *p, struct rq *rq)
++{
++ p->boost_prio = MAX_PRIORITY_ADJ;
++}
++
++#ifdef CONFIG_SMP
++static inline void sched_task_ttwu(struct task_struct *p)
++{
++ if(this_rq()->clock_task - p->last_ran > sched_timeslice_ns)
++ boost_task(p);
++}
++#endif
++
++static inline void sched_task_deactivate(struct task_struct *p, struct rq *rq)
++{
++ if (rq_switch_time(rq) < boost_threshold(p))
++ boost_task(p);
++}
++
++static inline void update_rq_time_edge(struct rq *rq) {}
+diff -urN linux-5.15.3/kernel/sched/cpufreq_schedutil.c linux-prjc-v5.15-prjc-r1/kernel/sched/cpufreq_schedutil.c
+--- linux-5.15.3/kernel/sched/cpufreq_schedutil.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/cpufreq_schedutil.c 2021-11-20 02:15:12.000000000 +1100
+@@ -167,9 +167,14 @@
+ unsigned long max = arch_scale_cpu_capacity(sg_cpu->cpu);
+
+ sg_cpu->max = max;
++#ifndef CONFIG_SCHED_ALT
+ sg_cpu->bw_dl = cpu_bw_dl(rq);
+ sg_cpu->util = effective_cpu_util(sg_cpu->cpu, cpu_util_cfs(rq), max,
+ FREQUENCY_UTIL, NULL);
++#else
++ sg_cpu->bw_dl = 0;
++ sg_cpu->util = rq_load_util(rq, max);
++#endif /* CONFIG_SCHED_ALT */
+ }
+
+ /**
+@@ -312,8 +317,10 @@
+ */
+ static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu)
+ {
++#ifndef CONFIG_SCHED_ALT
+ if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl)
+ sg_cpu->sg_policy->limits_changed = true;
++#endif
+ }
+
+ static inline bool sugov_update_single_common(struct sugov_cpu *sg_cpu,
+@@ -607,6 +614,7 @@
+ }
+
+ ret = sched_setattr_nocheck(thread, &attr);
++
+ if (ret) {
+ kthread_stop(thread);
+ pr_warn("%s: failed to set SCHED_DEADLINE\n", __func__);
+@@ -839,7 +847,9 @@
+ #ifdef CONFIG_ENERGY_MODEL
+ static void rebuild_sd_workfn(struct work_struct *work)
+ {
++#ifndef CONFIG_SCHED_ALT
+ rebuild_sched_domains_energy();
++#endif /* CONFIG_SCHED_ALT */
+ }
+ static DECLARE_WORK(rebuild_sd_work, rebuild_sd_workfn);
+
+diff -urN linux-5.15.3/kernel/sched/cputime.c linux-prjc-v5.15-prjc-r1/kernel/sched/cputime.c
+--- linux-5.15.3/kernel/sched/cputime.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/cputime.c 2021-11-20 02:15:12.000000000 +1100
+@@ -123,7 +123,7 @@
+ p->utime += cputime;
+ account_group_user_time(p, cputime);
+
+- index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
++ index = task_running_nice(p) ? CPUTIME_NICE : CPUTIME_USER;
+
+ /* Add user time to cpustat. */
+ task_group_account_field(p, index, cputime);
+@@ -147,7 +147,7 @@
+ p->gtime += cputime;
+
+ /* Add guest time to cpustat. */
+- if (task_nice(p) > 0) {
++ if (task_running_nice(p)) {
+ cpustat[CPUTIME_NICE] += cputime;
+ cpustat[CPUTIME_GUEST_NICE] += cputime;
+ } else {
+@@ -270,7 +270,7 @@
+ #ifdef CONFIG_64BIT
+ static inline u64 read_sum_exec_runtime(struct task_struct *t)
+ {
+- return t->se.sum_exec_runtime;
++ return tsk_seruntime(t);
+ }
+ #else
+ static u64 read_sum_exec_runtime(struct task_struct *t)
+@@ -280,7 +280,7 @@
+ struct rq *rq;
+
+ rq = task_rq_lock(t, &rf);
+- ns = t->se.sum_exec_runtime;
++ ns = tsk_seruntime(t);
+ task_rq_unlock(rq, t, &rf);
+
+ return ns;
+@@ -612,7 +612,7 @@
+ void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
+ {
+ struct task_cputime cputime = {
+- .sum_exec_runtime = p->se.sum_exec_runtime,
++ .sum_exec_runtime = tsk_seruntime(p),
+ };
+
+ task_cputime(p, &cputime.utime, &cputime.stime);
+diff -urN linux-5.15.3/kernel/sched/debug.c linux-prjc-v5.15-prjc-r1/kernel/sched/debug.c
+--- linux-5.15.3/kernel/sched/debug.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/debug.c 2021-11-20 02:15:12.000000000 +1100
+@@ -8,6 +8,7 @@
+ */
+ #include "sched.h"
+
++#ifndef CONFIG_SCHED_ALT
+ /*
+ * This allows printing both to /proc/sched_debug and
+ * to the console
+@@ -216,6 +217,7 @@
+ };
+
+ #endif /* SMP */
++#endif /* !CONFIG_SCHED_ALT */
+
+ #ifdef CONFIG_PREEMPT_DYNAMIC
+
+@@ -279,6 +281,7 @@
+
+ #endif /* CONFIG_PREEMPT_DYNAMIC */
+
++#ifndef CONFIG_SCHED_ALT
+ __read_mostly bool sched_debug_verbose;
+
+ static const struct seq_operations sched_debug_sops;
+@@ -294,6 +297,7 @@
+ .llseek = seq_lseek,
+ .release = seq_release,
+ };
++#endif /* !CONFIG_SCHED_ALT */
+
+ static struct dentry *debugfs_sched;
+
+@@ -303,12 +307,15 @@
+
+ debugfs_sched = debugfs_create_dir("sched", NULL);
+
++#ifndef CONFIG_SCHED_ALT
+ debugfs_create_file("features", 0644, debugfs_sched, NULL, &sched_feat_fops);
+ debugfs_create_bool("verbose", 0644, debugfs_sched, &sched_debug_verbose);
++#endif /* !CONFIG_SCHED_ALT */
+ #ifdef CONFIG_PREEMPT_DYNAMIC
+ debugfs_create_file("preempt", 0644, debugfs_sched, NULL, &sched_dynamic_fops);
+ #endif
+
++#ifndef CONFIG_SCHED_ALT
+ debugfs_create_u32("latency_ns", 0644, debugfs_sched, &sysctl_sched_latency);
+ debugfs_create_u32("min_granularity_ns", 0644, debugfs_sched, &sysctl_sched_min_granularity);
+ debugfs_create_u32("wakeup_granularity_ns", 0644, debugfs_sched, &sysctl_sched_wakeup_granularity);
+@@ -336,11 +343,13 @@
+ #endif
+
+ debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops);
++#endif /* !CONFIG_SCHED_ALT */
+
+ return 0;
+ }
+ late_initcall(sched_init_debug);
+
++#ifndef CONFIG_SCHED_ALT
+ #ifdef CONFIG_SMP
+
+ static cpumask_var_t sd_sysctl_cpus;
+@@ -1063,6 +1072,7 @@
+ memset(&p->se.statistics, 0, sizeof(p->se.statistics));
+ #endif
+ }
++#endif /* !CONFIG_SCHED_ALT */
+
+ void resched_latency_warn(int cpu, u64 latency)
+ {
+diff -urN linux-5.15.3/kernel/sched/idle.c linux-prjc-v5.15-prjc-r1/kernel/sched/idle.c
+--- linux-5.15.3/kernel/sched/idle.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/idle.c 2021-11-20 02:15:12.000000000 +1100
+@@ -403,6 +403,7 @@
+ do_idle();
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ /*
+ * idle-task scheduling class.
+ */
+@@ -525,3 +526,4 @@
+ .switched_to = switched_to_idle,
+ .update_curr = update_curr_idle,
+ };
++#endif
+diff -urN linux-5.15.3/kernel/sched/pds.h linux-prjc-v5.15-prjc-r1/kernel/sched/pds.h
+--- linux-5.15.3/kernel/sched/pds.h 1970-01-01 10:00:00.000000000 +1000
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/pds.h 2021-11-20 02:15:12.000000000 +1100
+@@ -0,0 +1,127 @@
++#define ALT_SCHED_VERSION_MSG "sched/pds: PDS CPU Scheduler "ALT_SCHED_VERSION" by Alfred Chen.\n"
++
++static int sched_timeslice_shift = 22;
++
++#define NORMAL_PRIO_MOD(x) ((x) & (NORMAL_PRIO_NUM - 1))
++
++/*
++ * Common interfaces
++ */
++static inline void sched_timeslice_imp(const int timeslice_ms)
++{
++ if (2 == timeslice_ms)
++ sched_timeslice_shift = 21;
++}
++
++static inline int
++task_sched_prio_normal(const struct task_struct *p, const struct rq *rq)
++{
++ s64 delta = p->deadline - rq->time_edge + NORMAL_PRIO_NUM - NICE_WIDTH;
++
++ if (WARN_ONCE(delta > NORMAL_PRIO_NUM - 1,
++ "pds: task_sched_prio_normal() delta %lld\n", delta))
++ return NORMAL_PRIO_NUM - 1;
++
++ return (delta < 0) ? 0 : delta;
++}
++
++static inline int task_sched_prio(const struct task_struct *p)
++{
++ return (p->prio < MAX_RT_PRIO) ? p->prio :
++ MIN_NORMAL_PRIO + task_sched_prio_normal(p, task_rq(p));
++}
++
++static inline int
++task_sched_prio_idx(const struct task_struct *p, const struct rq *rq)
++{
++ return (p->prio < MAX_RT_PRIO) ? p->prio : MIN_NORMAL_PRIO +
++ NORMAL_PRIO_MOD(task_sched_prio_normal(p, rq) + rq->time_edge);
++}
++
++static inline int sched_prio2idx(int prio, struct rq *rq)
++{
++ return (IDLE_TASK_SCHED_PRIO == prio || prio < MAX_RT_PRIO) ? prio :
++ MIN_NORMAL_PRIO + NORMAL_PRIO_MOD((prio - MIN_NORMAL_PRIO) +
++ rq->time_edge);
++}
++
++static inline int sched_idx2prio(int idx, struct rq *rq)
++{
++ return (idx < MAX_RT_PRIO) ? idx : MIN_NORMAL_PRIO +
++ NORMAL_PRIO_MOD((idx - MIN_NORMAL_PRIO) + NORMAL_PRIO_NUM -
++ NORMAL_PRIO_MOD(rq->time_edge));
++}
++
++static inline void sched_renew_deadline(struct task_struct *p, const struct rq *rq)
++{
++ if (p->prio >= MAX_RT_PRIO)
++ p->deadline = (rq->clock >> sched_timeslice_shift) +
++ p->static_prio - (MAX_PRIO - NICE_WIDTH);
++}
++
++int task_running_nice(struct task_struct *p)
++{
++ return (p->prio > DEFAULT_PRIO);
++}
++
++static inline void update_rq_time_edge(struct rq *rq)
++{
++ struct list_head head;
++ u64 old = rq->time_edge;
++ u64 now = rq->clock >> sched_timeslice_shift;
++ u64 prio, delta;
++
++ if (now == old)
++ return;
++
++ delta = min_t(u64, NORMAL_PRIO_NUM, now - old);
++ INIT_LIST_HEAD(&head);
++
++ for_each_set_bit(prio, &rq->queue.bitmap[2], delta)
++ list_splice_tail_init(rq->queue.heads + MIN_NORMAL_PRIO +
++ NORMAL_PRIO_MOD(prio + old), &head);
++
++ rq->queue.bitmap[2] = (NORMAL_PRIO_NUM == delta) ? 0UL :
++ rq->queue.bitmap[2] >> delta;
++ rq->time_edge = now;
++ if (!list_empty(&head)) {
++ u64 idx = MIN_NORMAL_PRIO + NORMAL_PRIO_MOD(now);
++ struct task_struct *p;
++
++ list_for_each_entry(p, &head, sq_node)
++ p->sq_idx = idx;
++
++ list_splice(&head, rq->queue.heads + idx);
++ rq->queue.bitmap[2] |= 1UL;
++ }
++}
++
++static inline void time_slice_expired(struct task_struct *p, struct rq *rq)
++{
++ p->time_slice = sched_timeslice_ns;
++ sched_renew_deadline(p, rq);
++ if (SCHED_FIFO != p->policy && task_on_rq_queued(p))
++ requeue_task(p, rq);
++}
++
++static inline void sched_task_sanity_check(struct task_struct *p, struct rq *rq)
++{
++ u64 max_dl = rq->time_edge + NICE_WIDTH - 1;
++ if (unlikely(p->deadline > max_dl))
++ p->deadline = max_dl;
++}
++
++static void sched_task_fork(struct task_struct *p, struct rq *rq)
++{
++ sched_renew_deadline(p, rq);
++}
++
++static inline void do_sched_yield_type_1(struct task_struct *p, struct rq *rq)
++{
++ time_slice_expired(p, rq);
++}
++
++#ifdef CONFIG_SMP
++static inline void sched_task_ttwu(struct task_struct *p) {}
++#endif
++static inline void sched_task_deactivate(struct task_struct *p, struct rq *rq) {}
+diff -urN linux-5.15.3/kernel/sched/pelt.c linux-prjc-v5.15-prjc-r1/kernel/sched/pelt.c
+--- linux-5.15.3/kernel/sched/pelt.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/pelt.c 2021-11-20 02:15:12.000000000 +1100
+@@ -270,6 +270,7 @@
+ WRITE_ONCE(sa->util_avg, sa->util_sum / divider);
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ /*
+ * sched_entity:
+ *
+@@ -387,8 +388,9 @@
+
+ return 0;
+ }
++#endif
+
+-#ifdef CONFIG_SCHED_THERMAL_PRESSURE
++#if defined(CONFIG_SCHED_THERMAL_PRESSURE) && !defined(CONFIG_SCHED_ALT)
+ /*
+ * thermal:
+ *
+diff -urN linux-5.15.3/kernel/sched/pelt.h linux-prjc-v5.15-prjc-r1/kernel/sched/pelt.h
+--- linux-5.15.3/kernel/sched/pelt.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/pelt.h 2021-11-20 02:15:12.000000000 +1100
+@@ -1,13 +1,15 @@
+ #ifdef CONFIG_SMP
+ #include "sched-pelt.h"
+
++#ifndef CONFIG_SCHED_ALT
+ int __update_load_avg_blocked_se(u64 now, struct sched_entity *se);
+ int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se);
+ int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq);
+ int update_rt_rq_load_avg(u64 now, struct rq *rq, int running);
+ int update_dl_rq_load_avg(u64 now, struct rq *rq, int running);
++#endif
+
+-#ifdef CONFIG_SCHED_THERMAL_PRESSURE
++#if defined(CONFIG_SCHED_THERMAL_PRESSURE) && !defined(CONFIG_SCHED_ALT)
+ int update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity);
+
+ static inline u64 thermal_load_avg(struct rq *rq)
+@@ -42,6 +44,7 @@
+ return LOAD_AVG_MAX - 1024 + avg->period_contrib;
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ static inline void cfs_se_util_change(struct sched_avg *avg)
+ {
+ unsigned int enqueued;
+@@ -153,9 +156,11 @@
+ return rq_clock_pelt(rq_of(cfs_rq));
+ }
+ #endif
++#endif /* CONFIG_SCHED_ALT */
+
+ #else
+
++#ifndef CONFIG_SCHED_ALT
+ static inline int
+ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
+ {
+@@ -173,6 +178,7 @@
+ {
+ return 0;
+ }
++#endif
+
+ static inline int
+ update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity)
+diff -urN linux-5.15.3/kernel/sched/sched.h linux-prjc-v5.15-prjc-r1/kernel/sched/sched.h
+--- linux-5.15.3/kernel/sched/sched.h 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/sched.h 2021-11-20 02:15:12.000000000 +1100
+@@ -2,6 +2,10 @@
+ /*
+ * Scheduler internal types and methods:
+ */
++#ifdef CONFIG_SCHED_ALT
++#include "alt_sched.h"
++#else
++
+ #include <linux/sched.h>
+
+ #include <linux/sched/autogroup.h>
+@@ -3064,3 +3068,8 @@
+ extern void sched_dynamic_update(int mode);
+ #endif
+
++static inline int task_running_nice(struct task_struct *p)
++{
++ return (task_nice(p) > 0);
++}
++#endif /* !CONFIG_SCHED_ALT */
+diff -urN linux-5.15.3/kernel/sched/stats.c linux-prjc-v5.15-prjc-r1/kernel/sched/stats.c
+--- linux-5.15.3/kernel/sched/stats.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/stats.c 2021-11-20 02:15:12.000000000 +1100
+@@ -22,9 +22,11 @@
+ } else {
+ struct rq *rq;
+ #ifdef CONFIG_SMP
++#ifndef CONFIG_SCHED_ALT
+ struct sched_domain *sd;
+ int dcount = 0;
+ #endif
++#endif
+ cpu = (unsigned long)(v - 2);
+ rq = cpu_rq(cpu);
+
+@@ -40,6 +42,7 @@
+ seq_printf(seq, "\n");
+
+ #ifdef CONFIG_SMP
++#ifndef CONFIG_SCHED_ALT
+ /* domain-specific stats */
+ rcu_read_lock();
+ for_each_domain(cpu, sd) {
+@@ -69,6 +72,7 @@
+ }
+ rcu_read_unlock();
+ #endif
++#endif
+ }
+ return 0;
+ }
+diff -urN linux-5.15.3/kernel/sched/topology.c linux-prjc-v5.15-prjc-r1/kernel/sched/topology.c
+--- linux-5.15.3/kernel/sched/topology.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sched/topology.c 2021-11-20 02:15:12.000000000 +1100
+@@ -4,6 +4,7 @@
+ */
+ #include "sched.h"
+
++#ifndef CONFIG_SCHED_ALT
+ DEFINE_MUTEX(sched_domains_mutex);
+
+ /* Protected by sched_domains_mutex: */
+@@ -1382,8 +1383,10 @@
+ */
+
+ static int default_relax_domain_level = -1;
++#endif /* CONFIG_SCHED_ALT */
+ int sched_domain_level_max;
+
++#ifndef CONFIG_SCHED_ALT
+ static int __init setup_relax_domain_level(char *str)
+ {
+ if (kstrtoint(str, 0, &default_relax_domain_level))
+@@ -1619,6 +1622,7 @@
+
+ return sd;
+ }
++#endif /* CONFIG_SCHED_ALT */
+
+ /*
+ * Topology list, bottom-up.
+@@ -1648,6 +1652,7 @@
+ sched_domain_topology = tl;
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ #ifdef CONFIG_NUMA
+
+ static const struct cpumask *sd_numa_mask(int cpu)
+@@ -2516,3 +2521,17 @@
+ partition_sched_domains_locked(ndoms_new, doms_new, dattr_new);
+ mutex_unlock(&sched_domains_mutex);
+ }
++#else /* CONFIG_SCHED_ALT */
++void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
++ struct sched_domain_attr *dattr_new)
++{}
++
++#ifdef CONFIG_NUMA
++int __read_mostly node_reclaim_distance = RECLAIM_DISTANCE;
++
++int sched_numa_find_closest(const struct cpumask *cpus, int cpu)
++{
++ return best_mask_cpu(cpu, cpus);
++}
++#endif /* CONFIG_NUMA */
++#endif
+diff -urN linux-5.15.3/kernel/sysctl.c linux-prjc-v5.15-prjc-r1/kernel/sysctl.c
+--- linux-5.15.3/kernel/sysctl.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/sysctl.c 2021-11-20 02:15:12.000000000 +1100
+@@ -122,6 +122,10 @@
+ static int one_hundred = 100;
+ static int two_hundred = 200;
+ static int one_thousand = 1000;
++#ifdef CONFIG_SCHED_ALT
++static int __maybe_unused zero = 0;
++extern int sched_yield_type;
++#endif
+ #ifdef CONFIG_PRINTK
+ static int ten_thousand = 10000;
+ #endif
+@@ -1771,6 +1775,24 @@
+ }
+
+ static struct ctl_table kern_table[] = {
++#ifdef CONFIG_SCHED_ALT
++/* In ALT, only supported "sched_schedstats" */
++#ifdef CONFIG_SCHED_DEBUG
++#ifdef CONFIG_SMP
++#ifdef CONFIG_SCHEDSTATS
++ {
++ .procname = "sched_schedstats",
++ .data = NULL,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = sysctl_schedstats,
++ .extra1 = SYSCTL_ZERO,
++ .extra2 = SYSCTL_ONE,
++ },
++#endif /* CONFIG_SCHEDSTATS */
++#endif /* CONFIG_SMP */
++#endif /* CONFIG_SCHED_DEBUG */
++#else /* !CONFIG_SCHED_ALT */
+ {
+ .procname = "sched_child_runs_first",
+ .data = &sysctl_sched_child_runs_first,
+@@ -1901,6 +1923,7 @@
+ .extra2 = SYSCTL_ONE,
+ },
+ #endif
++#endif /* !CONFIG_SCHED_ALT */
+ #ifdef CONFIG_PROVE_LOCKING
+ {
+ .procname = "prove_locking",
+@@ -2477,6 +2500,17 @@
+ .proc_handler = proc_dointvec,
+ },
+ #endif
++#ifdef CONFIG_SCHED_ALT
++ {
++ .procname = "yield_type",
++ .data = &sched_yield_type,
++ .maxlen = sizeof (int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_minmax,
++ .extra1 = &zero,
++ .extra2 = &two,
++ },
++#endif
+ #if defined(CONFIG_S390) && defined(CONFIG_SMP)
+ {
+ .procname = "spin_retry",
+diff -urN linux-5.15.3/kernel/time/hrtimer.c linux-prjc-v5.15-prjc-r1/kernel/time/hrtimer.c
+--- linux-5.15.3/kernel/time/hrtimer.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/time/hrtimer.c 2021-11-20 02:15:12.000000000 +1100
+@@ -2088,8 +2088,10 @@
+ int ret = 0;
+ u64 slack;
+
++#ifndef CONFIG_SCHED_ALT
+ slack = current->timer_slack_ns;
+ if (dl_task(current) || rt_task(current))
++#endif
+ slack = 0;
+
+ hrtimer_init_sleeper_on_stack(&t, clockid, mode);
+diff -urN linux-5.15.3/kernel/time/posix-cpu-timers.c linux-prjc-v5.15-prjc-r1/kernel/time/posix-cpu-timers.c
+--- linux-5.15.3/kernel/time/posix-cpu-timers.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/time/posix-cpu-timers.c 2021-11-20 02:15:12.000000000 +1100
+@@ -216,7 +216,7 @@
+ u64 stime, utime;
+
+ task_cputime(p, &utime, &stime);
+- store_samples(samples, stime, utime, p->se.sum_exec_runtime);
++ store_samples(samples, stime, utime, tsk_seruntime(p));
+ }
+
+ static void proc_sample_cputime_atomic(struct task_cputime_atomic *at,
+@@ -859,6 +859,7 @@
+ }
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ static inline void check_dl_overrun(struct task_struct *tsk)
+ {
+ if (tsk->dl.dl_overrun) {
+@@ -866,6 +867,7 @@
+ __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
+ }
+ }
++#endif
+
+ static bool check_rlimit(u64 time, u64 limit, int signo, bool rt, bool hard)
+ {
+@@ -893,8 +895,10 @@
+ u64 samples[CPUCLOCK_MAX];
+ unsigned long soft;
+
++#ifndef CONFIG_SCHED_ALT
+ if (dl_task(tsk))
+ check_dl_overrun(tsk);
++#endif
+
+ if (expiry_cache_is_inactive(pct))
+ return;
+@@ -908,7 +912,7 @@
+ soft = task_rlimit(tsk, RLIMIT_RTTIME);
+ if (soft != RLIM_INFINITY) {
+ /* Task RT timeout is accounted in jiffies. RTTIME is usec */
+- unsigned long rttime = tsk->rt.timeout * (USEC_PER_SEC / HZ);
++ unsigned long rttime = tsk_rttimeout(tsk) * (USEC_PER_SEC / HZ);
+ unsigned long hard = task_rlimit_max(tsk, RLIMIT_RTTIME);
+
+ /* At the hard limit, send SIGKILL. No further action. */
+@@ -1144,8 +1148,10 @@
+ return true;
+ }
+
++#ifndef CONFIG_SCHED_ALT
+ if (dl_task(tsk) && tsk->dl.dl_overrun)
+ return true;
++#endif
+
+ return false;
+ }
+diff -urN linux-5.15.3/kernel/trace/trace_selftest.c linux-prjc-v5.15-prjc-r1/kernel/trace/trace_selftest.c
+--- linux-5.15.3/kernel/trace/trace_selftest.c 2021-11-19 05:17:21.000000000 +1100
++++ linux-prjc-v5.15-prjc-r1/kernel/trace/trace_selftest.c 2021-11-20 02:15:12.000000000 +1100
+@@ -1052,10 +1052,15 @@
+ {
+ /* Make this a -deadline thread */
+ static const struct sched_attr attr = {
++#ifdef CONFIG_SCHED_ALT
++ /* No deadline on BMQ/PDS, use RR */
++ .sched_policy = SCHED_RR,
++#else
+ .sched_policy = SCHED_DEADLINE,
+ .sched_runtime = 100000ULL,
+ .sched_deadline = 10000000ULL,
+ .sched_period = 10000000ULL
++#endif
+ };
+ struct wakeup_test_data *x = data;
+
diff --git a/system/easy-kernel/0255-ultra-ksm.patch b/system/easy-kernel/0255-ultra-ksm.patch
new file mode 100644
index 000000000..8011e2266
--- /dev/null
+++ b/system/easy-kernel/0255-ultra-ksm.patch
@@ -0,0 +1,6970 @@
+From 4f10e65a3f482d3d2e07eab75a8c8610f59b8112 Mon Sep 17 00:00:00 2001
+From: Piotr Gorski <lucjan.lucjanov@gmail.com>
+Date: Mon, 1 Nov 2021 12:32:31 +0100
+Subject: [PATCH] UKSM for 5.15
+
+Signed-off-by: Piotr Gorski <lucjan.lucjanov@gmail.com>
+---
+ Documentation/vm/uksm.txt | 61 +
+ fs/exec.c | 1 +
+ fs/proc/meminfo.c | 4 +
+ include/linux/ksm.h | 43 +-
+ include/linux/mm_types.h | 3 +
+ include/linux/mmzone.h | 3 +
+ include/linux/pgtable.h | 17 +-
+ include/linux/sradix-tree.h | 77 +
+ include/linux/uksm.h | 149 +
+ kernel/fork.c | 2 +-
+ lib/Makefile | 2 +-
+ lib/sradix-tree.c | 476 +++
+ mm/Kconfig | 26 +
+ mm/Makefile | 3 +-
+ mm/ksm.c | 11 -
+ mm/memory.c | 33 +-
+ mm/mmap.c | 36 +
+ mm/uksm.c | 5614 +++++++++++++++++++++++++++++++++++
+ mm/vmstat.c | 3 +
+ 19 files changed, 6538 insertions(+), 26 deletions(-)
+ create mode 100644 Documentation/vm/uksm.txt
+ create mode 100644 include/linux/sradix-tree.h
+ create mode 100644 include/linux/uksm.h
+ create mode 100644 lib/sradix-tree.c
+ create mode 100644 mm/uksm.c
+
+diff --git a/Documentation/vm/uksm.txt b/Documentation/vm/uksm.txt
+new file mode 100644
+index 000000000..be19a3127
+--- /dev/null
++++ b/Documentation/vm/uksm.txt
+@@ -0,0 +1,61 @@
++The Ultra Kernel Samepage Merging feature
++----------------------------------------------
++/*
++ * Ultra KSM. Copyright (C) 2011-2012 Nai Xia
++ *
++ * This is an improvement upon KSM. Some basic data structures and routines
++ * are borrowed from ksm.c .
++ *
++ * Its new features:
++ * 1. Full system scan:
++ * It automatically scans all user processes' anonymous VMAs. Kernel-user
++ * interaction to submit a memory area to KSM is no longer needed.
++ *
++ * 2. Rich area detection:
++ * It automatically detects rich areas containing abundant duplicated
++ * pages based. Rich areas are given a full scan speed. Poor areas are
++ * sampled at a reasonable speed with very low CPU consumption.
++ *
++ * 3. Ultra Per-page scan speed improvement:
++ * A new hash algorithm is proposed. As a result, on a machine with
++ * Core(TM)2 Quad Q9300 CPU in 32-bit mode and 800MHZ DDR2 main memory, it
++ * can scan memory areas that does not contain duplicated pages at speed of
++ * 627MB/sec ~ 2445MB/sec and can merge duplicated areas at speed of
++ * 477MB/sec ~ 923MB/sec.
++ *
++ * 4. Thrashing area avoidance:
++ * Thrashing area(an VMA that has frequent Ksm page break-out) can be
++ * filtered out. My benchmark shows it's more efficient than KSM's per-page
++ * hash value based volatile page detection.
++ *
++ *
++ * 5. Misc changes upon KSM:
++ * * It has a fully x86-opitmized memcmp dedicated for 4-byte-aligned page
++ * comparison. It's much faster than default C version on x86.
++ * * rmap_item now has an struct *page member to loosely cache a
++ * address-->page mapping, which reduces too much time-costly
++ * follow_page().
++ * * The VMA creation/exit procedures are hooked to let the Ultra KSM know.
++ * * try_to_merge_two_pages() now can revert a pte if it fails. No break_
++ * ksm is needed for this case.
++ *
++ * 6. Full Zero Page consideration(contributed by Figo Zhang)
++ * Now uksmd consider full zero pages as special pages and merge them to an
++ * special unswappable uksm zero page.
++ */
++
++ChangeLog:
++
++2012-05-05 The creation of this Doc
++2012-05-08 UKSM 0.1.1.1 libc crash bug fix, api clean up, doc clean up.
++2012-05-28 UKSM 0.1.1.2 bug fix release
++2012-06-26 UKSM 0.1.2-beta1 first beta release for 0.1.2
++2012-07-2 UKSM 0.1.2-beta2
++2012-07-10 UKSM 0.1.2-beta3
++2012-07-26 UKSM 0.1.2 Fine grained speed control, more scan optimization.
++2012-10-13 UKSM 0.1.2.1 Bug fixes.
++2012-12-31 UKSM 0.1.2.2 Minor bug fixes.
++2014-07-02 UKSM 0.1.2.3 Fix a " __this_cpu_read() in preemptible bug".
++2015-04-22 UKSM 0.1.2.4 Fix a race condition that can sometimes trigger anonying warnings.
++2016-09-10 UKSM 0.1.2.5 Fix a bug in dedup ratio calculation.
++2017-02-26 UKSM 0.1.2.6 Fix a bug in hugetlbpage handling and a race bug with page migration.
+diff --git a/fs/exec.c b/fs/exec.c
+index a098c133d..da9985b3e 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -65,6 +65,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/io_uring.h>
+ #include <linux/syscall_user_dispatch.h>
++#include <linux/ksm.h>
+
+ #include <linux/uaccess.h>
+ #include <asm/mmu_context.h>
+diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
+index 6fa761c9c..45fd59a0d 100644
+--- a/fs/proc/meminfo.c
++++ b/fs/proc/meminfo.c
+@@ -108,6 +108,10 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
+ #endif
+ show_val_kb(m, "PageTables: ",
+ global_node_page_state(NR_PAGETABLE));
++#ifdef CONFIG_UKSM
++ show_val_kb(m, "KsmZeroPages: ",
++ global_zone_page_state(NR_UKSM_ZERO_PAGES));
++#endif
+
+ show_val_kb(m, "NFS_Unstable: ", 0);
+ show_val_kb(m, "Bounce: ",
+diff --git a/include/linux/ksm.h b/include/linux/ksm.h
+index 161e8164a..f0dbdf3c9 100644
+--- a/include/linux/ksm.h
++++ b/include/linux/ksm.h
+@@ -21,20 +21,16 @@ struct mem_cgroup;
+ #ifdef CONFIG_KSM
+ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, int advice, unsigned long *vm_flags);
+-int __ksm_enter(struct mm_struct *mm);
+-void __ksm_exit(struct mm_struct *mm);
+
+-static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
++static inline struct stable_node *page_stable_node(struct page *page)
+ {
+- if (test_bit(MMF_VM_MERGEABLE, &oldmm->flags))
+- return __ksm_enter(mm);
+- return 0;
++ return PageKsm(page) ? page_rmapping(page) : NULL;
+ }
+
+-static inline void ksm_exit(struct mm_struct *mm)
++static inline void set_page_stable_node(struct page *page,
++ struct stable_node *stable_node)
+ {
+- if (test_bit(MMF_VM_MERGEABLE, &mm->flags))
+- __ksm_exit(mm);
++ page->mapping = (void *)((unsigned long)stable_node | PAGE_MAPPING_KSM);
+ }
+
+ /*
+@@ -54,6 +50,33 @@ struct page *ksm_might_need_to_copy(struct page *page,
+ void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc);
+ void ksm_migrate_page(struct page *newpage, struct page *oldpage);
+
++#ifdef CONFIG_KSM_LEGACY
++int __ksm_enter(struct mm_struct *mm);
++void __ksm_exit(struct mm_struct *mm);
++static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
++{
++ if (test_bit(MMF_VM_MERGEABLE, &oldmm->flags))
++ return __ksm_enter(mm);
++ return 0;
++}
++
++static inline void ksm_exit(struct mm_struct *mm)
++{
++ if (test_bit(MMF_VM_MERGEABLE, &mm->flags))
++ __ksm_exit(mm);
++}
++
++#elif defined(CONFIG_UKSM)
++static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
++{
++ return 0;
++}
++
++static inline void ksm_exit(struct mm_struct *mm)
++{
++}
++#endif /* !CONFIG_UKSM */
++
+ #else /* !CONFIG_KSM */
+
+ static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
+@@ -89,4 +112,6 @@ static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage)
+ #endif /* CONFIG_MMU */
+ #endif /* !CONFIG_KSM */
+
++#include <linux/uksm.h>
++
+ #endif /* __LINUX_KSM_H */
+diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
+index 7f8ee09c7..da86d7fc0 100644
+--- a/include/linux/mm_types.h
++++ b/include/linux/mm_types.h
+@@ -385,6 +385,9 @@ struct vm_area_struct {
+ struct mempolicy *vm_policy; /* NUMA policy for the VMA */
+ #endif
+ struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
++#ifdef CONFIG_UKSM
++ struct vma_slot *uksm_vma_slot;
++#endif
+ } __randomize_layout;
+
+ struct core_thread {
+diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
+index 6a1d79d84..4af26d848 100644
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -158,6 +158,9 @@ enum zone_stat_item {
+ NR_ZSPAGES, /* allocated in zsmalloc */
+ #endif
+ NR_FREE_CMA_PAGES,
++#ifdef CONFIG_UKSM
++ NR_UKSM_ZERO_PAGES,
++#endif
+ NR_VM_ZONE_STAT_ITEMS };
+
+ enum node_stat_item {
+diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
+index e24d2c992..8e9d8af58 100644
+--- a/include/linux/pgtable.h
++++ b/include/linux/pgtable.h
+@@ -1137,13 +1137,26 @@ extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
+ extern void untrack_pfn_moved(struct vm_area_struct *vma);
+ #endif
+
++#ifdef CONFIG_UKSM
++static inline int is_uksm_zero_pfn(unsigned long pfn)
++{
++ extern unsigned long uksm_zero_pfn;
++ return pfn == uksm_zero_pfn;
++}
++#else
++static inline int is_uksm_zero_pfn(unsigned long pfn)
++{
++ return 0;
++}
++#endif
++
+ #ifdef CONFIG_MMU
+ #ifdef __HAVE_COLOR_ZERO_PAGE
+ static inline int is_zero_pfn(unsigned long pfn)
+ {
+ extern unsigned long zero_pfn;
+ unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+- return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
++ return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT) || is_uksm_zero_pfn(pfn);
+ }
+
+ #define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
+@@ -1152,7 +1165,7 @@ static inline int is_zero_pfn(unsigned long pfn)
+ static inline int is_zero_pfn(unsigned long pfn)
+ {
+ extern unsigned long zero_pfn;
+- return pfn == zero_pfn;
++ return (pfn == zero_pfn) || (is_uksm_zero_pfn(pfn));
+ }
+
+ static inline unsigned long my_zero_pfn(unsigned long addr)
+diff --git a/include/linux/sradix-tree.h b/include/linux/sradix-tree.h
+new file mode 100644
+index 000000000..d71edba6b
+--- /dev/null
++++ b/include/linux/sradix-tree.h
+@@ -0,0 +1,77 @@
++#ifndef _LINUX_SRADIX_TREE_H
++#define _LINUX_SRADIX_TREE_H
++
++
++#define INIT_SRADIX_TREE(root, mask) \
++do { \
++ (root)->height = 0; \
++ (root)->gfp_mask = (mask); \
++ (root)->rnode = NULL; \
++} while (0)
++
++#define ULONG_BITS (sizeof(unsigned long) * 8)
++#define SRADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
++//#define SRADIX_TREE_MAP_SHIFT 6
++//#define SRADIX_TREE_MAP_SIZE (1UL << SRADIX_TREE_MAP_SHIFT)
++//#define SRADIX_TREE_MAP_MASK (SRADIX_TREE_MAP_SIZE-1)
++
++struct sradix_tree_node {
++ unsigned int height; /* Height from the bottom */
++ unsigned int count;
++ unsigned int fulls; /* Number of full sublevel trees */
++ struct sradix_tree_node *parent;
++ void *stores[0];
++};
++
++/* A simple radix tree implementation */
++struct sradix_tree_root {
++ unsigned int height;
++ struct sradix_tree_node *rnode;
++
++ /* Where found to have available empty stores in its sublevels */
++ struct sradix_tree_node *enter_node;
++ unsigned int shift;
++ unsigned int stores_size;
++ unsigned int mask;
++ unsigned long min; /* The first hole index */
++ unsigned long num;
++ //unsigned long *height_to_maxindex;
++
++ /* How the node is allocated and freed. */
++ struct sradix_tree_node *(*alloc)(void);
++ void (*free)(struct sradix_tree_node *node);
++
++ /* When a new node is added and removed */
++ void (*extend)(struct sradix_tree_node *parent, struct sradix_tree_node *child);
++ void (*assign)(struct sradix_tree_node *node, unsigned int index, void *item);
++ void (*rm)(struct sradix_tree_node *node, unsigned int offset);
++};
++
++struct sradix_tree_path {
++ struct sradix_tree_node *node;
++ int offset;
++};
++
++static inline
++void init_sradix_tree_root(struct sradix_tree_root *root, unsigned long shift)
++{
++ root->height = 0;
++ root->rnode = NULL;
++ root->shift = shift;
++ root->stores_size = 1UL << shift;
++ root->mask = root->stores_size - 1;
++}
++
++
++extern void *sradix_tree_next(struct sradix_tree_root *root,
++ struct sradix_tree_node *node, unsigned long index,
++ int (*iter)(void *, unsigned long));
++
++extern int sradix_tree_enter(struct sradix_tree_root *root, void **item, int num);
++
++extern void sradix_tree_delete_from_leaf(struct sradix_tree_root *root,
++ struct sradix_tree_node *node, unsigned long index);
++
++extern void *sradix_tree_lookup(struct sradix_tree_root *root, unsigned long index);
++
++#endif /* _LINUX_SRADIX_TREE_H */
+diff --git a/include/linux/uksm.h b/include/linux/uksm.h
+new file mode 100644
+index 000000000..bb8651f53
+--- /dev/null
++++ b/include/linux/uksm.h
+@@ -0,0 +1,149 @@
++#ifndef __LINUX_UKSM_H
++#define __LINUX_UKSM_H
++/*
++ * Memory merging support.
++ *
++ * This code enables dynamic sharing of identical pages found in different
++ * memory areas, even if they are not shared by fork().
++ */
++
++/* if !CONFIG_UKSM this file should not be compiled at all. */
++#ifdef CONFIG_UKSM
++
++#include <linux/bitops.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/rmap.h>
++#include <linux/sched.h>
++
++extern unsigned long zero_pfn __read_mostly;
++extern unsigned long uksm_zero_pfn __read_mostly;
++extern struct page *empty_uksm_zero_page;
++
++/* must be done before linked to mm */
++extern void uksm_vma_add_new(struct vm_area_struct *vma);
++extern void uksm_remove_vma(struct vm_area_struct *vma);
++
++#define UKSM_SLOT_NEED_SORT (1 << 0)
++#define UKSM_SLOT_NEED_RERAND (1 << 1)
++#define UKSM_SLOT_SCANNED (1 << 2) /* It's scanned in this round */
++#define UKSM_SLOT_FUL_SCANNED (1 << 3)
++#define UKSM_SLOT_IN_UKSM (1 << 4)
++
++struct vma_slot {
++ struct sradix_tree_node *snode;
++ unsigned long sindex;
++
++ struct list_head slot_list;
++ unsigned long fully_scanned_round;
++ unsigned long dedup_num;
++ unsigned long pages_scanned;
++ unsigned long this_sampled;
++ unsigned long last_scanned;
++ unsigned long pages_to_scan;
++ struct scan_rung *rung;
++ struct page **rmap_list_pool;
++ unsigned int *pool_counts;
++ unsigned long pool_size;
++ struct vm_area_struct *vma;
++ struct mm_struct *mm;
++ unsigned long ctime_j;
++ unsigned long pages;
++ unsigned long flags;
++ unsigned long pages_cowed; /* pages cowed this round */
++ unsigned long pages_merged; /* pages merged this round */
++ unsigned long pages_bemerged;
++
++ /* when it has page merged in this eval round */
++ struct list_head dedup_list;
++};
++
++static inline void uksm_unmap_zero_page(pte_t pte)
++{
++ if (pte_pfn(pte) == uksm_zero_pfn)
++ __dec_zone_page_state(empty_uksm_zero_page, NR_UKSM_ZERO_PAGES);
++}
++
++static inline void uksm_map_zero_page(pte_t pte)
++{
++ if (pte_pfn(pte) == uksm_zero_pfn)
++ __inc_zone_page_state(empty_uksm_zero_page, NR_UKSM_ZERO_PAGES);
++}
++
++static inline void uksm_cow_page(struct vm_area_struct *vma, struct page *page)
++{
++ if (vma->uksm_vma_slot && PageKsm(page))
++ vma->uksm_vma_slot->pages_cowed++;
++}
++
++static inline void uksm_cow_pte(struct vm_area_struct *vma, pte_t pte)
++{
++ if (vma->uksm_vma_slot && pte_pfn(pte) == uksm_zero_pfn)
++ vma->uksm_vma_slot->pages_cowed++;
++}
++
++static inline int uksm_flags_can_scan(unsigned long vm_flags)
++{
++#ifdef VM_SAO
++ if (vm_flags & VM_SAO)
++ return 0;
++#endif
++
++ return !(vm_flags & (VM_PFNMAP | VM_IO | VM_DONTEXPAND |
++ VM_HUGETLB | VM_MIXEDMAP | VM_SHARED
++ | VM_MAYSHARE | VM_GROWSUP | VM_GROWSDOWN));
++}
++
++static inline void uksm_vm_flags_mod(unsigned long *vm_flags_p)
++{
++ if (uksm_flags_can_scan(*vm_flags_p))
++ *vm_flags_p |= VM_MERGEABLE;
++}
++
++/*
++ * Just a wrapper for BUG_ON for where ksm_zeropage must not be. TODO: it will
++ * be removed when uksm zero page patch is stable enough.
++ */
++static inline void uksm_bugon_zeropage(pte_t pte)
++{
++ BUG_ON(pte_pfn(pte) == uksm_zero_pfn);
++}
++#else
++static inline void uksm_vma_add_new(struct vm_area_struct *vma)
++{
++}
++
++static inline void uksm_remove_vma(struct vm_area_struct *vma)
++{
++}
++
++static inline void uksm_unmap_zero_page(pte_t pte)
++{
++}
++
++static inline void uksm_map_zero_page(pte_t pte)
++{
++}
++
++static inline void uksm_cow_page(struct vm_area_struct *vma, struct page *page)
++{
++}
++
++static inline void uksm_cow_pte(struct vm_area_struct *vma, pte_t pte)
++{
++}
++
++static inline int uksm_flags_can_scan(unsigned long vm_flags)
++{
++ return 0;
++}
++
++static inline void uksm_vm_flags_mod(unsigned long *vm_flags_p)
++{
++}
++
++static inline void uksm_bugon_zeropage(pte_t pte)
++{
++}
++#endif /* !CONFIG_UKSM */
++#endif /* __LINUX_UKSM_H */
+diff --git a/kernel/fork.c b/kernel/fork.c
+index 38681ad44..af32e377d 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -604,7 +604,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
+ __vma_link_rb(mm, tmp, rb_link, rb_parent);
+ rb_link = &tmp->vm_rb.rb_right;
+ rb_parent = &tmp->vm_rb;
+-
++ uksm_vma_add_new(tmp);
+ mm->map_count++;
+ if (!(tmp->vm_flags & VM_WIPEONFORK))
+ retval = copy_page_range(tmp, mpnt);
+diff --git a/lib/Makefile b/lib/Makefile
+index a841be524..446bb9818 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -28,7 +28,7 @@ CFLAGS_string.o += -fno-stack-protector
+ endif
+
+ lib-y := ctype.o string.o vsprintf.o cmdline.o \
+- rbtree.o radix-tree.o timerqueue.o xarray.o \
++ rbtree.o radix-tree.o sradix-tree.o timerqueue.o xarray.o \
+ idr.o extable.o sha1.o irq_regs.o argv_split.o \
+ flex_proportions.o ratelimit.o show_mem.o \
+ is_single_threaded.o plist.o decompress.o kobject_uevent.o \
+diff --git a/lib/sradix-tree.c b/lib/sradix-tree.c
+new file mode 100644
+index 000000000..ab21e6309
+--- /dev/null
++++ b/lib/sradix-tree.c
+@@ -0,0 +1,476 @@
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/gcd.h>
++#include <linux/sradix-tree.h>
++
++static inline int sradix_node_full(struct sradix_tree_root *root, struct sradix_tree_node *node)
++{
++ return node->fulls == root->stores_size ||
++ (node->height == 1 && node->count == root->stores_size);
++}
++
++/*
++ * Extend a sradix tree so it can store key @index.
++ */
++static int sradix_tree_extend(struct sradix_tree_root *root, unsigned long index)
++{
++ struct sradix_tree_node *node;
++ unsigned int height;
++
++ if (unlikely(root->rnode == NULL)) {
++ if (!(node = root->alloc()))
++ return -ENOMEM;
++
++ node->height = 1;
++ root->rnode = node;
++ root->height = 1;
++ }
++
++ /* Figure out what the height should be. */
++ height = root->height;
++ index >>= root->shift * height;
++
++ while (index) {
++ index >>= root->shift;
++ height++;
++ }
++
++ while (height > root->height) {
++ unsigned int newheight;
++
++ if (!(node = root->alloc()))
++ return -ENOMEM;
++
++ /* Increase the height. */
++ node->stores[0] = root->rnode;
++ root->rnode->parent = node;
++ if (root->extend)
++ root->extend(node, root->rnode);
++
++ newheight = root->height + 1;
++ node->height = newheight;
++ node->count = 1;
++ if (sradix_node_full(root, root->rnode))
++ node->fulls = 1;
++
++ root->rnode = node;
++ root->height = newheight;
++ }
++
++ return 0;
++}
++
++/*
++ * Search the next item from the current node, that is not NULL
++ * and can satify root->iter().
++ */
++void *sradix_tree_next(struct sradix_tree_root *root,
++ struct sradix_tree_node *node, unsigned long index,
++ int (*iter)(void *item, unsigned long height))
++{
++ unsigned long offset;
++ void *item;
++
++ if (unlikely(node == NULL)) {
++ node = root->rnode;
++ for (offset = 0; offset < root->stores_size; offset++) {
++ item = node->stores[offset];
++ if (item && (!iter || iter(item, node->height)))
++ break;
++ }
++
++ if (unlikely(offset >= root->stores_size))
++ return NULL;
++
++ if (node->height == 1)
++ return item;
++ else
++ goto go_down;
++ }
++
++ while (node) {
++ offset = (index & root->mask) + 1;
++ for (; offset < root->stores_size; offset++) {
++ item = node->stores[offset];
++ if (item && (!iter || iter(item, node->height)))
++ break;
++ }
++
++ if (offset < root->stores_size)
++ break;
++
++ node = node->parent;
++ index >>= root->shift;
++ }
++
++ if (!node)
++ return NULL;
++
++ while (node->height > 1) {
++go_down:
++ node = item;
++ for (offset = 0; offset < root->stores_size; offset++) {
++ item = node->stores[offset];
++ if (item && (!iter || iter(item, node->height)))
++ break;
++ }
++
++ if (unlikely(offset >= root->stores_size))
++ return NULL;
++ }
++
++ BUG_ON(offset > root->stores_size);
++
++ return item;
++}
++
++/*
++ * Blindly insert the item to the tree. Typically, we reuse the
++ * first empty store item.
++ */
++int sradix_tree_enter(struct sradix_tree_root *root, void **item, int num)
++{
++ unsigned long index;
++ unsigned int height;
++ struct sradix_tree_node *node, *tmp = NULL;
++ int offset, offset_saved;
++ void **store = NULL;
++ int error, i, j, shift;
++
++go_on:
++ index = root->min;
++
++ if (root->enter_node && !sradix_node_full(root, root->enter_node)) {
++ node = root->enter_node;
++ BUG_ON((index >> (root->shift * root->height)));
++ } else {
++ node = root->rnode;
++ if (node == NULL || (index >> (root->shift * root->height))
++ || sradix_node_full(root, node)) {
++ error = sradix_tree_extend(root, index);
++ if (error)
++ return error;
++
++ node = root->rnode;
++ }
++ }
++
++
++ height = node->height;
++ shift = (height - 1) * root->shift;
++ offset = (index >> shift) & root->mask;
++ while (shift > 0) {
++ offset_saved = offset;
++ for (; offset < root->stores_size; offset++) {
++ store = &node->stores[offset];
++ tmp = *store;
++
++ if (!tmp || !sradix_node_full(root, tmp))
++ break;
++ }
++ BUG_ON(offset >= root->stores_size);
++
++ if (offset != offset_saved) {
++ index += (offset - offset_saved) << shift;
++ index &= ~((1UL << shift) - 1);
++ }
++
++ if (!tmp) {
++ if (!(tmp = root->alloc()))
++ return -ENOMEM;
++
++ tmp->height = shift / root->shift;
++ *store = tmp;
++ tmp->parent = node;
++ node->count++;
++// if (root->extend)
++// root->extend(node, tmp);
++ }
++
++ node = tmp;
++ shift -= root->shift;
++ offset = (index >> shift) & root->mask;
++ }
++
++ BUG_ON(node->height != 1);
++
++
++ store = &node->stores[offset];
++ for (i = 0, j = 0;
++ j < root->stores_size - node->count &&
++ i < root->stores_size - offset && j < num; i++) {
++ if (!store[i]) {
++ store[i] = item[j];
++ if (root->assign)
++ root->assign(node, index + i, item[j]);
++ j++;
++ }
++ }
++
++ node->count += j;
++ root->num += j;
++ num -= j;
++
++ while (sradix_node_full(root, node)) {
++ node = node->parent;
++ if (!node)
++ break;
++
++ node->fulls++;
++ }
++
++ if (unlikely(!node)) {
++ /* All nodes are full */
++ root->min = 1 << (root->height * root->shift);
++ root->enter_node = NULL;
++ } else {
++ root->min = index + i - 1;
++ root->min |= (1UL << (node->height - 1)) - 1;
++ root->min++;
++ root->enter_node = node;
++ }
++
++ if (num) {
++ item += j;
++ goto go_on;
++ }
++
++ return 0;
++}
++
++
++/**
++ * sradix_tree_shrink - shrink height of a sradix tree to minimal
++ * @root sradix tree root
++ *
++ */
++static inline void sradix_tree_shrink(struct sradix_tree_root *root)
++{
++ /* try to shrink tree height */
++ while (root->height > 1) {
++ struct sradix_tree_node *to_free = root->rnode;
++
++ /*
++ * The candidate node has more than one child, or its child
++ * is not at the leftmost store, we cannot shrink.
++ */
++ if (to_free->count != 1 || !to_free->stores[0])
++ break;
++
++ root->rnode = to_free->stores[0];
++ root->rnode->parent = NULL;
++ root->height--;
++ if (unlikely(root->enter_node == to_free))
++ root->enter_node = NULL;
++ root->free(to_free);
++ }
++}
++
++/*
++ * Del the item on the known leaf node and index
++ */
++void sradix_tree_delete_from_leaf(struct sradix_tree_root *root,
++ struct sradix_tree_node *node, unsigned long index)
++{
++ unsigned int offset;
++ struct sradix_tree_node *start, *end;
++
++ BUG_ON(node->height != 1);
++
++ start = node;
++ while (node && !(--node->count))
++ node = node->parent;
++
++ end = node;
++ if (!node) {
++ root->rnode = NULL;
++ root->height = 0;
++ root->min = 0;
++ root->num = 0;
++ root->enter_node = NULL;
++ } else {
++ offset = (index >> (root->shift * (node->height - 1))) & root->mask;
++ if (root->rm)
++ root->rm(node, offset);
++ node->stores[offset] = NULL;
++ root->num--;
++ if (root->min > index) {
++ root->min = index;
++ root->enter_node = node;
++ }
++ }
++
++ if (start != end) {
++ do {
++ node = start;
++ start = start->parent;
++ if (unlikely(root->enter_node == node))
++ root->enter_node = end;
++ root->free(node);
++ } while (start != end);
++
++ /*
++ * Note that shrink may free "end", so enter_node still need to
++ * be checked inside.
++ */
++ sradix_tree_shrink(root);
++ } else if (node->count == root->stores_size - 1) {
++ /* It WAS a full leaf node. Update the ancestors */
++ node = node->parent;
++ while (node) {
++ node->fulls--;
++ if (node->fulls != root->stores_size - 1)
++ break;
++
++ node = node->parent;
++ }
++ }
++}
++
++void *sradix_tree_lookup(struct sradix_tree_root *root, unsigned long index)
++{
++ unsigned int height, offset;
++ struct sradix_tree_node *node;
++ int shift;
++
++ node = root->rnode;
++ if (node == NULL || (index >> (root->shift * root->height)))
++ return NULL;
++
++ height = root->height;
++ shift = (height - 1) * root->shift;
++
++ do {
++ offset = (index >> shift) & root->mask;
++ node = node->stores[offset];
++ if (!node)
++ return NULL;
++
++ shift -= root->shift;
++ } while (shift >= 0);
++
++ return node;
++}
++
++/*
++ * Return the item if it exists, otherwise create it in place
++ * and return the created item.
++ */
++void *sradix_tree_lookup_create(struct sradix_tree_root *root,
++ unsigned long index, void *(*item_alloc)(void))
++{
++ unsigned int height, offset;
++ struct sradix_tree_node *node, *tmp;
++ void *item;
++ int shift, error;
++
++ if (root->rnode == NULL || (index >> (root->shift * root->height))) {
++ if (item_alloc) {
++ error = sradix_tree_extend(root, index);
++ if (error)
++ return NULL;
++ } else {
++ return NULL;
++ }
++ }
++
++ node = root->rnode;
++ height = root->height;
++ shift = (height - 1) * root->shift;
++
++ do {
++ offset = (index >> shift) & root->mask;
++ if (!node->stores[offset]) {
++ if (!(tmp = root->alloc()))
++ return NULL;
++
++ tmp->height = shift / root->shift;
++ node->stores[offset] = tmp;
++ tmp->parent = node;
++ node->count++;
++ node = tmp;
++ } else {
++ node = node->stores[offset];
++ }
++
++ shift -= root->shift;
++ } while (shift > 0);
++
++ BUG_ON(node->height != 1);
++ offset = index & root->mask;
++ if (node->stores[offset]) {
++ return node->stores[offset];
++ } else if (item_alloc) {
++ if (!(item = item_alloc()))
++ return NULL;
++
++ node->stores[offset] = item;
++
++ /*
++ * NOTE: we do NOT call root->assign here, since this item is
++ * newly created by us having no meaning. Caller can call this
++ * if it's necessary to do so.
++ */
++
++ node->count++;
++ root->num++;
++
++ while (sradix_node_full(root, node)) {
++ node = node->parent;
++ if (!node)
++ break;
++
++ node->fulls++;
++ }
++
++ if (unlikely(!node)) {
++ /* All nodes are full */
++ root->min = 1 << (root->height * root->shift);
++ } else {
++ if (root->min == index) {
++ root->min |= (1UL << (node->height - 1)) - 1;
++ root->min++;
++ root->enter_node = node;
++ }
++ }
++
++ return item;
++ } else {
++ return NULL;
++ }
++
++}
++
++int sradix_tree_delete(struct sradix_tree_root *root, unsigned long index)
++{
++ unsigned int height, offset;
++ struct sradix_tree_node *node;
++ int shift;
++
++ node = root->rnode;
++ if (node == NULL || (index >> (root->shift * root->height)))
++ return -ENOENT;
++
++ height = root->height;
++ shift = (height - 1) * root->shift;
++
++ do {
++ offset = (index >> shift) & root->mask;
++ node = node->stores[offset];
++ if (!node)
++ return -ENOENT;
++
++ shift -= root->shift;
++ } while (shift > 0);
++
++ offset = index & root->mask;
++ if (!node->stores[offset])
++ return -ENOENT;
++
++ sradix_tree_delete_from_leaf(root, node, index);
++
++ return 0;
++}
+diff --git a/mm/Kconfig b/mm/Kconfig
+index d16ba9249..744b0ed24 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -301,6 +301,32 @@ config KSM
+ See Documentation/vm/ksm.rst for more information: KSM is inactive
+ until a program has madvised that an area is MADV_MERGEABLE, and
+ root has set /sys/kernel/mm/ksm/run to 1 (if CONFIG_SYSFS is set).
++choice
++ prompt "Choose UKSM/KSM strategy"
++ default UKSM
++ depends on KSM
++ help
++ This option allows to select a UKSM/KSM stragety.
++
++config UKSM
++ bool "Ultra-KSM for page merging"
++ depends on KSM
++ help
++ UKSM is inspired by the Linux kernel project \u2014 KSM(Kernel Same
++ page Merging), but with a fundamentally rewritten core algorithm. With
++ an advanced algorithm, UKSM now can transparently scans all anonymously
++ mapped user space applications with an significantly improved scan speed
++ and CPU efficiency. Since KVM is friendly to KSM, KVM can also benefit from
++ UKSM. Now UKSM has its first stable release and first real world enterprise user.
++ For more information, please goto its project page.
++ (github.com/dolohow/uksm)
++
++config KSM_LEGACY
++ bool "Legacy KSM implementation"
++ depends on KSM
++ help
++ The legacy KSM implementation from Red Hat.
++endchoice
+
+ config DEFAULT_MMAP_MIN_ADDR
+ int "Low address space to protect from user allocation"
+diff --git a/mm/Makefile b/mm/Makefile
+index fc60a40ce..69015e892 100644
+--- a/mm/Makefile
++++ b/mm/Makefile
+@@ -81,7 +81,8 @@ obj-$(CONFIG_SPARSEMEM) += sparse.o
+ obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
+ obj-$(CONFIG_SLOB) += slob.o
+ obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
+-obj-$(CONFIG_KSM) += ksm.o
++obj-$(CONFIG_KSM_LEGACY) += ksm.o
++obj-$(CONFIG_UKSM) += uksm.o
+ obj-$(CONFIG_PAGE_POISONING) += page_poison.o
+ obj-$(CONFIG_SLAB) += slab.o
+ obj-$(CONFIG_SLUB) += slub.o
+diff --git a/mm/ksm.c b/mm/ksm.c
+index a5716fdec..b8a7f01cd 100644
+--- a/mm/ksm.c
++++ b/mm/ksm.c
+@@ -852,17 +852,6 @@ static int unmerge_ksm_pages(struct vm_area_struct *vma,
+ return err;
+ }
+
+-static inline struct stable_node *page_stable_node(struct page *page)
+-{
+- return PageKsm(page) ? page_rmapping(page) : NULL;
+-}
+-
+-static inline void set_page_stable_node(struct page *page,
+- struct stable_node *stable_node)
+-{
+- page->mapping = (void *)((unsigned long)stable_node | PAGE_MAPPING_KSM);
+-}
+-
+ #ifdef CONFIG_SYSFS
+ /*
+ * Only called through the sysfs control interface:
+diff --git a/mm/memory.c b/mm/memory.c
+index c52be6d6b..c5512e697 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -157,6 +157,25 @@ EXPORT_SYMBOL(zero_pfn);
+
+ unsigned long highest_memmap_pfn __read_mostly;
+
++#ifdef CONFIG_UKSM
++unsigned long uksm_zero_pfn __read_mostly;
++EXPORT_SYMBOL_GPL(uksm_zero_pfn);
++struct page *empty_uksm_zero_page;
++
++static int __init setup_uksm_zero_page(void)
++{
++ empty_uksm_zero_page = alloc_pages(__GFP_ZERO & ~__GFP_MOVABLE, 0);
++ if (!empty_uksm_zero_page)
++ panic("Oh boy, that early out of memory?");
++
++ SetPageReserved(empty_uksm_zero_page);
++ uksm_zero_pfn = page_to_pfn(empty_uksm_zero_page);
++
++ return 0;
++}
++core_initcall(setup_uksm_zero_page);
++#endif
++
+ /*
+ * CONFIG_MMU architectures set up ZERO_PAGE in their paging_init()
+ */
+@@ -172,6 +191,7 @@ void mm_trace_rss_stat(struct mm_struct *mm, int member, long count)
+ trace_rss_stat(mm, member, count);
+ }
+
++
+ #if defined(SPLIT_RSS_COUNTING)
+
+ void sync_mm_rss(struct mm_struct *mm)
+@@ -954,6 +974,11 @@ copy_present_pte(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
+ get_page(page);
+ page_dup_rmap(page, false);
+ rss[mm_counter(page)]++;
++
++ /* Should return NULL in vm_normal_page() */
++ uksm_bugon_zeropage(pte);
++ } else {
++ uksm_map_zero_page(pte);
+ }
+
+ /*
+@@ -1346,8 +1371,10 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
+ ptent = ptep_get_and_clear_full(mm, addr, pte,
+ tlb->fullmm);
+ tlb_remove_tlb_entry(tlb, pte, addr);
+- if (unlikely(!page))
++ if (unlikely(!page)) {
++ uksm_unmap_zero_page(ptent);
+ continue;
++ }
+
+ if (!PageAnon(page)) {
+ if (pte_dirty(ptent)) {
+@@ -2753,6 +2780,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
+
+ if (likely(src)) {
+ copy_user_highpage(dst, src, addr, vma);
++ uksm_cow_page(vma, src);
+ return true;
+ }
+
+@@ -2999,6 +3027,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
+ vmf->address);
+ if (!new_page)
+ goto oom;
++ uksm_cow_pte(vma, vmf->orig_pte);
+ } else {
+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,
+ vmf->address);
+@@ -3041,7 +3070,9 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
+ mm_counter_file(old_page));
+ inc_mm_counter_fast(mm, MM_ANONPAGES);
+ }
++ uksm_bugon_zeropage(vmf->orig_pte);
+ } else {
++ uksm_unmap_zero_page(vmf->orig_pte);
+ inc_mm_counter_fast(mm, MM_ANONPAGES);
+ }
+ flush_cache_page(vma, vmf->address, pte_pfn(vmf->orig_pte));
+diff --git a/mm/mmap.c b/mm/mmap.c
+index 88dcc5c25..b93c12938 100644
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -46,6 +46,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/pkeys.h>
+ #include <linux/oom.h>
++#include <linux/ksm.h>
+ #include <linux/sched/mm.h>
+
+ #include <linux/uaccess.h>
+@@ -185,6 +186,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
+ if (vma->vm_file)
+ fput(vma->vm_file);
+ mpol_put(vma_policy(vma));
++ uksm_remove_vma(vma);
+ vm_area_free(vma);
+ return next;
+ }
+@@ -751,9 +753,16 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ long adjust_next = 0;
+ int remove_next = 0;
+
++/*
++ * to avoid deadlock, ksm_remove_vma must be done before any spin_lock is
++ * acquired
++ */
++ uksm_remove_vma(vma);
++
+ if (next && !insert) {
+ struct vm_area_struct *exporter = NULL, *importer = NULL;
+
++ uksm_remove_vma(next);
+ if (end >= next->vm_end) {
+ /*
+ * vma expands, overlapping all the next, and
+@@ -884,6 +893,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ end_changed = true;
+ }
+ vma->vm_pgoff = pgoff;
++
+ if (adjust_next) {
+ next->vm_start += adjust_next;
+ next->vm_pgoff += adjust_next >> PAGE_SHIFT;
+@@ -988,6 +998,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ if (remove_next == 2) {
+ remove_next = 1;
+ end = next->vm_end;
++ uksm_remove_vma(next);
+ goto again;
+ }
+ else if (next)
+@@ -1014,10 +1025,14 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ */
+ VM_WARN_ON(mm->highest_vm_end != vm_end_gap(vma));
+ }
++ } else {
++ if (next && !insert)
++ uksm_vma_add_new(next);
+ }
+ if (insert && file)
+ uprobe_mmap(insert);
+
++ uksm_vma_add_new(vma);
+ validate_mm(mm);
+
+ return 0;
+@@ -1470,6 +1485,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
+ vm_flags = calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
+ mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+
++ /* If uksm is enabled, we add VM_MERGEABLE to new VMAs. */
++ uksm_vm_flags_mod(&vm_flags);
++
+ if (flags & MAP_LOCKED)
+ if (!can_do_mlock())
+ return -EPERM;
+@@ -1843,6 +1861,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
+ if (file && vm_flags & VM_SHARED)
+ mapping_unmap_writable(file->f_mapping);
+ file = vma->vm_file;
++ uksm_vma_add_new(vma);
+ out:
+ perf_event_mmap(vma);
+
+@@ -1882,6 +1901,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
+ if (vm_flags & VM_SHARED)
+ mapping_unmap_writable(file->f_mapping);
+ free_vma:
++ uksm_remove_vma(vma);
+ vm_area_free(vma);
+ unacct_error:
+ if (charged)
+@@ -2742,6 +2762,8 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
+ else
+ err = vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new);
+
++ uksm_vma_add_new(new);
++
+ /* Success. */
+ if (!err)
+ return 0;
+@@ -3032,6 +3054,7 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla
+ if ((flags & (~VM_EXEC)) != 0)
+ return -EINVAL;
+ flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
++ uksm_vm_flags_mod(&flags);
+
+ mapped_addr = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
+ if (IS_ERR_VALUE(mapped_addr))
+@@ -3077,6 +3100,7 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla
+ vma->vm_flags = flags;
+ vma->vm_page_prot = vm_get_page_prot(flags);
+ vma_link(mm, vma, prev, rb_link, rb_parent);
++ uksm_vma_add_new(vma);
+ out:
+ perf_event_mmap(vma);
+ mm->total_vm += len >> PAGE_SHIFT;
+@@ -3153,6 +3177,11 @@ void exit_mmap(struct mm_struct *mm)
+ mmap_write_lock(mm);
+ mmap_write_unlock(mm);
+ }
++ /*
++ * Taking write lock on mmap does not harm others,
++ * but it's crucial for uksm to avoid races.
++ */
++ mmap_write_lock(mm);
+
+ if (mm->locked_vm)
+ unlock_range(mm->mmap, ULONG_MAX);
+@@ -3183,6 +3212,11 @@ void exit_mmap(struct mm_struct *mm)
+ cond_resched();
+ }
+ vm_unacct_memory(nr_accounted);
++
++ mm->mmap = NULL;
++ mm->mm_rb = RB_ROOT;
++ vmacache_invalidate(mm);
++ mmap_write_unlock(mm);
+ }
+
+ /* Insert vm structure into process list sorted by address
+@@ -3290,6 +3324,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
+ new_vma->vm_ops->open(new_vma);
+ vma_link(mm, new_vma, prev, rb_link, rb_parent);
+ *need_rmap_locks = false;
++ uksm_vma_add_new(new_vma);
+ }
+ return new_vma;
+
+@@ -3454,6 +3489,7 @@ static struct vm_area_struct *__install_special_mapping(
+ vm_stat_account(mm, vma->vm_flags, len >> PAGE_SHIFT);
+
+ perf_event_mmap(vma);
++ uksm_vma_add_new(vma);
+
+ return vma;
+
+diff --git a/mm/uksm.c b/mm/uksm.c
+new file mode 100644
+index 000000000..e4732c00b
+--- /dev/null
++++ b/mm/uksm.c
+@@ -0,0 +1,5614 @@
++/*
++ * Ultra KSM. Copyright (C) 2011-2012 Nai Xia
++ *
++ * This is an improvement upon KSM. Some basic data structures and routines
++ * are borrowed from ksm.c .
++ *
++ * Its new features:
++ * 1. Full system scan:
++ * It automatically scans all user processes' anonymous VMAs. Kernel-user
++ * interaction to submit a memory area to KSM is no longer needed.
++ *
++ * 2. Rich area detection:
++ * It automatically detects rich areas containing abundant duplicated
++ * pages based. Rich areas are given a full scan speed. Poor areas are
++ * sampled at a reasonable speed with very low CPU consumption.
++ *
++ * 3. Ultra Per-page scan speed improvement:
++ * A new hash algorithm is proposed. As a result, on a machine with
++ * Core(TM)2 Quad Q9300 CPU in 32-bit mode and 800MHZ DDR2 main memory, it
++ * can scan memory areas that does not contain duplicated pages at speed of
++ * 627MB/sec ~ 2445MB/sec and can merge duplicated areas at speed of
++ * 477MB/sec ~ 923MB/sec.
++ *
++ * 4. Thrashing area avoidance:
++ * Thrashing area(an VMA that has frequent Ksm page break-out) can be
++ * filtered out. My benchmark shows it's more efficient than KSM's per-page
++ * hash value based volatile page detection.
++ *
++ *
++ * 5. Misc changes upon KSM:
++ * * It has a fully x86-opitmized memcmp dedicated for 4-byte-aligned page
++ * comparison. It's much faster than default C version on x86.
++ * * rmap_item now has an struct *page member to loosely cache a
++ * address-->page mapping, which reduces too much time-costly
++ * follow_page().
++ * * The VMA creation/exit procedures are hooked to let the Ultra KSM know.
++ * * try_to_merge_two_pages() now can revert a pte if it fails. No break_
++ * ksm is needed for this case.
++ *
++ * 6. Full Zero Page consideration(contributed by Figo Zhang)
++ * Now uksmd consider full zero pages as special pages and merge them to an
++ * special unswappable uksm zero page.
++ */
++
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/fs.h>
++#include <linux/mman.h>
++#include <linux/sched.h>
++#include <linux/sched/mm.h>
++#include <linux/sched/coredump.h>
++#include <linux/sched/cputime.h>
++#include <linux/rwsem.h>
++#include <linux/pagemap.h>
++#include <linux/rmap.h>
++#include <linux/spinlock.h>
++#include <linux/jhash.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/rbtree.h>
++#include <linux/memory.h>
++#include <linux/mmu_notifier.h>
++#include <linux/swap.h>
++#include <linux/ksm.h>
++#include <linux/crypto.h>
++#include <linux/scatterlist.h>
++#include <crypto/hash.h>
++#include <linux/random.h>
++#include <linux/math64.h>
++#include <linux/gcd.h>
++#include <linux/freezer.h>
++#include <linux/oom.h>
++#include <linux/numa.h>
++#include <linux/sradix-tree.h>
++
++#include <asm/tlbflush.h>
++#include "internal.h"
++
++#ifdef CONFIG_X86
++#undef memcmp
++
++#ifdef CONFIG_X86_32
++#define memcmp memcmpx86_32
++/*
++ * Compare 4-byte-aligned address s1 and s2, with length n
++ */
++int memcmpx86_32(void *s1, void *s2, size_t n)
++{
++ size_t num = n / 4;
++ register int res;
++
++ __asm__ __volatile__
++ (
++ "testl %3,%3\n\t"
++ "repe; cmpsd\n\t"
++ "je 1f\n\t"
++ "sbbl %0,%0\n\t"
++ "orl $1,%0\n"
++ "1:"
++ : "=&a" (res), "+&S" (s1), "+&D" (s2), "+&c" (num)
++ : "0" (0)
++ : "cc");
++
++ return res;
++}
++
++/*
++ * Check the page is all zero ?
++ */
++static int is_full_zero(const void *s1, size_t len)
++{
++ unsigned char same;
++
++ len /= 4;
++
++ __asm__ __volatile__
++ ("repe; scasl;"
++ "sete %0"
++ : "=qm" (same), "+D" (s1), "+c" (len)
++ : "a" (0)
++ : "cc");
++
++ return same;
++}
++
++
++#elif defined(CONFIG_X86_64)
++#define memcmp memcmpx86_64
++/*
++ * Compare 8-byte-aligned address s1 and s2, with length n
++ */
++int memcmpx86_64(void *s1, void *s2, size_t n)
++{
++ size_t num = n / 8;
++ register int res;
++
++ __asm__ __volatile__
++ (
++ "testq %q3,%q3\n\t"
++ "repe; cmpsq\n\t"
++ "je 1f\n\t"
++ "sbbq %q0,%q0\n\t"
++ "orq $1,%q0\n"
++ "1:"
++ : "=&a" (res), "+&S" (s1), "+&D" (s2), "+&c" (num)
++ : "0" (0)
++ : "cc");
++
++ return res;
++}
++
++static int is_full_zero(const void *s1, size_t len)
++{
++ unsigned char same;
++
++ len /= 8;
++
++ __asm__ __volatile__
++ ("repe; scasq;"
++ "sete %0"
++ : "=qm" (same), "+D" (s1), "+c" (len)
++ : "a" (0)
++ : "cc");
++
++ return same;
++}
++
++#endif
++#else
++static int is_full_zero(const void *s1, size_t len)
++{
++ unsigned long *src = s1;
++ int i;
++
++ len /= sizeof(*src);
++
++ for (i = 0; i < len; i++) {
++ if (src[i])
++ return 0;
++ }
++
++ return 1;
++}
++#endif
++
++#define UKSM_RUNG_ROUND_FINISHED (1 << 0)
++#define TIME_RATIO_SCALE 10000
++
++#define SLOT_TREE_NODE_SHIFT 8
++#define SLOT_TREE_NODE_STORE_SIZE (1UL << SLOT_TREE_NODE_SHIFT)
++struct slot_tree_node {
++ unsigned long size;
++ struct sradix_tree_node snode;
++ void *stores[SLOT_TREE_NODE_STORE_SIZE];
++};
++
++static struct kmem_cache *slot_tree_node_cachep;
++
++static struct sradix_tree_node *slot_tree_node_alloc(void)
++{
++ struct slot_tree_node *p;
++
++ p = kmem_cache_zalloc(slot_tree_node_cachep, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (!p)
++ return NULL;
++
++ return &p->snode;
++}
++
++static void slot_tree_node_free(struct sradix_tree_node *node)
++{
++ struct slot_tree_node *p;
++
++ p = container_of(node, struct slot_tree_node, snode);
++ kmem_cache_free(slot_tree_node_cachep, p);
++}
++
++static void slot_tree_node_extend(struct sradix_tree_node *parent,
++ struct sradix_tree_node *child)
++{
++ struct slot_tree_node *p, *c;
++
++ p = container_of(parent, struct slot_tree_node, snode);
++ c = container_of(child, struct slot_tree_node, snode);
++
++ p->size += c->size;
++}
++
++void slot_tree_node_assign(struct sradix_tree_node *node,
++ unsigned int index, void *item)
++{
++ struct vma_slot *slot = item;
++ struct slot_tree_node *cur;
++
++ slot->snode = node;
++ slot->sindex = index;
++
++ while (node) {
++ cur = container_of(node, struct slot_tree_node, snode);
++ cur->size += slot->pages;
++ node = node->parent;
++ }
++}
++
++void slot_tree_node_rm(struct sradix_tree_node *node, unsigned int offset)
++{
++ struct vma_slot *slot;
++ struct slot_tree_node *cur;
++ unsigned long pages;
++
++ if (node->height == 1) {
++ slot = node->stores[offset];
++ pages = slot->pages;
++ } else {
++ cur = container_of(node->stores[offset],
++ struct slot_tree_node, snode);
++ pages = cur->size;
++ }
++
++ while (node) {
++ cur = container_of(node, struct slot_tree_node, snode);
++ cur->size -= pages;
++ node = node->parent;
++ }
++}
++
++unsigned long slot_iter_index;
++int slot_iter(void *item, unsigned long height)
++{
++ struct slot_tree_node *node;
++ struct vma_slot *slot;
++
++ if (height == 1) {
++ slot = item;
++ if (slot_iter_index < slot->pages) {
++ /*in this one*/
++ return 1;
++ } else {
++ slot_iter_index -= slot->pages;
++ return 0;
++ }
++
++ } else {
++ node = container_of(item, struct slot_tree_node, snode);
++ if (slot_iter_index < node->size) {
++ /*in this one*/
++ return 1;
++ } else {
++ slot_iter_index -= node->size;
++ return 0;
++ }
++ }
++}
++
++
++static inline void slot_tree_init_root(struct sradix_tree_root *root)
++{
++ init_sradix_tree_root(root, SLOT_TREE_NODE_SHIFT);
++ root->alloc = slot_tree_node_alloc;
++ root->free = slot_tree_node_free;
++ root->extend = slot_tree_node_extend;
++ root->assign = slot_tree_node_assign;
++ root->rm = slot_tree_node_rm;
++}
++
++void slot_tree_init(void)
++{
++ slot_tree_node_cachep = kmem_cache_create("slot_tree_node",
++ sizeof(struct slot_tree_node), 0,
++ SLAB_PANIC | SLAB_RECLAIM_ACCOUNT,
++ NULL);
++}
++
++
++/* Each rung of this ladder is a list of VMAs having a same scan ratio */
++struct scan_rung {
++ //struct list_head scanned_list;
++ struct sradix_tree_root vma_root;
++ struct sradix_tree_root vma_root2;
++
++ struct vma_slot *current_scan;
++ unsigned long current_offset;
++
++ /*
++ * The initial value for current_offset, it should loop over
++ * [0~ step - 1] to let all slot have its chance to be scanned.
++ */
++ unsigned long offset_init;
++ unsigned long step; /* dynamic step for current_offset */
++ unsigned int flags;
++ unsigned long pages_to_scan;
++ //unsigned long fully_scanned_slots;
++ /*
++ * a little bit tricky - if cpu_time_ratio > 0, then the value is the
++ * the cpu time ratio it can spend in rung_i for every scan
++ * period. if < 0, then it is the cpu time ratio relative to the
++ * max cpu percentage user specified. Both in unit of
++ * 1/TIME_RATIO_SCALE
++ */
++ int cpu_ratio;
++
++ /*
++ * How long it will take for all slots in this rung to be fully
++ * scanned? If it's zero, we don't care about the cover time:
++ * it's fully scanned.
++ */
++ unsigned int cover_msecs;
++ //unsigned long vma_num;
++ //unsigned long pages; /* Sum of all slot's pages in rung */
++};
++
++/**
++ * node of either the stable or unstale rbtree
++ *
++ */
++struct tree_node {
++ struct rb_node node; /* link in the main (un)stable rbtree */
++ struct rb_root sub_root; /* rb_root for sublevel collision rbtree */
++ u32 hash;
++ unsigned long count; /* TODO: merged with sub_root */
++ struct list_head all_list; /* all tree nodes in stable/unstable tree */
++};
++
++/**
++ * struct stable_node - node of the stable rbtree
++ * @node: rb node of this ksm page in the stable tree
++ * @hlist: hlist head of rmap_items using this ksm page
++ * @kpfn: page frame number of this ksm page
++ */
++struct stable_node {
++ struct rb_node node; /* link in sub-rbtree */
++ struct tree_node *tree_node; /* it's tree node root in stable tree, NULL if it's in hell list */
++ struct hlist_head hlist;
++ unsigned long kpfn;
++ u32 hash_max; /* if ==0 then it's not been calculated yet */
++ struct list_head all_list; /* in a list for all stable nodes */
++};
++
++/**
++ * struct node_vma - group rmap_items linked in a same stable
++ * node together.
++ */
++struct node_vma {
++ union {
++ struct vma_slot *slot;
++ unsigned long key; /* slot is used as key sorted on hlist */
++ };
++ struct hlist_node hlist;
++ struct hlist_head rmap_hlist;
++ struct stable_node *head;
++};
++
++/**
++ * struct rmap_item - reverse mapping item for virtual addresses
++ * @rmap_list: next rmap_item in mm_slot's singly-linked rmap_list
++ * @anon_vma: pointer to anon_vma for this mm,address, when in stable tree
++ * @mm: the memory structure this rmap_item is pointing into
++ * @address: the virtual address this rmap_item tracks (+ flags in low bits)
++ * @node: rb node of this rmap_item in the unstable tree
++ * @head: pointer to stable_node heading this list in the stable tree
++ * @hlist: link into hlist of rmap_items hanging off that stable_node
++ */
++struct rmap_item {
++ struct vma_slot *slot;
++ struct page *page;
++ unsigned long address; /* + low bits used for flags below */
++ unsigned long hash_round;
++ unsigned long entry_index;
++ union {
++ struct {/* when in unstable tree */
++ struct rb_node node;
++ struct tree_node *tree_node;
++ u32 hash_max;
++ };
++ struct { /* when in stable tree */
++ struct node_vma *head;
++ struct hlist_node hlist;
++ struct anon_vma *anon_vma;
++ };
++ };
++} __aligned(4);
++
++struct rmap_list_entry {
++ union {
++ struct rmap_item *item;
++ unsigned long addr;
++ };
++ /* lowest bit is used for is_addr tag */
++} __aligned(4); /* 4 aligned to fit in to pages*/
++
++
++/* Basic data structure definition ends */
++
++
++/*
++ * Flags for rmap_item to judge if it's listed in the stable/unstable tree.
++ * The flags use the low bits of rmap_item.address
++ */
++#define UNSTABLE_FLAG 0x1
++#define STABLE_FLAG 0x2
++#define get_rmap_addr(x) ((x)->address & PAGE_MASK)
++
++/*
++ * rmap_list_entry helpers
++ */
++#define IS_ADDR_FLAG 1
++#define is_addr(ptr) ((unsigned long)(ptr) & IS_ADDR_FLAG)
++#define set_is_addr(ptr) ((ptr) |= IS_ADDR_FLAG)
++#define get_clean_addr(ptr) (((ptr) & ~(__typeof__(ptr))IS_ADDR_FLAG))
++
++
++/*
++ * High speed caches for frequently allocated and freed structs
++ */
++static struct kmem_cache *rmap_item_cache;
++static struct kmem_cache *stable_node_cache;
++static struct kmem_cache *node_vma_cache;
++static struct kmem_cache *vma_slot_cache;
++static struct kmem_cache *tree_node_cache;
++#define UKSM_KMEM_CACHE(__struct, __flags) kmem_cache_create("uksm_"#__struct,\
++ sizeof(struct __struct), __alignof__(struct __struct),\
++ (__flags), NULL)
++
++/* Array of all scan_rung, uksm_scan_ladder[0] having the minimum scan ratio */
++#define SCAN_LADDER_SIZE 4
++static struct scan_rung uksm_scan_ladder[SCAN_LADDER_SIZE];
++
++/* The evaluation rounds uksmd has finished */
++static unsigned long long uksm_eval_round = 1;
++
++/*
++ * we add 1 to this var when we consider we should rebuild the whole
++ * unstable tree.
++ */
++static unsigned long uksm_hash_round = 1;
++
++/*
++ * How many times the whole memory is scanned.
++ */
++static unsigned long long fully_scanned_round = 1;
++
++/* The total number of virtual pages of all vma slots */
++static u64 uksm_pages_total;
++
++/* The number of pages has been scanned since the start up */
++static u64 uksm_pages_scanned;
++
++static u64 scanned_virtual_pages;
++
++/* The number of pages has been scanned since last encode_benefit call */
++static u64 uksm_pages_scanned_last;
++
++/* If the scanned number is tooo large, we encode it here */
++static u64 pages_scanned_stored;
++
++static unsigned long pages_scanned_base;
++
++/* The number of nodes in the stable tree */
++static unsigned long uksm_pages_shared;
++
++/* The number of page slots additionally sharing those nodes */
++static unsigned long uksm_pages_sharing;
++
++/* The number of nodes in the unstable tree */
++static unsigned long uksm_pages_unshared;
++
++/*
++ * Milliseconds ksmd should sleep between scans,
++ * >= 100ms to be consistent with
++ * scan_time_to_sleep_msec()
++ */
++static unsigned int uksm_sleep_jiffies;
++
++/* The real value for the uksmd next sleep */
++static unsigned int uksm_sleep_real;
++
++/* Saved value for user input uksm_sleep_jiffies when it's enlarged */
++static unsigned int uksm_sleep_saved;
++
++/* Max percentage of cpu utilization ksmd can take to scan in one batch */
++static unsigned int uksm_max_cpu_percentage;
++
++static int uksm_cpu_governor;
++
++static char *uksm_cpu_governor_str[4] = { "full", "medium", "low", "quiet" };
++
++struct uksm_cpu_preset_s {
++ int cpu_ratio[SCAN_LADDER_SIZE];
++ unsigned int cover_msecs[SCAN_LADDER_SIZE];
++ unsigned int max_cpu; /* percentage */
++};
++
++struct uksm_cpu_preset_s uksm_cpu_preset[4] = {
++ { {20, 40, -2500, -10000}, {1000, 500, 200, 50}, 95},
++ { {20, 30, -2500, -10000}, {1000, 500, 400, 100}, 50},
++ { {10, 20, -5000, -10000}, {1500, 1000, 1000, 250}, 20},
++ { {10, 20, 40, 75}, {2000, 1000, 1000, 1000}, 1},
++};
++
++/* The default value for uksm_ema_page_time if it's not initialized */
++#define UKSM_PAGE_TIME_DEFAULT 500
++
++/*cost to scan one page by expotional moving average in nsecs */
++static unsigned long uksm_ema_page_time = UKSM_PAGE_TIME_DEFAULT;
++
++/* The expotional moving average alpha weight, in percentage. */
++#define EMA_ALPHA 20
++
++/*
++ * The threshold used to filter out thrashing areas,
++ * If it == 0, filtering is disabled, otherwise it's the percentage up-bound
++ * of the thrashing ratio of all areas. Any area with a bigger thrashing ratio
++ * will be considered as having a zero duplication ratio.
++ */
++static unsigned int uksm_thrash_threshold = 50;
++
++/* How much dedup ratio is considered to be abundant*/
++static unsigned int uksm_abundant_threshold = 10;
++
++/* All slots having merged pages in this eval round. */
++struct list_head vma_slot_dedup = LIST_HEAD_INIT(vma_slot_dedup);
++
++/* How many times the ksmd has slept since startup */
++static unsigned long long uksm_sleep_times;
++
++#define UKSM_RUN_STOP 0
++#define UKSM_RUN_MERGE 1
++static unsigned int uksm_run = 1;
++
++static DECLARE_WAIT_QUEUE_HEAD(uksm_thread_wait);
++static DEFINE_MUTEX(uksm_thread_mutex);
++
++/*
++ * List vma_slot_new is for newly created vma_slot waiting to be added by
++ * ksmd. If one cannot be added(e.g. due to it's too small), it's moved to
++ * vma_slot_noadd. vma_slot_del is the list for vma_slot whose corresponding
++ * VMA has been removed/freed.
++ */
++struct list_head vma_slot_new = LIST_HEAD_INIT(vma_slot_new);
++struct list_head vma_slot_noadd = LIST_HEAD_INIT(vma_slot_noadd);
++struct list_head vma_slot_del = LIST_HEAD_INIT(vma_slot_del);
++static DEFINE_SPINLOCK(vma_slot_list_lock);
++
++/* The unstable tree heads */
++static struct rb_root root_unstable_tree = RB_ROOT;
++
++/*
++ * All tree_nodes are in a list to be freed at once when unstable tree is
++ * freed after each scan round.
++ */
++static struct list_head unstable_tree_node_list =
++ LIST_HEAD_INIT(unstable_tree_node_list);
++
++/* List contains all stable nodes */
++static struct list_head stable_node_list = LIST_HEAD_INIT(stable_node_list);
++
++/*
++ * When the hash strength is changed, the stable tree must be delta_hashed and
++ * re-structured. We use two set of below structs to speed up the
++ * re-structuring of stable tree.
++ */
++static struct list_head
++stable_tree_node_list[2] = {LIST_HEAD_INIT(stable_tree_node_list[0]),
++ LIST_HEAD_INIT(stable_tree_node_list[1])};
++
++static struct list_head *stable_tree_node_listp = &stable_tree_node_list[0];
++static struct rb_root root_stable_tree[2] = {RB_ROOT, RB_ROOT};
++static struct rb_root *root_stable_treep = &root_stable_tree[0];
++static unsigned long stable_tree_index;
++
++/* The hash strength needed to hash a full page */
++#define HASH_STRENGTH_FULL (PAGE_SIZE / sizeof(u32))
++
++/* The hash strength needed for loop-back hashing */
++#define HASH_STRENGTH_MAX (HASH_STRENGTH_FULL + 10)
++
++/* The random offsets in a page */
++static u32 *random_nums;
++
++/* The hash strength */
++static unsigned long hash_strength = HASH_STRENGTH_FULL >> 4;
++
++/* The delta value each time the hash strength increases or decreases */
++static unsigned long hash_strength_delta;
++#define HASH_STRENGTH_DELTA_MAX 5
++
++/* The time we have saved due to random_sample_hash */
++static u64 rshash_pos;
++
++/* The time we have wasted due to hash collision */
++static u64 rshash_neg;
++
++struct uksm_benefit {
++ u64 pos;
++ u64 neg;
++ u64 scanned;
++ unsigned long base;
++} benefit;
++
++/*
++ * The relative cost of memcmp, compared to 1 time unit of random sample
++ * hash, this value is tested when ksm module is initialized
++ */
++static unsigned long memcmp_cost;
++
++static unsigned long rshash_neg_cont_zero;
++static unsigned long rshash_cont_obscure;
++
++/* The possible states of hash strength adjustment heuristic */
++enum rshash_states {
++ RSHASH_STILL,
++ RSHASH_TRYUP,
++ RSHASH_TRYDOWN,
++ RSHASH_NEW,
++ RSHASH_PRE_STILL,
++};
++
++/* The possible direction we are about to adjust hash strength */
++enum rshash_direct {
++ GO_UP,
++ GO_DOWN,
++ OBSCURE,
++ STILL,
++};
++
++/* random sampling hash state machine */
++static struct {
++ enum rshash_states state;
++ enum rshash_direct pre_direct;
++ u8 below_count;
++ /* Keep a lookup window of size 5, iff above_count/below_count > 3
++ * in this window we stop trying.
++ */
++ u8 lookup_window_index;
++ u64 stable_benefit;
++ unsigned long turn_point_down;
++ unsigned long turn_benefit_down;
++ unsigned long turn_point_up;
++ unsigned long turn_benefit_up;
++ unsigned long stable_point;
++} rshash_state;
++
++/*zero page hash table, hash_strength [0 ~ HASH_STRENGTH_MAX]*/
++static u32 *zero_hash_table;
++
++static inline struct node_vma *alloc_node_vma(void)
++{
++ struct node_vma *node_vma;
++
++ node_vma = kmem_cache_zalloc(node_vma_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (node_vma) {
++ INIT_HLIST_HEAD(&node_vma->rmap_hlist);
++ INIT_HLIST_NODE(&node_vma->hlist);
++ }
++ return node_vma;
++}
++
++static inline void free_node_vma(struct node_vma *node_vma)
++{
++ kmem_cache_free(node_vma_cache, node_vma);
++}
++
++
++static inline struct vma_slot *alloc_vma_slot(void)
++{
++ struct vma_slot *slot;
++
++ /*
++ * In case ksm is not initialized by now.
++ * Oops, we need to consider the call site of uksm_init() in the future.
++ */
++ if (!vma_slot_cache)
++ return NULL;
++
++ slot = kmem_cache_zalloc(vma_slot_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (slot) {
++ INIT_LIST_HEAD(&slot->slot_list);
++ INIT_LIST_HEAD(&slot->dedup_list);
++ slot->flags |= UKSM_SLOT_NEED_RERAND;
++ }
++ return slot;
++}
++
++static inline void free_vma_slot(struct vma_slot *vma_slot)
++{
++ kmem_cache_free(vma_slot_cache, vma_slot);
++}
++
++
++
++static inline struct rmap_item *alloc_rmap_item(void)
++{
++ struct rmap_item *rmap_item;
++
++ rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (rmap_item) {
++ /* bug on lowest bit is not clear for flag use */
++ BUG_ON(is_addr(rmap_item));
++ }
++ return rmap_item;
++}
++
++static inline void free_rmap_item(struct rmap_item *rmap_item)
++{
++ rmap_item->slot = NULL; /* debug safety */
++ kmem_cache_free(rmap_item_cache, rmap_item);
++}
++
++static inline struct stable_node *alloc_stable_node(void)
++{
++ struct stable_node *node;
++
++ node = kmem_cache_alloc(stable_node_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (!node)
++ return NULL;
++
++ INIT_HLIST_HEAD(&node->hlist);
++ list_add(&node->all_list, &stable_node_list);
++ return node;
++}
++
++static inline void free_stable_node(struct stable_node *stable_node)
++{
++ list_del(&stable_node->all_list);
++ kmem_cache_free(stable_node_cache, stable_node);
++}
++
++static inline struct tree_node *alloc_tree_node(struct list_head *list)
++{
++ struct tree_node *node;
++
++ node = kmem_cache_zalloc(tree_node_cache, GFP_KERNEL |
++ __GFP_NORETRY | __GFP_NOWARN);
++ if (!node)
++ return NULL;
++
++ list_add(&node->all_list, list);
++ return node;
++}
++
++static inline void free_tree_node(struct tree_node *node)
++{
++ list_del(&node->all_list);
++ kmem_cache_free(tree_node_cache, node);
++}
++
++static void uksm_drop_anon_vma(struct rmap_item *rmap_item)
++{
++ struct anon_vma *anon_vma = rmap_item->anon_vma;
++
++ put_anon_vma(anon_vma);
++}
++
++
++/**
++ * Remove a stable node from stable_tree, may unlink from its tree_node and
++ * may remove its parent tree_node if no other stable node is pending.
++ *
++ * @stable_node The node need to be removed
++ * @unlink_rb Will this node be unlinked from the rbtree?
++ * @remove_tree_ node Will its tree_node be removed if empty?
++ */
++static void remove_node_from_stable_tree(struct stable_node *stable_node,
++ int unlink_rb, int remove_tree_node)
++{
++ struct node_vma *node_vma;
++ struct rmap_item *rmap_item;
++ struct hlist_node *n;
++
++ if (!hlist_empty(&stable_node->hlist)) {
++ hlist_for_each_entry_safe(node_vma, n,
++ &stable_node->hlist, hlist) {
++ hlist_for_each_entry(rmap_item, &node_vma->rmap_hlist, hlist) {
++ uksm_pages_sharing--;
++
++ uksm_drop_anon_vma(rmap_item);
++ rmap_item->address &= PAGE_MASK;
++ }
++ free_node_vma(node_vma);
++ cond_resched();
++ }
++
++ /* the last one is counted as shared */
++ uksm_pages_shared--;
++ uksm_pages_sharing++;
++ }
++
++ if (stable_node->tree_node && unlink_rb) {
++ rb_erase(&stable_node->node,
++ &stable_node->tree_node->sub_root);
++
++ if (RB_EMPTY_ROOT(&stable_node->tree_node->sub_root) &&
++ remove_tree_node) {
++ rb_erase(&stable_node->tree_node->node,
++ root_stable_treep);
++ free_tree_node(stable_node->tree_node);
++ } else {
++ stable_node->tree_node->count--;
++ }
++ }
++
++ free_stable_node(stable_node);
++}
++
++
++/*
++ * get_uksm_page: checks if the page indicated by the stable node
++ * is still its ksm page, despite having held no reference to it.
++ * In which case we can trust the content of the page, and it
++ * returns the gotten page; but if the page has now been zapped,
++ * remove the stale node from the stable tree and return NULL.
++ *
++ * You would expect the stable_node to hold a reference to the ksm page.
++ * But if it increments the page's count, swapping out has to wait for
++ * ksmd to come around again before it can free the page, which may take
++ * seconds or even minutes: much too unresponsive. So instead we use a
++ * "keyhole reference": access to the ksm page from the stable node peeps
++ * out through its keyhole to see if that page still holds the right key,
++ * pointing back to this stable node. This relies on freeing a PageAnon
++ * page to reset its page->mapping to NULL, and relies on no other use of
++ * a page to put something that might look like our key in page->mapping.
++ *
++ * include/linux/pagemap.h page_cache_get_speculative() is a good reference,
++ * but this is different - made simpler by uksm_thread_mutex being held, but
++ * interesting for assuming that no other use of the struct page could ever
++ * put our expected_mapping into page->mapping (or a field of the union which
++ * coincides with page->mapping). The RCU calls are not for KSM at all, but
++ * to keep the page_count protocol described with page_cache_get_speculative.
++ *
++ * Note: it is possible that get_uksm_page() will return NULL one moment,
++ * then page the next, if the page is in between page_freeze_refs() and
++ * page_unfreeze_refs(): this shouldn't be a problem anywhere, the page
++ * is on its way to being freed; but it is an anomaly to bear in mind.
++ *
++ * @unlink_rb: if the removal of this node will firstly unlink from
++ * its rbtree. stable_node_reinsert will prevent this when restructuring the
++ * node from its old tree.
++ *
++ * @remove_tree_node: if this is the last one of its tree_node, will the
++ * tree_node be freed ? If we are inserting stable node, this tree_node may
++ * be reused, so don't free it.
++ */
++static struct page *get_uksm_page(struct stable_node *stable_node,
++ int unlink_rb, int remove_tree_node)
++{
++ struct page *page;
++ void *expected_mapping;
++ unsigned long kpfn;
++
++ expected_mapping = (void *)((unsigned long)stable_node |
++ PAGE_MAPPING_KSM);
++again:
++ kpfn = READ_ONCE(stable_node->kpfn);
++ page = pfn_to_page(kpfn);
++
++ /*
++ * page is computed from kpfn, so on most architectures reading
++ * page->mapping is naturally ordered after reading node->kpfn,
++ * but on Alpha we need to be more careful.
++ */
++ smp_rmb();
++
++ if (READ_ONCE(page->mapping) != expected_mapping)
++ goto stale;
++
++ /*
++ * We cannot do anything with the page while its refcount is 0.
++ * Usually 0 means free, or tail of a higher-order page: in which
++ * case this node is no longer referenced, and should be freed;
++ * however, it might mean that the page is under page_freeze_refs().
++ * The __remove_mapping() case is easy, again the node is now stale;
++ * but if page is swapcache in migrate_page_move_mapping(), it might
++ * still be our page, in which case it's essential to keep the node.
++ */
++ while (!get_page_unless_zero(page)) {
++ /*
++ * Another check for page->mapping != expected_mapping would
++ * work here too. We have chosen the !PageSwapCache test to
++ * optimize the common case, when the page is or is about to
++ * be freed: PageSwapCache is cleared (under spin_lock_irq)
++ * in the freeze_refs section of __remove_mapping(); but Anon
++ * page->mapping reset to NULL later, in free_pages_prepare().
++ */
++ if (!PageSwapCache(page))
++ goto stale;
++ cpu_relax();
++ }
++
++ if (READ_ONCE(page->mapping) != expected_mapping) {
++ put_page(page);
++ goto stale;
++ }
++
++ lock_page(page);
++ if (READ_ONCE(page->mapping) != expected_mapping) {
++ unlock_page(page);
++ put_page(page);
++ goto stale;
++ }
++ unlock_page(page);
++ return page;
++stale:
++ /*
++ * We come here from above when page->mapping or !PageSwapCache
++ * suggests that the node is stale; but it might be under migration.
++ * We need smp_rmb(), matching the smp_wmb() in ksm_migrate_page(),
++ * before checking whether node->kpfn has been changed.
++ */
++ smp_rmb();
++ if (stable_node->kpfn != kpfn)
++ goto again;
++
++ remove_node_from_stable_tree(stable_node, unlink_rb, remove_tree_node);
++
++ return NULL;
++}
++
++/*
++ * Removing rmap_item from stable or unstable tree.
++ * This function will clean the information from the stable/unstable tree.
++ */
++static inline void remove_rmap_item_from_tree(struct rmap_item *rmap_item)
++{
++ if (rmap_item->address & STABLE_FLAG) {
++ struct stable_node *stable_node;
++ struct node_vma *node_vma;
++ struct page *page;
++
++ node_vma = rmap_item->head;
++ stable_node = node_vma->head;
++ page = get_uksm_page(stable_node, 1, 1);
++ if (!page)
++ goto out;
++
++ /*
++ * page lock is needed because it's racing with
++ * try_to_unmap_ksm(), etc.
++ */
++ lock_page(page);
++ hlist_del(&rmap_item->hlist);
++
++ if (hlist_empty(&node_vma->rmap_hlist)) {
++ hlist_del(&node_vma->hlist);
++ free_node_vma(node_vma);
++ }
++ unlock_page(page);
++
++ put_page(page);
++ if (hlist_empty(&stable_node->hlist)) {
++ /* do NOT call remove_node_from_stable_tree() here,
++ * it's possible for a forked rmap_item not in
++ * stable tree while the in-tree rmap_items were
++ * deleted.
++ */
++ uksm_pages_shared--;
++ } else
++ uksm_pages_sharing--;
++
++
++ uksm_drop_anon_vma(rmap_item);
++ } else if (rmap_item->address & UNSTABLE_FLAG) {
++ if (rmap_item->hash_round == uksm_hash_round) {
++
++ rb_erase(&rmap_item->node,
++ &rmap_item->tree_node->sub_root);
++ if (RB_EMPTY_ROOT(&rmap_item->tree_node->sub_root)) {
++ rb_erase(&rmap_item->tree_node->node,
++ &root_unstable_tree);
++
++ free_tree_node(rmap_item->tree_node);
++ } else
++ rmap_item->tree_node->count--;
++ }
++ uksm_pages_unshared--;
++ }
++
++ rmap_item->address &= PAGE_MASK;
++ rmap_item->hash_max = 0;
++
++out:
++ cond_resched(); /* we're called from many long loops */
++}
++
++static inline int slot_in_uksm(struct vma_slot *slot)
++{
++ return list_empty(&slot->slot_list);
++}
++
++/*
++ * Test if the mm is exiting
++ */
++static inline bool uksm_test_exit(struct mm_struct *mm)
++{
++ return atomic_read(&mm->mm_users) == 0;
++}
++
++static inline unsigned long vma_pool_size(struct vma_slot *slot)
++{
++ return round_up(sizeof(struct rmap_list_entry) * slot->pages,
++ PAGE_SIZE) >> PAGE_SHIFT;
++}
++
++#define CAN_OVERFLOW_U64(x, delta) (U64_MAX - (x) < (delta))
++
++/* must be done with sem locked */
++static int slot_pool_alloc(struct vma_slot *slot)
++{
++ unsigned long pool_size;
++
++ if (slot->rmap_list_pool)
++ return 0;
++
++ pool_size = vma_pool_size(slot);
++ slot->rmap_list_pool = kcalloc(pool_size, sizeof(struct page *),
++ GFP_KERNEL);
++ if (!slot->rmap_list_pool)
++ return -ENOMEM;
++
++ slot->pool_counts = kcalloc(pool_size, sizeof(unsigned int),
++ GFP_KERNEL);
++ if (!slot->pool_counts) {
++ kfree(slot->rmap_list_pool);
++ return -ENOMEM;
++ }
++
++ slot->pool_size = pool_size;
++ BUG_ON(CAN_OVERFLOW_U64(uksm_pages_total, slot->pages));
++ slot->flags |= UKSM_SLOT_IN_UKSM;
++ uksm_pages_total += slot->pages;
++
++ return 0;
++}
++
++/*
++ * Called after vma is unlinked from its mm
++ */
++void uksm_remove_vma(struct vm_area_struct *vma)
++{
++ struct vma_slot *slot;
++
++ if (!vma->uksm_vma_slot)
++ return;
++
++ spin_lock(&vma_slot_list_lock);
++ slot = vma->uksm_vma_slot;
++ if (!slot)
++ goto out;
++
++ if (slot_in_uksm(slot)) {
++ /**
++ * This slot has been added by ksmd, so move to the del list
++ * waiting ksmd to free it.
++ */
++ list_add_tail(&slot->slot_list, &vma_slot_del);
++ } else {
++ /**
++ * It's still on new list. It's ok to free slot directly.
++ */
++ list_del(&slot->slot_list);
++ free_vma_slot(slot);
++ }
++out:
++ vma->uksm_vma_slot = NULL;
++ spin_unlock(&vma_slot_list_lock);
++}
++
++/**
++ * Need to do two things:
++ * 1. check if slot was moved to del list
++ * 2. make sure the mmap_sem is manipulated under valid vma.
++ *
++ * My concern here is that in some cases, this may make
++ * vma_slot_list_lock() waiters to serialized further by some
++ * sem->wait_lock, can this really be expensive?
++ *
++ *
++ * @return
++ * 0: if successfully locked mmap_sem
++ * -ENOENT: this slot was moved to del list
++ * -EBUSY: vma lock failed
++ */
++static int try_down_read_slot_mmap_sem(struct vma_slot *slot)
++{
++ struct vm_area_struct *vma;
++ struct mm_struct *mm;
++ struct rw_semaphore *sem;
++
++ spin_lock(&vma_slot_list_lock);
++
++ /* the slot_list was removed and inited from new list, when it enters
++ * uksm_list. If now it's not empty, then it must be moved to del list
++ */
++ if (!slot_in_uksm(slot)) {
++ spin_unlock(&vma_slot_list_lock);
++ return -ENOENT;
++ }
++
++ BUG_ON(slot->pages != vma_pages(slot->vma));
++ /* Ok, vma still valid */
++ vma = slot->vma;
++ mm = vma->vm_mm;
++ sem = &mm->mmap_lock;
++
++ if (uksm_test_exit(mm)) {
++ spin_unlock(&vma_slot_list_lock);
++ return -ENOENT;
++ }
++
++ if (down_read_trylock(sem)) {
++ spin_unlock(&vma_slot_list_lock);
++ if (slot_pool_alloc(slot)) {
++ uksm_remove_vma(vma);
++ up_read(sem);
++ return -ENOENT;
++ }
++ return 0;
++ }
++
++ spin_unlock(&vma_slot_list_lock);
++ return -EBUSY;
++}
++
++static inline unsigned long
++vma_page_address(struct page *page, struct vm_area_struct *vma)
++{
++ pgoff_t pgoff = page->index;
++ unsigned long address;
++
++ address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
++ if (unlikely(address < vma->vm_start || address >= vma->vm_end)) {
++ /* page should be within @vma mapping range */
++ return -EFAULT;
++ }
++ return address;
++}
++
++
++/* return 0 on success with the item's mmap_sem locked */
++static inline int get_mergeable_page_lock_mmap(struct rmap_item *item)
++{
++ struct mm_struct *mm;
++ struct vma_slot *slot = item->slot;
++ int err = -EINVAL;
++
++ struct page *page;
++
++ /*
++ * try_down_read_slot_mmap_sem() returns non-zero if the slot
++ * has been removed by uksm_remove_vma().
++ */
++ if (try_down_read_slot_mmap_sem(slot))
++ return -EBUSY;
++
++ mm = slot->vma->vm_mm;
++
++ if (uksm_test_exit(mm))
++ goto failout_up;
++
++ page = item->page;
++ rcu_read_lock();
++ if (!get_page_unless_zero(page)) {
++ rcu_read_unlock();
++ goto failout_up;
++ }
++
++ /* No need to consider huge page here. */
++ if (item->slot->vma->anon_vma != page_anon_vma(page) ||
++ vma_page_address(page, item->slot->vma) != get_rmap_addr(item)) {
++ /*
++ * TODO:
++ * should we release this item becase of its stale page
++ * mapping?
++ */
++ put_page(page);
++ rcu_read_unlock();
++ goto failout_up;
++ }
++ rcu_read_unlock();
++ return 0;
++
++failout_up:
++ mmap_read_unlock(mm);
++ return err;
++}
++
++/*
++ * What kind of VMA is considered ?
++ */
++static inline int vma_can_enter(struct vm_area_struct *vma)
++{
++ return uksm_flags_can_scan(vma->vm_flags);
++}
++
++/*
++ * Called whenever a fresh new vma is created A new vma_slot.
++ * is created and inserted into a global list Must be called.
++ * after vma is inserted to its mm.
++ */
++void uksm_vma_add_new(struct vm_area_struct *vma)
++{
++ struct vma_slot *slot;
++
++ if (!vma_can_enter(vma)) {
++ vma->uksm_vma_slot = NULL;
++ return;
++ }
++
++ slot = alloc_vma_slot();
++ if (!slot) {
++ vma->uksm_vma_slot = NULL;
++ return;
++ }
++
++ vma->uksm_vma_slot = slot;
++ vma->vm_flags |= VM_MERGEABLE;
++ slot->vma = vma;
++ slot->mm = vma->vm_mm;
++ slot->ctime_j = jiffies;
++ slot->pages = vma_pages(vma);
++ spin_lock(&vma_slot_list_lock);
++ list_add_tail(&slot->slot_list, &vma_slot_new);
++ spin_unlock(&vma_slot_list_lock);
++}
++
++/* 32/3 < they < 32/2 */
++#define shiftl 8
++#define shiftr 12
++
++#define HASH_FROM_TO(from, to) \
++for (index = from; index < to; index++) { \
++ pos = random_nums[index]; \
++ hash += key[pos]; \
++ hash += (hash << shiftl); \
++ hash ^= (hash >> shiftr); \
++}
++
++
++#define HASH_FROM_DOWN_TO(from, to) \
++for (index = from - 1; index >= to; index--) { \
++ hash ^= (hash >> shiftr); \
++ hash ^= (hash >> (shiftr*2)); \
++ hash -= (hash << shiftl); \
++ hash += (hash << (shiftl*2)); \
++ pos = random_nums[index]; \
++ hash -= key[pos]; \
++}
++
++/*
++ * The main random sample hash function.
++ */
++static u32 random_sample_hash(void *addr, u32 hash_strength)
++{
++ u32 hash = 0xdeadbeef;
++ int index, pos, loop = hash_strength;
++ u32 *key = (u32 *)addr;
++
++ if (loop > HASH_STRENGTH_FULL)
++ loop = HASH_STRENGTH_FULL;
++
++ HASH_FROM_TO(0, loop);
++
++ if (hash_strength > HASH_STRENGTH_FULL) {
++ loop = hash_strength - HASH_STRENGTH_FULL;
++ HASH_FROM_TO(0, loop);
++ }
++
++ return hash;
++}
++
++
++/**
++ * It's used when hash strength is adjusted
++ *
++ * @addr The page's virtual address
++ * @from The original hash strength
++ * @to The hash strength changed to
++ * @hash The hash value generated with "from" hash value
++ *
++ * return the hash value
++ */
++static u32 delta_hash(void *addr, int from, int to, u32 hash)
++{
++ u32 *key = (u32 *)addr;
++ int index, pos; /* make sure they are int type */
++
++ if (to > from) {
++ if (from >= HASH_STRENGTH_FULL) {
++ from -= HASH_STRENGTH_FULL;
++ to -= HASH_STRENGTH_FULL;
++ HASH_FROM_TO(from, to);
++ } else if (to <= HASH_STRENGTH_FULL) {
++ HASH_FROM_TO(from, to);
++ } else {
++ HASH_FROM_TO(from, HASH_STRENGTH_FULL);
++ HASH_FROM_TO(0, to - HASH_STRENGTH_FULL);
++ }
++ } else {
++ if (from <= HASH_STRENGTH_FULL) {
++ HASH_FROM_DOWN_TO(from, to);
++ } else if (to >= HASH_STRENGTH_FULL) {
++ from -= HASH_STRENGTH_FULL;
++ to -= HASH_STRENGTH_FULL;
++ HASH_FROM_DOWN_TO(from, to);
++ } else {
++ HASH_FROM_DOWN_TO(from - HASH_STRENGTH_FULL, 0);
++ HASH_FROM_DOWN_TO(HASH_STRENGTH_FULL, to);
++ }
++ }
++
++ return hash;
++}
++
++/**
++ *
++ * Called when: rshash_pos or rshash_neg is about to overflow or a scan round
++ * has finished.
++ *
++ * return 0 if no page has been scanned since last call, 1 otherwise.
++ */
++static inline int encode_benefit(void)
++{
++ u64 scanned_delta, pos_delta, neg_delta;
++ unsigned long base = benefit.base;
++
++ scanned_delta = uksm_pages_scanned - uksm_pages_scanned_last;
++
++ if (!scanned_delta)
++ return 0;
++
++ scanned_delta >>= base;
++ pos_delta = rshash_pos >> base;
++ neg_delta = rshash_neg >> base;
++
++ if (CAN_OVERFLOW_U64(benefit.pos, pos_delta) ||
++ CAN_OVERFLOW_U64(benefit.neg, neg_delta) ||
++ CAN_OVERFLOW_U64(benefit.scanned, scanned_delta)) {
++ benefit.scanned >>= 1;
++ benefit.neg >>= 1;
++ benefit.pos >>= 1;
++ benefit.base++;
++ scanned_delta >>= 1;
++ pos_delta >>= 1;
++ neg_delta >>= 1;
++ }
++
++ benefit.pos += pos_delta;
++ benefit.neg += neg_delta;
++ benefit.scanned += scanned_delta;
++
++ BUG_ON(!benefit.scanned);
++
++ rshash_pos = rshash_neg = 0;
++ uksm_pages_scanned_last = uksm_pages_scanned;
++
++ return 1;
++}
++
++static inline void reset_benefit(void)
++{
++ benefit.pos = 0;
++ benefit.neg = 0;
++ benefit.base = 0;
++ benefit.scanned = 0;
++}
++
++static inline void inc_rshash_pos(unsigned long delta)
++{
++ if (CAN_OVERFLOW_U64(rshash_pos, delta))
++ encode_benefit();
++
++ rshash_pos += delta;
++}
++
++static inline void inc_rshash_neg(unsigned long delta)
++{
++ if (CAN_OVERFLOW_U64(rshash_neg, delta))
++ encode_benefit();
++
++ rshash_neg += delta;
++}
++
++
++static inline u32 page_hash(struct page *page, unsigned long hash_strength,
++ int cost_accounting)
++{
++ u32 val;
++ unsigned long delta;
++
++ void *addr = kmap_atomic(page);
++
++ val = random_sample_hash(addr, hash_strength);
++ kunmap_atomic(addr);
++
++ if (cost_accounting) {
++ if (hash_strength < HASH_STRENGTH_FULL)
++ delta = HASH_STRENGTH_FULL - hash_strength;
++ else
++ delta = 0;
++
++ inc_rshash_pos(delta);
++ }
++
++ return val;
++}
++
++static int memcmp_pages_with_cost(struct page *page1, struct page *page2,
++ int cost_accounting)
++{
++ char *addr1, *addr2;
++ int ret;
++
++ addr1 = kmap_atomic(page1);
++ addr2 = kmap_atomic(page2);
++ ret = memcmp(addr1, addr2, PAGE_SIZE);
++ kunmap_atomic(addr2);
++ kunmap_atomic(addr1);
++
++ if (cost_accounting)
++ inc_rshash_neg(memcmp_cost);
++
++ return ret;
++}
++
++static inline int pages_identical_with_cost(struct page *page1, struct page *page2)
++{
++ return !memcmp_pages_with_cost(page1, page2, 0);
++}
++
++static inline int is_page_full_zero(struct page *page)
++{
++ char *addr;
++ int ret;
++
++ addr = kmap_atomic(page);
++ ret = is_full_zero(addr, PAGE_SIZE);
++ kunmap_atomic(addr);
++
++ return ret;
++}
++
++static int write_protect_page(struct vm_area_struct *vma, struct page *page,
++ pte_t *orig_pte, pte_t *old_pte)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ struct page_vma_mapped_walk pvmw = {
++ .page = page,
++ .vma = vma,
++ };
++ struct mmu_notifier_range range;
++ int swapped;
++ int err = -EFAULT;
++
++ pvmw.address = page_address_in_vma(page, vma);
++ if (pvmw.address == -EFAULT)
++ goto out;
++
++ BUG_ON(PageTransCompound(page));
++
++ mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm, pvmw.address,
++ pvmw.address + PAGE_SIZE);
++ mmu_notifier_invalidate_range_start(&range);
++
++ if (!page_vma_mapped_walk(&pvmw))
++ goto out_mn;
++ if (WARN_ONCE(!pvmw.pte, "Unexpected PMD mapping?"))
++ goto out_unlock;
++
++ if (old_pte)
++ *old_pte = *pvmw.pte;
++
++ if (pte_write(*pvmw.pte) || pte_dirty(*pvmw.pte) ||
++ (pte_protnone(*pvmw.pte) && pte_savedwrite(*pvmw.pte)) || mm_tlb_flush_pending(mm)) {
++ pte_t entry;
++
++ swapped = PageSwapCache(page);
++ flush_cache_page(vma, pvmw.address, page_to_pfn(page));
++ /*
++ * Ok this is tricky, when get_user_pages_fast() run it doesn't
++ * take any lock, therefore the check that we are going to make
++ * with the pagecount against the mapcount is racey and
++ * O_DIRECT can happen right after the check.
++ * So we clear the pte and flush the tlb before the check
++ * this assure us that no O_DIRECT can happen after the check
++ * or in the middle of the check.
++ */
++ entry = ptep_clear_flush_notify(vma, pvmw.address, pvmw.pte);
++ /*
++ * Check that no O_DIRECT or similar I/O is in progress on the
++ * page
++ */
++ if (page_mapcount(page) + 1 + swapped != page_count(page)) {
++ set_pte_at(mm, pvmw.address, pvmw.pte, entry);
++ goto out_unlock;
++ }
++ if (pte_dirty(entry))
++ set_page_dirty(page);
++
++ if (pte_protnone(entry))
++ entry = pte_mkclean(pte_clear_savedwrite(entry));
++ else
++ entry = pte_mkclean(pte_wrprotect(entry));
++
++ set_pte_at_notify(mm, pvmw.address, pvmw.pte, entry);
++ }
++ *orig_pte = *pvmw.pte;
++ err = 0;
++
++out_unlock:
++ page_vma_mapped_walk_done(&pvmw);
++out_mn:
++ mmu_notifier_invalidate_range_end(&range);
++out:
++ return err;
++}
++
++#define MERGE_ERR_PGERR 1 /* the page is invalid cannot continue */
++#define MERGE_ERR_COLLI 2 /* there is a collision */
++#define MERGE_ERR_COLLI_MAX 3 /* collision at the max hash strength */
++#define MERGE_ERR_CHANGED 4 /* the page has changed since last hash */
++
++
++/**
++ * replace_page - replace page in vma by new ksm page
++ * @vma: vma that holds the pte pointing to page
++ * @page: the page we are replacing by kpage
++ * @kpage: the ksm page we replace page by
++ * @orig_pte: the original value of the pte
++ *
++ * Returns 0 on success, MERGE_ERR_PGERR on failure.
++ */
++static int replace_page(struct vm_area_struct *vma, struct page *page,
++ struct page *kpage, pte_t orig_pte)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ struct mmu_notifier_range range;
++ pgd_t *pgd;
++ p4d_t *p4d;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *ptep;
++ spinlock_t *ptl;
++ pte_t entry;
++
++ unsigned long addr;
++ int err = MERGE_ERR_PGERR;
++
++ addr = page_address_in_vma(page, vma);
++ if (addr == -EFAULT)
++ goto out;
++
++ pgd = pgd_offset(mm, addr);
++ if (!pgd_present(*pgd))
++ goto out;
++
++ p4d = p4d_offset(pgd, addr);
++ pud = pud_offset(p4d, addr);
++ if (!pud_present(*pud))
++ goto out;
++
++ pmd = pmd_offset(pud, addr);
++ BUG_ON(pmd_trans_huge(*pmd));
++ if (!pmd_present(*pmd))
++ goto out;
++
++ mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm, addr,
++ addr + PAGE_SIZE);
++ mmu_notifier_invalidate_range_start(&range);
++
++ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
++ if (!pte_same(*ptep, orig_pte)) {
++ pte_unmap_unlock(ptep, ptl);
++ goto out_mn;
++ }
++
++ flush_cache_page(vma, addr, pte_pfn(*ptep));
++ ptep_clear_flush_notify(vma, addr, ptep);
++ entry = mk_pte(kpage, vma->vm_page_prot);
++
++ /* special treatment is needed for zero_page */
++ if ((page_to_pfn(kpage) == uksm_zero_pfn) ||
++ (page_to_pfn(kpage) == zero_pfn)) {
++ entry = pte_mkspecial(entry);
++ dec_mm_counter(mm, MM_ANONPAGES);
++ inc_zone_page_state(page, NR_UKSM_ZERO_PAGES);
++ } else {
++ get_page(kpage);
++ page_add_anon_rmap(kpage, vma, addr, false);
++ }
++
++ set_pte_at_notify(mm, addr, ptep, entry);
++
++ page_remove_rmap(page, false);
++ if (!page_mapped(page))
++ try_to_free_swap(page);
++ put_page(page);
++
++ pte_unmap_unlock(ptep, ptl);
++ err = 0;
++out_mn:
++ mmu_notifier_invalidate_range_end(&range);
++out:
++ return err;
++}
++
++
++/**
++ * Fully hash a page with HASH_STRENGTH_MAX return a non-zero hash value. The
++ * zero hash value at HASH_STRENGTH_MAX is used to indicated that its
++ * hash_max member has not been calculated.
++ *
++ * @page The page needs to be hashed
++ * @hash_old The hash value calculated with current hash strength
++ *
++ * return the new hash value calculated at HASH_STRENGTH_MAX
++ */
++static inline u32 page_hash_max(struct page *page, u32 hash_old)
++{
++ u32 hash_max = 0;
++ void *addr;
++
++ addr = kmap_atomic(page);
++ hash_max = delta_hash(addr, hash_strength,
++ HASH_STRENGTH_MAX, hash_old);
++
++ kunmap_atomic(addr);
++
++ if (!hash_max)
++ hash_max = 1;
++
++ inc_rshash_neg(HASH_STRENGTH_MAX - hash_strength);
++ return hash_max;
++}
++
++/*
++ * We compare the hash again, to ensure that it is really a hash collision
++ * instead of being caused by page write.
++ */
++static inline int check_collision(struct rmap_item *rmap_item,
++ u32 hash)
++{
++ int err;
++ struct page *page = rmap_item->page;
++
++ /* if this rmap_item has already been hash_maxed, then the collision
++ * must appears in the second-level rbtree search. In this case we check
++ * if its hash_max value has been changed. Otherwise, the collision
++ * happens in the first-level rbtree search, so we check against it's
++ * current hash value.
++ */
++ if (rmap_item->hash_max) {
++ inc_rshash_neg(memcmp_cost);
++ inc_rshash_neg(HASH_STRENGTH_MAX - hash_strength);
++
++ if (rmap_item->hash_max == page_hash_max(page, hash))
++ err = MERGE_ERR_COLLI;
++ else
++ err = MERGE_ERR_CHANGED;
++ } else {
++ inc_rshash_neg(memcmp_cost + hash_strength);
++
++ if (page_hash(page, hash_strength, 0) == hash)
++ err = MERGE_ERR_COLLI;
++ else
++ err = MERGE_ERR_CHANGED;
++ }
++
++ return err;
++}
++
++/**
++ * Try to merge a rmap_item.page with a kpage in stable node. kpage must
++ * already be a ksm page.
++ *
++ * @return 0 if the pages were merged, -EFAULT otherwise.
++ */
++static int try_to_merge_with_uksm_page(struct rmap_item *rmap_item,
++ struct page *kpage, u32 hash)
++{
++ struct vm_area_struct *vma = rmap_item->slot->vma;
++ struct mm_struct *mm = vma->vm_mm;
++ pte_t orig_pte = __pte(0);
++ int err = MERGE_ERR_PGERR;
++ struct page *page;
++
++ if (uksm_test_exit(mm))
++ goto out;
++
++ page = rmap_item->page;
++
++ if (page == kpage) { /* ksm page forked */
++ err = 0;
++ goto out;
++ }
++
++ /*
++ * We need the page lock to read a stable PageSwapCache in
++ * write_protect_page(). We use trylock_page() instead of
++ * lock_page() because we don't want to wait here - we
++ * prefer to continue scanning and merging different pages,
++ * then come back to this page when it is unlocked.
++ */
++ if (!trylock_page(page))
++ goto out;
++
++ if (!PageAnon(page) || !PageKsm(kpage))
++ goto out_unlock;
++
++ if (PageTransCompound(page)) {
++ err = split_huge_page(page);
++ if (err)
++ goto out_unlock;
++ }
++
++ /*
++ * If this anonymous page is mapped only here, its pte may need
++ * to be write-protected. If it's mapped elsewhere, all of its
++ * ptes are necessarily already write-protected. But in either
++ * case, we need to lock and check page_count is not raised.
++ */
++ if (write_protect_page(vma, page, &orig_pte, NULL) == 0) {
++ if (pages_identical_with_cost(page, kpage))
++ err = replace_page(vma, page, kpage, orig_pte);
++ else
++ err = check_collision(rmap_item, hash);
++ }
++
++ if ((vma->vm_flags & VM_LOCKED) && kpage && !err) {
++ munlock_vma_page(page);
++ if (!PageMlocked(kpage)) {
++ unlock_page(page);
++ lock_page(kpage);
++ mlock_vma_page(kpage);
++ page = kpage; /* for final unlock */
++ }
++ }
++
++out_unlock:
++ unlock_page(page);
++out:
++ return err;
++}
++
++
++
++/**
++ * If two pages fail to merge in try_to_merge_two_pages, then we have a chance
++ * to restore a page mapping that has been changed in try_to_merge_two_pages.
++ *
++ * @return 0 on success.
++ */
++static int restore_uksm_page_pte(struct vm_area_struct *vma, unsigned long addr,
++ pte_t orig_pte, pte_t wprt_pte)
++{
++ struct mm_struct *mm = vma->vm_mm;
++ pgd_t *pgd;
++ p4d_t *p4d;
++ pud_t *pud;
++ pmd_t *pmd;
++ pte_t *ptep;
++ spinlock_t *ptl;
++
++ int err = -EFAULT;
++
++ pgd = pgd_offset(mm, addr);
++ if (!pgd_present(*pgd))
++ goto out;
++
++ p4d = p4d_offset(pgd, addr);
++ pud = pud_offset(p4d, addr);
++ if (!pud_present(*pud))
++ goto out;
++
++ pmd = pmd_offset(pud, addr);
++ if (!pmd_present(*pmd))
++ goto out;
++
++ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
++ if (!pte_same(*ptep, wprt_pte)) {
++ /* already copied, let it be */
++ pte_unmap_unlock(ptep, ptl);
++ goto out;
++ }
++
++ /*
++ * Good boy, still here. When we still get the ksm page, it does not
++ * return to the free page pool, there is no way that a pte was changed
++ * to other page and gets back to this page. And remind that ksm page
++ * do not reuse in do_wp_page(). So it's safe to restore the original
++ * pte.
++ */
++ flush_cache_page(vma, addr, pte_pfn(*ptep));
++ ptep_clear_flush_notify(vma, addr, ptep);
++ set_pte_at_notify(mm, addr, ptep, orig_pte);
++
++ pte_unmap_unlock(ptep, ptl);
++ err = 0;
++out:
++ return err;
++}
++
++/**
++ * try_to_merge_two_pages() - take two identical pages and prepare
++ * them to be merged into one page(rmap_item->page)
++ *
++ * @return 0 if we successfully merged two identical pages into
++ * one ksm page. MERGE_ERR_COLLI if it's only a hash collision
++ * search in rbtree. MERGE_ERR_CHANGED if rmap_item has been
++ * changed since it's hashed. MERGE_ERR_PGERR otherwise.
++ *
++ */
++static int try_to_merge_two_pages(struct rmap_item *rmap_item,
++ struct rmap_item *tree_rmap_item,
++ u32 hash)
++{
++ pte_t orig_pte1 = __pte(0), orig_pte2 = __pte(0);
++ pte_t wprt_pte1 = __pte(0), wprt_pte2 = __pte(0);
++ struct vm_area_struct *vma1 = rmap_item->slot->vma;
++ struct vm_area_struct *vma2 = tree_rmap_item->slot->vma;
++ struct page *page = rmap_item->page;
++ struct page *tree_page = tree_rmap_item->page;
++ int err = MERGE_ERR_PGERR;
++ struct address_space *saved_mapping;
++
++
++ if (rmap_item->page == tree_rmap_item->page)
++ goto out;
++
++ if (!trylock_page(page))
++ goto out;
++
++ if (!PageAnon(page))
++ goto out_unlock;
++
++ if (PageTransCompound(page)) {
++ err = split_huge_page(page);
++ if (err)
++ goto out_unlock;
++ }
++
++ if (write_protect_page(vma1, page, &wprt_pte1, &orig_pte1) != 0) {
++ unlock_page(page);
++ goto out;
++ }
++
++ /*
++ * While we hold page lock, upgrade page from
++ * PageAnon+anon_vma to PageKsm+NULL stable_node:
++ * stable_tree_insert() will update stable_node.
++ */
++ saved_mapping = page->mapping;
++ set_page_stable_node(page, NULL);
++ mark_page_accessed(page);
++ if (!PageDirty(page))
++ SetPageDirty(page);
++
++ unlock_page(page);
++
++ if (!trylock_page(tree_page))
++ goto restore_out;
++
++ if (!PageAnon(tree_page)) {
++ unlock_page(tree_page);
++ goto restore_out;
++ }
++
++ if (PageTransCompound(tree_page)) {
++ err = split_huge_page(tree_page);
++ if (err) {
++ unlock_page(tree_page);
++ goto restore_out;
++ }
++ }
++
++ if (write_protect_page(vma2, tree_page, &wprt_pte2, &orig_pte2) != 0) {
++ unlock_page(tree_page);
++ goto restore_out;
++ }
++
++ if (pages_identical_with_cost(page, tree_page)) {
++ err = replace_page(vma2, tree_page, page, wprt_pte2);
++ if (err) {
++ unlock_page(tree_page);
++ goto restore_out;
++ }
++
++ if ((vma2->vm_flags & VM_LOCKED)) {
++ munlock_vma_page(tree_page);
++ if (!PageMlocked(page)) {
++ unlock_page(tree_page);
++ lock_page(page);
++ mlock_vma_page(page);
++ tree_page = page; /* for final unlock */
++ }
++ }
++
++ unlock_page(tree_page);
++
++ goto out; /* success */
++
++ } else {
++ if (tree_rmap_item->hash_max &&
++ tree_rmap_item->hash_max == rmap_item->hash_max) {
++ err = MERGE_ERR_COLLI_MAX;
++ } else if (page_hash(page, hash_strength, 0) ==
++ page_hash(tree_page, hash_strength, 0)) {
++ inc_rshash_neg(memcmp_cost + hash_strength * 2);
++ err = MERGE_ERR_COLLI;
++ } else {
++ err = MERGE_ERR_CHANGED;
++ }
++
++ unlock_page(tree_page);
++ }
++
++restore_out:
++ lock_page(page);
++ if (!restore_uksm_page_pte(vma1, get_rmap_addr(rmap_item),
++ orig_pte1, wprt_pte1))
++ page->mapping = saved_mapping;
++
++out_unlock:
++ unlock_page(page);
++out:
++ return err;
++}
++
++static inline int hash_cmp(u32 new_val, u32 node_val)
++{
++ if (new_val > node_val)
++ return 1;
++ else if (new_val < node_val)
++ return -1;
++ else
++ return 0;
++}
++
++static inline u32 rmap_item_hash_max(struct rmap_item *item, u32 hash)
++{
++ u32 hash_max = item->hash_max;
++
++ if (!hash_max) {
++ hash_max = page_hash_max(item->page, hash);
++
++ item->hash_max = hash_max;
++ }
++
++ return hash_max;
++}
++
++
++
++/**
++ * stable_tree_search() - search the stable tree for a page
++ *
++ * @item: the rmap_item we are comparing with
++ * @hash: the hash value of this item->page already calculated
++ *
++ * @return the page we have found, NULL otherwise. The page returned has
++ * been gotten.
++ */
++static struct page *stable_tree_search(struct rmap_item *item, u32 hash)
++{
++ struct rb_node *node = root_stable_treep->rb_node;
++ struct tree_node *tree_node;
++ unsigned long hash_max;
++ struct page *page = item->page;
++ struct stable_node *stable_node;
++
++ stable_node = page_stable_node(page);
++ if (stable_node) {
++ /* ksm page forked, that is
++ * if (PageKsm(page) && !in_stable_tree(rmap_item))
++ * it's actually gotten once outside.
++ */
++ get_page(page);
++ return page;
++ }
++
++ while (node) {
++ int cmp;
++
++ tree_node = rb_entry(node, struct tree_node, node);
++
++ cmp = hash_cmp(hash, tree_node->hash);
++
++ if (cmp < 0)
++ node = node->rb_left;
++ else if (cmp > 0)
++ node = node->rb_right;
++ else
++ break;
++ }
++
++ if (!node)
++ return NULL;
++
++ if (tree_node->count == 1) {
++ stable_node = rb_entry(tree_node->sub_root.rb_node,
++ struct stable_node, node);
++ BUG_ON(!stable_node);
++
++ goto get_page_out;
++ }
++
++ /*
++ * ok, we have to search the second
++ * level subtree, hash the page to a
++ * full strength.
++ */
++ node = tree_node->sub_root.rb_node;
++ BUG_ON(!node);
++ hash_max = rmap_item_hash_max(item, hash);
++
++ while (node) {
++ int cmp;
++
++ stable_node = rb_entry(node, struct stable_node, node);
++
++ cmp = hash_cmp(hash_max, stable_node->hash_max);
++
++ if (cmp < 0)
++ node = node->rb_left;
++ else if (cmp > 0)
++ node = node->rb_right;
++ else
++ goto get_page_out;
++ }
++
++ return NULL;
++
++get_page_out:
++ page = get_uksm_page(stable_node, 1, 1);
++ return page;
++}
++
++static int try_merge_rmap_item(struct rmap_item *item,
++ struct page *kpage,
++ struct page *tree_page)
++{
++ struct vm_area_struct *vma = item->slot->vma;
++ struct page_vma_mapped_walk pvmw = {
++ .page = kpage,
++ .vma = vma,
++ };
++
++ pvmw.address = get_rmap_addr(item);
++ if (!page_vma_mapped_walk(&pvmw))
++ return 0;
++
++ if (pte_write(*pvmw.pte)) {
++ /* has changed, abort! */
++ page_vma_mapped_walk_done(&pvmw);
++ return 0;
++ }
++
++ get_page(tree_page);
++ page_add_anon_rmap(tree_page, vma, pvmw.address, false);
++
++ flush_cache_page(vma, pvmw.address, page_to_pfn(kpage));
++ ptep_clear_flush_notify(vma, pvmw.address, pvmw.pte);
++ set_pte_at_notify(vma->vm_mm, pvmw.address, pvmw.pte,
++ mk_pte(tree_page, vma->vm_page_prot));
++
++ page_remove_rmap(kpage, false);
++ put_page(kpage);
++
++ page_vma_mapped_walk_done(&pvmw);
++
++ return 1;
++}
++
++/**
++ * try_to_merge_with_stable_page() - when two rmap_items need to be inserted
++ * into stable tree, the page was found to be identical to a stable ksm page,
++ * this is the last chance we can merge them into one.
++ *
++ * @item1: the rmap_item holding the page which we wanted to insert
++ * into stable tree.
++ * @item2: the other rmap_item we found when unstable tree search
++ * @oldpage: the page currently mapped by the two rmap_items
++ * @tree_page: the page we found identical in stable tree node
++ * @success1: return if item1 is successfully merged
++ * @success2: return if item2 is successfully merged
++ */
++static void try_merge_with_stable(struct rmap_item *item1,
++ struct rmap_item *item2,
++ struct page **kpage,
++ struct page *tree_page,
++ int *success1, int *success2)
++{
++ struct vm_area_struct *vma1 = item1->slot->vma;
++ struct vm_area_struct *vma2 = item2->slot->vma;
++ *success1 = 0;
++ *success2 = 0;
++
++ if (unlikely(*kpage == tree_page)) {
++ /* I don't think this can really happen */
++ pr_warn("UKSM: unexpected condition detected in "
++ "%s -- *kpage == tree_page !\n", __func__);
++ *success1 = 1;
++ *success2 = 1;
++ return;
++ }
++
++ if (!PageAnon(*kpage) || !PageKsm(*kpage))
++ goto failed;
++
++ if (!trylock_page(tree_page))
++ goto failed;
++
++ /* If the oldpage is still ksm and still pointed
++ * to in the right place, and still write protected,
++ * we are confident it's not changed, no need to
++ * memcmp anymore.
++ * be ware, we cannot take nested pte locks,
++ * deadlock risk.
++ */
++ if (!try_merge_rmap_item(item1, *kpage, tree_page))
++ goto unlock_failed;
++
++ /* ok, then vma2, remind that pte1 already set */
++ if (!try_merge_rmap_item(item2, *kpage, tree_page))
++ goto success_1;
++
++ *success2 = 1;
++success_1:
++ *success1 = 1;
++
++
++ if ((*success1 && vma1->vm_flags & VM_LOCKED) ||
++ (*success2 && vma2->vm_flags & VM_LOCKED)) {
++ munlock_vma_page(*kpage);
++ if (!PageMlocked(tree_page))
++ mlock_vma_page(tree_page);
++ }
++
++ /*
++ * We do not need oldpage any more in the caller, so can break the lock
++ * now.
++ */
++ unlock_page(*kpage);
++ *kpage = tree_page; /* Get unlocked outside. */
++ return;
++
++unlock_failed:
++ unlock_page(tree_page);
++failed:
++ return;
++}
++
++static inline void stable_node_hash_max(struct stable_node *node,
++ struct page *page, u32 hash)
++{
++ u32 hash_max = node->hash_max;
++
++ if (!hash_max) {
++ hash_max = page_hash_max(page, hash);
++ node->hash_max = hash_max;
++ }
++}
++
++static inline
++struct stable_node *new_stable_node(struct tree_node *tree_node,
++ struct page *kpage, u32 hash_max)
++{
++ struct stable_node *new_stable_node;
++
++ new_stable_node = alloc_stable_node();
++ if (!new_stable_node)
++ return NULL;
++
++ new_stable_node->kpfn = page_to_pfn(kpage);
++ new_stable_node->hash_max = hash_max;
++ new_stable_node->tree_node = tree_node;
++ set_page_stable_node(kpage, new_stable_node);
++
++ return new_stable_node;
++}
++
++static inline
++struct stable_node *first_level_insert(struct tree_node *tree_node,
++ struct rmap_item *rmap_item,
++ struct rmap_item *tree_rmap_item,
++ struct page **kpage, u32 hash,
++ int *success1, int *success2)
++{
++ int cmp;
++ struct page *tree_page;
++ u32 hash_max = 0;
++ struct stable_node *stable_node, *new_snode;
++ struct rb_node *parent = NULL, **new;
++
++ /* this tree node contains no sub-tree yet */
++ stable_node = rb_entry(tree_node->sub_root.rb_node,
++ struct stable_node, node);
++
++ tree_page = get_uksm_page(stable_node, 1, 0);
++ if (tree_page) {
++ cmp = memcmp_pages_with_cost(*kpage, tree_page, 1);
++ if (!cmp) {
++ try_merge_with_stable(rmap_item, tree_rmap_item, kpage,
++ tree_page, success1, success2);
++ put_page(tree_page);
++ if (!*success1 && !*success2)
++ goto failed;
++
++ return stable_node;
++
++ } else {
++ /*
++ * collision in first level try to create a subtree.
++ * A new node need to be created.
++ */
++ put_page(tree_page);
++
++ stable_node_hash_max(stable_node, tree_page,
++ tree_node->hash);
++ hash_max = rmap_item_hash_max(rmap_item, hash);
++ cmp = hash_cmp(hash_max, stable_node->hash_max);
++
++ parent = &stable_node->node;
++ if (cmp < 0)
++ new = &parent->rb_left;
++ else if (cmp > 0)
++ new = &parent->rb_right;
++ else
++ goto failed;
++ }
++
++ } else {
++ /* the only stable_node deleted, we reuse its tree_node.
++ */
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++ }
++
++ new_snode = new_stable_node(tree_node, *kpage, hash_max);
++ if (!new_snode)
++ goto failed;
++
++ rb_link_node(&new_snode->node, parent, new);
++ rb_insert_color(&new_snode->node, &tree_node->sub_root);
++ tree_node->count++;
++ *success1 = *success2 = 1;
++
++ return new_snode;
++
++failed:
++ return NULL;
++}
++
++static inline
++struct stable_node *stable_subtree_insert(struct tree_node *tree_node,
++ struct rmap_item *rmap_item,
++ struct rmap_item *tree_rmap_item,
++ struct page **kpage, u32 hash,
++ int *success1, int *success2)
++{
++ struct page *tree_page;
++ u32 hash_max;
++ struct stable_node *stable_node, *new_snode;
++ struct rb_node *parent, **new;
++
++research:
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++ BUG_ON(!*new);
++ hash_max = rmap_item_hash_max(rmap_item, hash);
++ while (*new) {
++ int cmp;
++
++ stable_node = rb_entry(*new, struct stable_node, node);
++
++ cmp = hash_cmp(hash_max, stable_node->hash_max);
++
++ if (cmp < 0) {
++ parent = *new;
++ new = &parent->rb_left;
++ } else if (cmp > 0) {
++ parent = *new;
++ new = &parent->rb_right;
++ } else {
++ tree_page = get_uksm_page(stable_node, 1, 0);
++ if (tree_page) {
++ cmp = memcmp_pages_with_cost(*kpage, tree_page, 1);
++ if (!cmp) {
++ try_merge_with_stable(rmap_item,
++ tree_rmap_item, kpage,
++ tree_page, success1, success2);
++
++ put_page(tree_page);
++ if (!*success1 && !*success2)
++ goto failed;
++ /*
++ * successfully merged with a stable
++ * node
++ */
++ return stable_node;
++ } else {
++ put_page(tree_page);
++ goto failed;
++ }
++ } else {
++ /*
++ * stable node may be deleted,
++ * and subtree maybe
++ * restructed, cannot
++ * continue, research it.
++ */
++ if (tree_node->count) {
++ goto research;
++ } else {
++ /* reuse the tree node*/
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++ }
++ }
++ }
++ }
++
++ new_snode = new_stable_node(tree_node, *kpage, hash_max);
++ if (!new_snode)
++ goto failed;
++
++ rb_link_node(&new_snode->node, parent, new);
++ rb_insert_color(&new_snode->node, &tree_node->sub_root);
++ tree_node->count++;
++ *success1 = *success2 = 1;
++
++ return new_snode;
++
++failed:
++ return NULL;
++}
++
++
++/**
++ * stable_tree_insert() - try to insert a merged page in unstable tree to
++ * the stable tree
++ *
++ * @kpage: the page need to be inserted
++ * @hash: the current hash of this page
++ * @rmap_item: the rmap_item being scanned
++ * @tree_rmap_item: the rmap_item found on unstable tree
++ * @success1: return if rmap_item is merged
++ * @success2: return if tree_rmap_item is merged
++ *
++ * @return the stable_node on stable tree if at least one
++ * rmap_item is inserted into stable tree, NULL
++ * otherwise.
++ */
++static struct stable_node *
++stable_tree_insert(struct page **kpage, u32 hash,
++ struct rmap_item *rmap_item,
++ struct rmap_item *tree_rmap_item,
++ int *success1, int *success2)
++{
++ struct rb_node **new = &root_stable_treep->rb_node;
++ struct rb_node *parent = NULL;
++ struct stable_node *stable_node;
++ struct tree_node *tree_node;
++ u32 hash_max = 0;
++
++ *success1 = *success2 = 0;
++
++ while (*new) {
++ int cmp;
++
++ tree_node = rb_entry(*new, struct tree_node, node);
++
++ cmp = hash_cmp(hash, tree_node->hash);
++
++ if (cmp < 0) {
++ parent = *new;
++ new = &parent->rb_left;
++ } else if (cmp > 0) {
++ parent = *new;
++ new = &parent->rb_right;
++ } else
++ break;
++ }
++
++ if (*new) {
++ if (tree_node->count == 1) {
++ stable_node = first_level_insert(tree_node, rmap_item,
++ tree_rmap_item, kpage,
++ hash, success1, success2);
++ } else {
++ stable_node = stable_subtree_insert(tree_node,
++ rmap_item, tree_rmap_item, kpage,
++ hash, success1, success2);
++ }
++ } else {
++
++ /* no tree node found */
++ tree_node = alloc_tree_node(stable_tree_node_listp);
++ if (!tree_node) {
++ stable_node = NULL;
++ goto out;
++ }
++
++ stable_node = new_stable_node(tree_node, *kpage, hash_max);
++ if (!stable_node) {
++ free_tree_node(tree_node);
++ goto out;
++ }
++
++ tree_node->hash = hash;
++ rb_link_node(&tree_node->node, parent, new);
++ rb_insert_color(&tree_node->node, root_stable_treep);
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++
++ rb_link_node(&stable_node->node, parent, new);
++ rb_insert_color(&stable_node->node, &tree_node->sub_root);
++ tree_node->count++;
++ *success1 = *success2 = 1;
++ }
++
++out:
++ return stable_node;
++}
++
++
++/**
++ * get_tree_rmap_item_page() - try to get the page and lock the mmap_sem
++ *
++ * @return 0 on success, -EBUSY if unable to lock the mmap_sem,
++ * -EINVAL if the page mapping has been changed.
++ */
++static inline int get_tree_rmap_item_page(struct rmap_item *tree_rmap_item)
++{
++ int err;
++
++ err = get_mergeable_page_lock_mmap(tree_rmap_item);
++
++ if (err == -EINVAL) {
++ /* its page map has been changed, remove it */
++ remove_rmap_item_from_tree(tree_rmap_item);
++ }
++
++ /* The page is gotten and mmap_sem is locked now. */
++ return err;
++}
++
++
++/**
++ * unstable_tree_search_insert() - search an unstable tree rmap_item with the
++ * same hash value. Get its page and trylock the mmap_sem
++ */
++static inline
++struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item,
++ u32 hash)
++
++{
++ struct rb_node **new = &root_unstable_tree.rb_node;
++ struct rb_node *parent = NULL;
++ struct tree_node *tree_node;
++ u32 hash_max;
++ struct rmap_item *tree_rmap_item;
++
++ while (*new) {
++ int cmp;
++
++ tree_node = rb_entry(*new, struct tree_node, node);
++
++ cmp = hash_cmp(hash, tree_node->hash);
++
++ if (cmp < 0) {
++ parent = *new;
++ new = &parent->rb_left;
++ } else if (cmp > 0) {
++ parent = *new;
++ new = &parent->rb_right;
++ } else
++ break;
++ }
++
++ if (*new) {
++ /* got the tree_node */
++ if (tree_node->count == 1) {
++ tree_rmap_item = rb_entry(tree_node->sub_root.rb_node,
++ struct rmap_item, node);
++ BUG_ON(!tree_rmap_item);
++
++ goto get_page_out;
++ }
++
++ /* well, search the collision subtree */
++ new = &tree_node->sub_root.rb_node;
++ BUG_ON(!*new);
++ hash_max = rmap_item_hash_max(rmap_item, hash);
++
++ while (*new) {
++ int cmp;
++
++ tree_rmap_item = rb_entry(*new, struct rmap_item,
++ node);
++
++ cmp = hash_cmp(hash_max, tree_rmap_item->hash_max);
++ parent = *new;
++ if (cmp < 0)
++ new = &parent->rb_left;
++ else if (cmp > 0)
++ new = &parent->rb_right;
++ else
++ goto get_page_out;
++ }
++ } else {
++ /* alloc a new tree_node */
++ tree_node = alloc_tree_node(&unstable_tree_node_list);
++ if (!tree_node)
++ return NULL;
++
++ tree_node->hash = hash;
++ rb_link_node(&tree_node->node, parent, new);
++ rb_insert_color(&tree_node->node, &root_unstable_tree);
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++ }
++
++ /* did not found even in sub-tree */
++ rmap_item->tree_node = tree_node;
++ rmap_item->address |= UNSTABLE_FLAG;
++ rmap_item->hash_round = uksm_hash_round;
++ rb_link_node(&rmap_item->node, parent, new);
++ rb_insert_color(&rmap_item->node, &tree_node->sub_root);
++
++ uksm_pages_unshared++;
++ return NULL;
++
++get_page_out:
++ if (tree_rmap_item->page == rmap_item->page)
++ return NULL;
++
++ if (get_tree_rmap_item_page(tree_rmap_item))
++ return NULL;
++
++ return tree_rmap_item;
++}
++
++static void hold_anon_vma(struct rmap_item *rmap_item,
++ struct anon_vma *anon_vma)
++{
++ rmap_item->anon_vma = anon_vma;
++ get_anon_vma(anon_vma);
++}
++
++
++/**
++ * stable_tree_append() - append a rmap_item to a stable node. Deduplication
++ * ratio statistics is done in this function.
++ *
++ */
++static void stable_tree_append(struct rmap_item *rmap_item,
++ struct stable_node *stable_node, int logdedup)
++{
++ struct node_vma *node_vma = NULL, *new_node_vma, *node_vma_cont = NULL;
++ unsigned long key = (unsigned long)rmap_item->slot;
++ unsigned long factor = rmap_item->slot->rung->step;
++
++ BUG_ON(!stable_node);
++ rmap_item->address |= STABLE_FLAG;
++
++ if (hlist_empty(&stable_node->hlist)) {
++ uksm_pages_shared++;
++ goto node_vma_new;
++ } else {
++ uksm_pages_sharing++;
++ }
++
++ hlist_for_each_entry(node_vma, &stable_node->hlist, hlist) {
++ if (node_vma->key >= key)
++ break;
++
++ if (logdedup) {
++ node_vma->slot->pages_bemerged += factor;
++ if (list_empty(&node_vma->slot->dedup_list))
++ list_add(&node_vma->slot->dedup_list,
++ &vma_slot_dedup);
++ }
++ }
++
++ if (node_vma) {
++ if (node_vma->key == key) {
++ node_vma_cont = hlist_entry_safe(node_vma->hlist.next, struct node_vma, hlist);
++ goto node_vma_ok;
++ } else if (node_vma->key > key) {
++ node_vma_cont = node_vma;
++ }
++ }
++
++node_vma_new:
++ /* no same vma already in node, alloc a new node_vma */
++ new_node_vma = alloc_node_vma();
++ BUG_ON(!new_node_vma);
++ new_node_vma->head = stable_node;
++ new_node_vma->slot = rmap_item->slot;
++
++ if (!node_vma) {
++ hlist_add_head(&new_node_vma->hlist, &stable_node->hlist);
++ } else if (node_vma->key != key) {
++ if (node_vma->key < key)
++ hlist_add_behind(&new_node_vma->hlist, &node_vma->hlist);
++ else {
++ hlist_add_before(&new_node_vma->hlist,
++ &node_vma->hlist);
++ }
++
++ }
++ node_vma = new_node_vma;
++
++node_vma_ok: /* ok, ready to add to the list */
++ rmap_item->head = node_vma;
++ hlist_add_head(&rmap_item->hlist, &node_vma->rmap_hlist);
++ hold_anon_vma(rmap_item, rmap_item->slot->vma->anon_vma);
++ if (logdedup) {
++ rmap_item->slot->pages_merged++;
++ if (node_vma_cont) {
++ node_vma = node_vma_cont;
++ hlist_for_each_entry_continue(node_vma, hlist) {
++ node_vma->slot->pages_bemerged += factor;
++ if (list_empty(&node_vma->slot->dedup_list))
++ list_add(&node_vma->slot->dedup_list,
++ &vma_slot_dedup);
++ }
++ }
++ }
++}
++
++/*
++ * We use break_ksm to break COW on a ksm page: it's a stripped down
++ *
++ * if (get_user_pages(addr, 1, 1, 1, &page, NULL) == 1)
++ * put_page(page);
++ *
++ * but taking great care only to touch a ksm page, in a VM_MERGEABLE vma,
++ * in case the application has unmapped and remapped mm,addr meanwhile.
++ * Could a ksm page appear anywhere else? Actually yes, in a VM_PFNMAP
++ * mmap of /dev/mem or /dev/kmem, where we would not want to touch it.
++ */
++static int break_ksm(struct vm_area_struct *vma, unsigned long addr)
++{
++ struct page *page;
++ int ret = 0;
++
++ do {
++ cond_resched();
++ page = follow_page(vma, addr, FOLL_GET | FOLL_MIGRATION | FOLL_REMOTE);
++ if (IS_ERR_OR_NULL(page))
++ break;
++ if (PageKsm(page)) {
++ ret = handle_mm_fault(vma, addr,
++ FAULT_FLAG_WRITE | FAULT_FLAG_REMOTE,
++ NULL);
++ } else
++ ret = VM_FAULT_WRITE;
++ put_page(page);
++ } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM)));
++ /*
++ * We must loop because handle_mm_fault() may back out if there's
++ * any difficulty e.g. if pte accessed bit gets updated concurrently.
++ *
++ * VM_FAULT_WRITE is what we have been hoping for: it indicates that
++ * COW has been broken, even if the vma does not permit VM_WRITE;
++ * but note that a concurrent fault might break PageKsm for us.
++ *
++ * VM_FAULT_SIGBUS could occur if we race with truncation of the
++ * backing file, which also invalidates anonymous pages: that's
++ * okay, that truncation will have unmapped the PageKsm for us.
++ *
++ * VM_FAULT_OOM: at the time of writing (late July 2009), setting
++ * aside mem_cgroup limits, VM_FAULT_OOM would only be set if the
++ * current task has TIF_MEMDIE set, and will be OOM killed on return
++ * to user; and ksmd, having no mm, would never be chosen for that.
++ *
++ * But if the mm is in a limited mem_cgroup, then the fault may fail
++ * with VM_FAULT_OOM even if the current task is not TIF_MEMDIE; and
++ * even ksmd can fail in this way - though it's usually breaking ksm
++ * just to undo a merge it made a moment before, so unlikely to oom.
++ *
++ * That's a pity: we might therefore have more kernel pages allocated
++ * than we're counting as nodes in the stable tree; but uksm_do_scan
++ * will retry to break_cow on each pass, so should recover the page
++ * in due course. The important thing is to not let VM_MERGEABLE
++ * be cleared while any such pages might remain in the area.
++ */
++ return (ret & VM_FAULT_OOM) ? -ENOMEM : 0;
++}
++
++static void break_cow(struct rmap_item *rmap_item)
++{
++ struct vm_area_struct *vma = rmap_item->slot->vma;
++ struct mm_struct *mm = vma->vm_mm;
++ unsigned long addr = get_rmap_addr(rmap_item);
++
++ if (uksm_test_exit(mm))
++ goto out;
++
++ break_ksm(vma, addr);
++out:
++ return;
++}
++
++/*
++ * Though it's very tempting to unmerge in_stable_tree(rmap_item)s rather
++ * than check every pte of a given vma, the locking doesn't quite work for
++ * that - an rmap_item is assigned to the stable tree after inserting ksm
++ * page and upping mmap_sem. Nor does it fit with the way we skip dup'ing
++ * rmap_items from parent to child at fork time (so as not to waste time
++ * if exit comes before the next scan reaches it).
++ *
++ * Similarly, although we'd like to remove rmap_items (so updating counts
++ * and freeing memory) when unmerging an area, it's easier to leave that
++ * to the next pass of ksmd - consider, for example, how ksmd might be
++ * in cmp_and_merge_page on one of the rmap_items we would be removing.
++ */
++inline int unmerge_uksm_pages(struct vm_area_struct *vma,
++ unsigned long start, unsigned long end)
++{
++ unsigned long addr;
++ int err = 0;
++
++ for (addr = start; addr < end && !err; addr += PAGE_SIZE) {
++ if (uksm_test_exit(vma->vm_mm))
++ break;
++ if (signal_pending(current))
++ err = -ERESTARTSYS;
++ else
++ err = break_ksm(vma, addr);
++ }
++ return err;
++}
++
++static inline void inc_uksm_pages_scanned(void)
++{
++ u64 delta;
++
++
++ if (uksm_pages_scanned == U64_MAX) {
++ encode_benefit();
++
++ delta = uksm_pages_scanned >> pages_scanned_base;
++
++ if (CAN_OVERFLOW_U64(pages_scanned_stored, delta)) {
++ pages_scanned_stored >>= 1;
++ delta >>= 1;
++ pages_scanned_base++;
++ }
++
++ pages_scanned_stored += delta;
++
++ uksm_pages_scanned = uksm_pages_scanned_last = 0;
++ }
++
++ uksm_pages_scanned++;
++}
++
++static inline int find_zero_page_hash(int strength, u32 hash)
++{
++ return (zero_hash_table[strength] == hash);
++}
++
++static
++int cmp_and_merge_zero_page(struct vm_area_struct *vma, struct page *page)
++{
++ struct page *zero_page = empty_uksm_zero_page;
++ struct mm_struct *mm = vma->vm_mm;
++ pte_t orig_pte = __pte(0);
++ int err = -EFAULT;
++
++ if (uksm_test_exit(mm))
++ goto out;
++
++ if (!trylock_page(page))
++ goto out;
++
++ if (!PageAnon(page))
++ goto out_unlock;
++
++ if (PageTransCompound(page)) {
++ err = split_huge_page(page);
++ if (err)
++ goto out_unlock;
++ }
++
++ if (write_protect_page(vma, page, &orig_pte, 0) == 0) {
++ if (is_page_full_zero(page))
++ err = replace_page(vma, page, zero_page, orig_pte);
++ }
++
++out_unlock:
++ unlock_page(page);
++out:
++ return err;
++}
++
++/*
++ * cmp_and_merge_page() - first see if page can be merged into the stable
++ * tree; if not, compare hash to previous and if it's the same, see if page
++ * can be inserted into the unstable tree, or merged with a page already there
++ * and both transferred to the stable tree.
++ *
++ * @page: the page that we are searching identical page to.
++ * @rmap_item: the reverse mapping into the virtual address of this page
++ */
++static void cmp_and_merge_page(struct rmap_item *rmap_item, u32 hash)
++{
++ struct rmap_item *tree_rmap_item;
++ struct page *page;
++ struct page *kpage = NULL;
++ u32 hash_max;
++ int err;
++ unsigned int success1, success2;
++ struct stable_node *snode;
++ int cmp;
++ struct rb_node *parent = NULL, **new;
++
++ remove_rmap_item_from_tree(rmap_item);
++ page = rmap_item->page;
++
++ /* We first start with searching the page inside the stable tree */
++ kpage = stable_tree_search(rmap_item, hash);
++ if (kpage) {
++ err = try_to_merge_with_uksm_page(rmap_item, kpage,
++ hash);
++ if (!err) {
++ /*
++ * The page was successfully merged, add
++ * its rmap_item to the stable tree.
++ * page lock is needed because it's
++ * racing with try_to_unmap_ksm(), etc.
++ */
++ lock_page(kpage);
++ snode = page_stable_node(kpage);
++ stable_tree_append(rmap_item, snode, 1);
++ unlock_page(kpage);
++ put_page(kpage);
++ return; /* success */
++ }
++ put_page(kpage);
++
++ /*
++ * if it's a collision and it has been search in sub-rbtree
++ * (hash_max != 0), we want to abort, because if it is
++ * successfully merged in unstable tree, the collision trends to
++ * happen again.
++ */
++ if (err == MERGE_ERR_COLLI && rmap_item->hash_max)
++ return;
++ }
++
++ tree_rmap_item =
++ unstable_tree_search_insert(rmap_item, hash);
++ if (tree_rmap_item) {
++ err = try_to_merge_two_pages(rmap_item, tree_rmap_item, hash);
++ /*
++ * As soon as we merge this page, we want to remove the
++ * rmap_item of the page we have merged with from the unstable
++ * tree, and insert it instead as new node in the stable tree.
++ */
++ if (!err) {
++ kpage = page;
++ remove_rmap_item_from_tree(tree_rmap_item);
++ lock_page(kpage);
++ snode = stable_tree_insert(&kpage, hash,
++ rmap_item, tree_rmap_item,
++ &success1, &success2);
++
++ /*
++ * Do not log dedup for tree item, it's not counted as
++ * scanned in this round.
++ */
++ if (success2)
++ stable_tree_append(tree_rmap_item, snode, 0);
++
++ /*
++ * The order of these two stable append is important:
++ * we are scanning rmap_item.
++ */
++ if (success1)
++ stable_tree_append(rmap_item, snode, 1);
++
++ /*
++ * The original kpage may be unlocked inside
++ * stable_tree_insert() already. This page
++ * should be unlocked before doing
++ * break_cow().
++ */
++ unlock_page(kpage);
++
++ if (!success1)
++ break_cow(rmap_item);
++
++ if (!success2)
++ break_cow(tree_rmap_item);
++
++ } else if (err == MERGE_ERR_COLLI) {
++ BUG_ON(tree_rmap_item->tree_node->count > 1);
++
++ rmap_item_hash_max(tree_rmap_item,
++ tree_rmap_item->tree_node->hash);
++
++ hash_max = rmap_item_hash_max(rmap_item, hash);
++ cmp = hash_cmp(hash_max, tree_rmap_item->hash_max);
++ parent = &tree_rmap_item->node;
++ if (cmp < 0)
++ new = &parent->rb_left;
++ else if (cmp > 0)
++ new = &parent->rb_right;
++ else
++ goto put_up_out;
++
++ rmap_item->tree_node = tree_rmap_item->tree_node;
++ rmap_item->address |= UNSTABLE_FLAG;
++ rmap_item->hash_round = uksm_hash_round;
++ rb_link_node(&rmap_item->node, parent, new);
++ rb_insert_color(&rmap_item->node,
++ &tree_rmap_item->tree_node->sub_root);
++ rmap_item->tree_node->count++;
++ } else {
++ /*
++ * either one of the page has changed or they collide
++ * at the max hash, we consider them as ill items.
++ */
++ remove_rmap_item_from_tree(tree_rmap_item);
++ }
++put_up_out:
++ put_page(tree_rmap_item->page);
++ mmap_read_unlock(tree_rmap_item->slot->vma->vm_mm);
++ }
++}
++
++
++
++
++static inline unsigned long get_pool_index(struct vma_slot *slot,
++ unsigned long index)
++{
++ unsigned long pool_index;
++
++ pool_index = (sizeof(struct rmap_list_entry *) * index) >> PAGE_SHIFT;
++ if (pool_index >= slot->pool_size)
++ BUG();
++ return pool_index;
++}
++
++static inline unsigned long index_page_offset(unsigned long index)
++{
++ return offset_in_page(sizeof(struct rmap_list_entry *) * index);
++}
++
++static inline
++struct rmap_list_entry *get_rmap_list_entry(struct vma_slot *slot,
++ unsigned long index, int need_alloc)
++{
++ unsigned long pool_index;
++ struct page *page;
++ void *addr;
++
++
++ pool_index = get_pool_index(slot, index);
++ if (!slot->rmap_list_pool[pool_index]) {
++ if (!need_alloc)
++ return NULL;
++
++ page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
++ if (!page)
++ return NULL;
++
++ slot->rmap_list_pool[pool_index] = page;
++ }
++
++ addr = kmap(slot->rmap_list_pool[pool_index]);
++ addr += index_page_offset(index);
++
++ return addr;
++}
++
++static inline void put_rmap_list_entry(struct vma_slot *slot,
++ unsigned long index)
++{
++ unsigned long pool_index;
++
++ pool_index = get_pool_index(slot, index);
++ BUG_ON(!slot->rmap_list_pool[pool_index]);
++ kunmap(slot->rmap_list_pool[pool_index]);
++}
++
++static inline int entry_is_new(struct rmap_list_entry *entry)
++{
++ return !entry->item;
++}
++
++static inline unsigned long get_index_orig_addr(struct vma_slot *slot,
++ unsigned long index)
++{
++ return slot->vma->vm_start + (index << PAGE_SHIFT);
++}
++
++static inline unsigned long get_entry_address(struct rmap_list_entry *entry)
++{
++ unsigned long addr;
++
++ if (is_addr(entry->addr))
++ addr = get_clean_addr(entry->addr);
++ else if (entry->item)
++ addr = get_rmap_addr(entry->item);
++ else
++ BUG();
++
++ return addr;
++}
++
++static inline struct rmap_item *get_entry_item(struct rmap_list_entry *entry)
++{
++ if (is_addr(entry->addr))
++ return NULL;
++
++ return entry->item;
++}
++
++static inline void inc_rmap_list_pool_count(struct vma_slot *slot,
++ unsigned long index)
++{
++ unsigned long pool_index;
++
++ pool_index = get_pool_index(slot, index);
++ BUG_ON(!slot->rmap_list_pool[pool_index]);
++ slot->pool_counts[pool_index]++;
++}
++
++static inline void dec_rmap_list_pool_count(struct vma_slot *slot,
++ unsigned long index)
++{
++ unsigned long pool_index;
++
++ pool_index = get_pool_index(slot, index);
++ BUG_ON(!slot->rmap_list_pool[pool_index]);
++ BUG_ON(!slot->pool_counts[pool_index]);
++ slot->pool_counts[pool_index]--;
++}
++
++static inline int entry_has_rmap(struct rmap_list_entry *entry)
++{
++ return !is_addr(entry->addr) && entry->item;
++}
++
++static inline void swap_entries(struct rmap_list_entry *entry1,
++ unsigned long index1,
++ struct rmap_list_entry *entry2,
++ unsigned long index2)
++{
++ struct rmap_list_entry tmp;
++
++ /* swapping two new entries is meaningless */
++ BUG_ON(entry_is_new(entry1) && entry_is_new(entry2));
++
++ tmp = *entry1;
++ *entry1 = *entry2;
++ *entry2 = tmp;
++
++ if (entry_has_rmap(entry1))
++ entry1->item->entry_index = index1;
++
++ if (entry_has_rmap(entry2))
++ entry2->item->entry_index = index2;
++
++ if (entry_has_rmap(entry1) && !entry_has_rmap(entry2)) {
++ inc_rmap_list_pool_count(entry1->item->slot, index1);
++ dec_rmap_list_pool_count(entry1->item->slot, index2);
++ } else if (!entry_has_rmap(entry1) && entry_has_rmap(entry2)) {
++ inc_rmap_list_pool_count(entry2->item->slot, index2);
++ dec_rmap_list_pool_count(entry2->item->slot, index1);
++ }
++}
++
++static inline void free_entry_item(struct rmap_list_entry *entry)
++{
++ unsigned long index;
++ struct rmap_item *item;
++
++ if (!is_addr(entry->addr)) {
++ BUG_ON(!entry->item);
++ item = entry->item;
++ entry->addr = get_rmap_addr(item);
++ set_is_addr(entry->addr);
++ index = item->entry_index;
++ remove_rmap_item_from_tree(item);
++ dec_rmap_list_pool_count(item->slot, index);
++ free_rmap_item(item);
++ }
++}
++
++static inline int pool_entry_boundary(unsigned long index)
++{
++ unsigned long linear_addr;
++
++ linear_addr = sizeof(struct rmap_list_entry *) * index;
++ return index && !offset_in_page(linear_addr);
++}
++
++static inline void try_free_last_pool(struct vma_slot *slot,
++ unsigned long index)
++{
++ unsigned long pool_index;
++
++ pool_index = get_pool_index(slot, index);
++ if (slot->rmap_list_pool[pool_index] &&
++ !slot->pool_counts[pool_index]) {
++ __free_page(slot->rmap_list_pool[pool_index]);
++ slot->rmap_list_pool[pool_index] = NULL;
++ slot->flags |= UKSM_SLOT_NEED_SORT;
++ }
++
++}
++
++static inline unsigned long vma_item_index(struct vm_area_struct *vma,
++ struct rmap_item *item)
++{
++ return (get_rmap_addr(item) - vma->vm_start) >> PAGE_SHIFT;
++}
++
++static int within_same_pool(struct vma_slot *slot,
++ unsigned long i, unsigned long j)
++{
++ unsigned long pool_i, pool_j;
++
++ pool_i = get_pool_index(slot, i);
++ pool_j = get_pool_index(slot, j);
++
++ return (pool_i == pool_j);
++}
++
++static void sort_rmap_entry_list(struct vma_slot *slot)
++{
++ unsigned long i, j;
++ struct rmap_list_entry *entry, *swap_entry;
++
++ entry = get_rmap_list_entry(slot, 0, 0);
++ for (i = 0; i < slot->pages; ) {
++
++ if (!entry)
++ goto skip_whole_pool;
++
++ if (entry_is_new(entry))
++ goto next_entry;
++
++ if (is_addr(entry->addr)) {
++ entry->addr = 0;
++ goto next_entry;
++ }
++
++ j = vma_item_index(slot->vma, entry->item);
++ if (j == i)
++ goto next_entry;
++
++ if (within_same_pool(slot, i, j))
++ swap_entry = entry + j - i;
++ else
++ swap_entry = get_rmap_list_entry(slot, j, 1);
++
++ swap_entries(entry, i, swap_entry, j);
++ if (!within_same_pool(slot, i, j))
++ put_rmap_list_entry(slot, j);
++ continue;
++
++skip_whole_pool:
++ i += PAGE_SIZE / sizeof(*entry);
++ if (i < slot->pages)
++ entry = get_rmap_list_entry(slot, i, 0);
++ continue;
++
++next_entry:
++ if (i >= slot->pages - 1 ||
++ !within_same_pool(slot, i, i + 1)) {
++ put_rmap_list_entry(slot, i);
++ if (i + 1 < slot->pages)
++ entry = get_rmap_list_entry(slot, i + 1, 0);
++ } else
++ entry++;
++ i++;
++ continue;
++ }
++
++ /* free empty pool entries which contain no rmap_item */
++ /* CAN be simplied to based on only pool_counts when bug freed !!!!! */
++ for (i = 0; i < slot->pool_size; i++) {
++ unsigned char has_rmap;
++ void *addr;
++
++ if (!slot->rmap_list_pool[i])
++ continue;
++
++ has_rmap = 0;
++ addr = kmap(slot->rmap_list_pool[i]);
++ BUG_ON(!addr);
++ for (j = 0; j < PAGE_SIZE / sizeof(*entry); j++) {
++ entry = (struct rmap_list_entry *)addr + j;
++ if (is_addr(entry->addr))
++ continue;
++ if (!entry->item)
++ continue;
++ has_rmap = 1;
++ }
++ kunmap(slot->rmap_list_pool[i]);
++ if (!has_rmap) {
++ BUG_ON(slot->pool_counts[i]);
++ __free_page(slot->rmap_list_pool[i]);
++ slot->rmap_list_pool[i] = NULL;
++ }
++ }
++
++ slot->flags &= ~UKSM_SLOT_NEED_SORT;
++}
++
++/*
++ * vma_fully_scanned() - if all the pages in this slot have been scanned.
++ */
++static inline int vma_fully_scanned(struct vma_slot *slot)
++{
++ return slot->pages_scanned == slot->pages;
++}
++
++/**
++ * get_next_rmap_item() - Get the next rmap_item in a vma_slot according to
++ * its random permutation. This function is embedded with the random
++ * permutation index management code.
++ */
++static struct rmap_item *get_next_rmap_item(struct vma_slot *slot, u32 *hash)
++{
++ unsigned long rand_range, addr, swap_index, scan_index;
++ struct rmap_item *item = NULL;
++ struct rmap_list_entry *scan_entry, *swap_entry = NULL;
++ struct page *page;
++
++ scan_index = swap_index = slot->pages_scanned % slot->pages;
++
++ if (pool_entry_boundary(scan_index))
++ try_free_last_pool(slot, scan_index - 1);
++
++ if (vma_fully_scanned(slot)) {
++ if (slot->flags & UKSM_SLOT_NEED_SORT)
++ slot->flags |= UKSM_SLOT_NEED_RERAND;
++ else
++ slot->flags &= ~UKSM_SLOT_NEED_RERAND;
++ if (slot->flags & UKSM_SLOT_NEED_SORT)
++ sort_rmap_entry_list(slot);
++ }
++
++ scan_entry = get_rmap_list_entry(slot, scan_index, 1);
++ if (!scan_entry)
++ return NULL;
++
++ if (entry_is_new(scan_entry)) {
++ scan_entry->addr = get_index_orig_addr(slot, scan_index);
++ set_is_addr(scan_entry->addr);
++ }
++
++ if (slot->flags & UKSM_SLOT_NEED_RERAND) {
++ rand_range = slot->pages - scan_index;
++ BUG_ON(!rand_range);
++ swap_index = scan_index + (prandom_u32() % rand_range);
++ }
++
++ if (swap_index != scan_index) {
++ swap_entry = get_rmap_list_entry(slot, swap_index, 1);
++
++ if (!swap_entry)
++ return NULL;
++
++ if (entry_is_new(swap_entry)) {
++ swap_entry->addr = get_index_orig_addr(slot,
++ swap_index);
++ set_is_addr(swap_entry->addr);
++ }
++ swap_entries(scan_entry, scan_index, swap_entry, swap_index);
++ }
++
++ addr = get_entry_address(scan_entry);
++ item = get_entry_item(scan_entry);
++ BUG_ON(addr > slot->vma->vm_end || addr < slot->vma->vm_start);
++
++ page = follow_page(slot->vma, addr, FOLL_GET);
++ if (IS_ERR_OR_NULL(page))
++ goto nopage;
++
++ if (!PageAnon(page))
++ goto putpage;
++
++ /*check is zero_page pfn or uksm_zero_page*/
++ if ((page_to_pfn(page) == zero_pfn)
++ || (page_to_pfn(page) == uksm_zero_pfn))
++ goto putpage;
++
++ flush_anon_page(slot->vma, page, addr);
++ flush_dcache_page(page);
++
++
++ *hash = page_hash(page, hash_strength, 1);
++ inc_uksm_pages_scanned();
++ /*if the page content all zero, re-map to zero-page*/
++ if (find_zero_page_hash(hash_strength, *hash)) {
++ if (!cmp_and_merge_zero_page(slot->vma, page)) {
++ slot->pages_merged++;
++
++ /* For full-zero pages, no need to create rmap item */
++ goto putpage;
++ } else {
++ inc_rshash_neg(memcmp_cost / 2);
++ }
++ }
++
++ if (!item) {
++ item = alloc_rmap_item();
++ if (item) {
++ /* It has already been zeroed */
++ item->slot = slot;
++ item->address = addr;
++ item->entry_index = scan_index;
++ scan_entry->item = item;
++ inc_rmap_list_pool_count(slot, scan_index);
++ } else
++ goto putpage;
++ }
++
++ BUG_ON(item->slot != slot);
++ /* the page may have changed */
++ item->page = page;
++ put_rmap_list_entry(slot, scan_index);
++ if (swap_entry)
++ put_rmap_list_entry(slot, swap_index);
++ return item;
++
++putpage:
++ put_page(page);
++ page = NULL;
++nopage:
++ /* no page, store addr back and free rmap_item if possible */
++ free_entry_item(scan_entry);
++ put_rmap_list_entry(slot, scan_index);
++ if (swap_entry)
++ put_rmap_list_entry(slot, swap_index);
++ return NULL;
++}
++
++static inline int in_stable_tree(struct rmap_item *rmap_item)
++{
++ return rmap_item->address & STABLE_FLAG;
++}
++
++/**
++ * scan_vma_one_page() - scan the next page in a vma_slot. Called with
++ * mmap_sem locked.
++ */
++static noinline void scan_vma_one_page(struct vma_slot *slot)
++{
++ u32 hash;
++ struct mm_struct *mm;
++ struct rmap_item *rmap_item = NULL;
++ struct vm_area_struct *vma = slot->vma;
++
++ mm = vma->vm_mm;
++ BUG_ON(!mm);
++ BUG_ON(!slot);
++
++ rmap_item = get_next_rmap_item(slot, &hash);
++ if (!rmap_item)
++ goto out1;
++
++ if (PageKsm(rmap_item->page) && in_stable_tree(rmap_item))
++ goto out2;
++
++ cmp_and_merge_page(rmap_item, hash);
++out2:
++ put_page(rmap_item->page);
++out1:
++ slot->pages_scanned++;
++ slot->this_sampled++;
++ if (slot->fully_scanned_round != fully_scanned_round)
++ scanned_virtual_pages++;
++
++ if (vma_fully_scanned(slot))
++ slot->fully_scanned_round = fully_scanned_round;
++}
++
++static inline unsigned long rung_get_pages(struct scan_rung *rung)
++{
++ struct slot_tree_node *node;
++
++ if (!rung->vma_root.rnode)
++ return 0;
++
++ node = container_of(rung->vma_root.rnode, struct slot_tree_node, snode);
++
++ return node->size;
++}
++
++#define RUNG_SAMPLED_MIN 3
++
++static inline
++void uksm_calc_rung_step(struct scan_rung *rung,
++ unsigned long page_time, unsigned long ratio)
++{
++ unsigned long sampled, pages;
++
++ /* will be fully scanned ? */
++ if (!rung->cover_msecs) {
++ rung->step = 1;
++ return;
++ }
++
++ sampled = rung->cover_msecs * (NSEC_PER_MSEC / TIME_RATIO_SCALE)
++ * ratio / page_time;
++
++ /*
++ * Before we finsish a scan round and expensive per-round jobs,
++ * we need to have a chance to estimate the per page time. So
++ * the sampled number can not be too small.
++ */
++ if (sampled < RUNG_SAMPLED_MIN)
++ sampled = RUNG_SAMPLED_MIN;
++
++ pages = rung_get_pages(rung);
++ if (likely(pages > sampled))
++ rung->step = pages / sampled;
++ else
++ rung->step = 1;
++}
++
++static inline int step_need_recalc(struct scan_rung *rung)
++{
++ unsigned long pages, stepmax;
++
++ pages = rung_get_pages(rung);
++ stepmax = pages / RUNG_SAMPLED_MIN;
++
++ return pages && (rung->step > pages ||
++ (stepmax && rung->step > stepmax));
++}
++
++static inline
++void reset_current_scan(struct scan_rung *rung, int finished, int step_recalc)
++{
++ struct vma_slot *slot;
++
++ if (finished)
++ rung->flags |= UKSM_RUNG_ROUND_FINISHED;
++
++ if (step_recalc || step_need_recalc(rung)) {
++ uksm_calc_rung_step(rung, uksm_ema_page_time, rung->cpu_ratio);
++ BUG_ON(step_need_recalc(rung));
++ }
++
++ slot_iter_index = prandom_u32() % rung->step;
++ BUG_ON(!rung->vma_root.rnode);
++ slot = sradix_tree_next(&rung->vma_root, NULL, 0, slot_iter);
++ BUG_ON(!slot);
++
++ rung->current_scan = slot;
++ rung->current_offset = slot_iter_index;
++}
++
++static inline struct sradix_tree_root *slot_get_root(struct vma_slot *slot)
++{
++ return &slot->rung->vma_root;
++}
++
++/*
++ * return if resetted.
++ */
++static int advance_current_scan(struct scan_rung *rung)
++{
++ unsigned short n;
++ struct vma_slot *slot, *next = NULL;
++
++ BUG_ON(!rung->vma_root.num);
++
++ slot = rung->current_scan;
++ n = (slot->pages - rung->current_offset) % rung->step;
++ slot_iter_index = rung->step - n;
++ next = sradix_tree_next(&rung->vma_root, slot->snode,
++ slot->sindex, slot_iter);
++
++ if (next) {
++ rung->current_offset = slot_iter_index;
++ rung->current_scan = next;
++ return 0;
++ } else {
++ reset_current_scan(rung, 1, 0);
++ return 1;
++ }
++}
++
++static inline void rung_rm_slot(struct vma_slot *slot)
++{
++ struct scan_rung *rung = slot->rung;
++ struct sradix_tree_root *root;
++
++ if (rung->current_scan == slot)
++ advance_current_scan(rung);
++
++ root = slot_get_root(slot);
++ sradix_tree_delete_from_leaf(root, slot->snode, slot->sindex);
++ slot->snode = NULL;
++ if (step_need_recalc(rung)) {
++ uksm_calc_rung_step(rung, uksm_ema_page_time, rung->cpu_ratio);
++ BUG_ON(step_need_recalc(rung));
++ }
++
++ /* In case advance_current_scan loop back to this slot again */
++ if (rung->vma_root.num && rung->current_scan == slot)
++ reset_current_scan(slot->rung, 1, 0);
++}
++
++static inline void rung_add_new_slots(struct scan_rung *rung,
++ struct vma_slot **slots, unsigned long num)
++{
++ int err;
++ struct vma_slot *slot;
++ unsigned long i;
++ struct sradix_tree_root *root = &rung->vma_root;
++
++ err = sradix_tree_enter(root, (void **)slots, num);
++ BUG_ON(err);
++
++ for (i = 0; i < num; i++) {
++ slot = slots[i];
++ slot->rung = rung;
++ BUG_ON(vma_fully_scanned(slot));
++ }
++
++ if (rung->vma_root.num == num)
++ reset_current_scan(rung, 0, 1);
++}
++
++static inline int rung_add_one_slot(struct scan_rung *rung,
++ struct vma_slot *slot)
++{
++ int err;
++
++ err = sradix_tree_enter(&rung->vma_root, (void **)&slot, 1);
++ if (err)
++ return err;
++
++ slot->rung = rung;
++ if (rung->vma_root.num == 1)
++ reset_current_scan(rung, 0, 1);
++
++ return 0;
++}
++
++/*
++ * Return true if the slot is deleted from its rung.
++ */
++static inline int vma_rung_enter(struct vma_slot *slot, struct scan_rung *rung)
++{
++ struct scan_rung *old_rung = slot->rung;
++ int err;
++
++ if (old_rung == rung)
++ return 0;
++
++ rung_rm_slot(slot);
++ err = rung_add_one_slot(rung, slot);
++ if (err) {
++ err = rung_add_one_slot(old_rung, slot);
++ WARN_ON(err); /* OOPS, badly OOM, we lost this slot */
++ }
++
++ return 1;
++}
++
++static inline int vma_rung_up(struct vma_slot *slot)
++{
++ struct scan_rung *rung;
++
++ rung = slot->rung;
++ if (slot->rung != &uksm_scan_ladder[SCAN_LADDER_SIZE-1])
++ rung++;
++
++ return vma_rung_enter(slot, rung);
++}
++
++static inline int vma_rung_down(struct vma_slot *slot)
++{
++ struct scan_rung *rung;
++
++ rung = slot->rung;
++ if (slot->rung != &uksm_scan_ladder[0])
++ rung--;
++
++ return vma_rung_enter(slot, rung);
++}
++
++/**
++ * cal_dedup_ratio() - Calculate the deduplication ratio for this slot.
++ */
++static unsigned long cal_dedup_ratio(struct vma_slot *slot)
++{
++ unsigned long ret;
++ unsigned long pages;
++
++ pages = slot->this_sampled;
++ if (!pages)
++ return 0;
++
++ BUG_ON(slot->pages_scanned == slot->last_scanned);
++
++ ret = slot->pages_merged;
++
++ /* Thrashing area filtering */
++ if (ret && uksm_thrash_threshold) {
++ if (slot->pages_cowed * 100 / slot->pages_merged
++ > uksm_thrash_threshold) {
++ ret = 0;
++ } else {
++ ret = slot->pages_merged - slot->pages_cowed;
++ }
++ }
++
++ return ret * 100 / pages;
++}
++
++/**
++ * cal_dedup_ratio() - Calculate the deduplication ratio for this slot.
++ */
++static unsigned long cal_dedup_ratio_old(struct vma_slot *slot)
++{
++ unsigned long ret;
++ unsigned long pages;
++
++ pages = slot->pages;
++ if (!pages)
++ return 0;
++
++ ret = slot->pages_bemerged;
++
++ /* Thrashing area filtering */
++ if (ret && uksm_thrash_threshold) {
++ if (slot->pages_cowed * 100 / slot->pages_bemerged
++ > uksm_thrash_threshold) {
++ ret = 0;
++ } else {
++ ret = slot->pages_bemerged - slot->pages_cowed;
++ }
++ }
++
++ return ret * 100 / pages;
++}
++
++/**
++ * stable_node_reinsert() - When the hash_strength has been adjusted, the
++ * stable tree need to be restructured, this is the function re-inserting the
++ * stable node.
++ */
++static inline void stable_node_reinsert(struct stable_node *new_node,
++ struct page *page,
++ struct rb_root *root_treep,
++ struct list_head *tree_node_listp,
++ u32 hash)
++{
++ struct rb_node **new = &root_treep->rb_node;
++ struct rb_node *parent = NULL;
++ struct stable_node *stable_node;
++ struct tree_node *tree_node;
++ struct page *tree_page;
++ int cmp;
++
++ while (*new) {
++ int cmp;
++
++ tree_node = rb_entry(*new, struct tree_node, node);
++
++ cmp = hash_cmp(hash, tree_node->hash);
++
++ if (cmp < 0) {
++ parent = *new;
++ new = &parent->rb_left;
++ } else if (cmp > 0) {
++ parent = *new;
++ new = &parent->rb_right;
++ } else
++ break;
++ }
++
++ if (*new) {
++ /* find a stable tree node with same first level hash value */
++ stable_node_hash_max(new_node, page, hash);
++ if (tree_node->count == 1) {
++ stable_node = rb_entry(tree_node->sub_root.rb_node,
++ struct stable_node, node);
++ tree_page = get_uksm_page(stable_node, 1, 0);
++ if (tree_page) {
++ stable_node_hash_max(stable_node,
++ tree_page, hash);
++ put_page(tree_page);
++
++ /* prepare for stable node insertion */
++
++ cmp = hash_cmp(new_node->hash_max,
++ stable_node->hash_max);
++ parent = &stable_node->node;
++ if (cmp < 0)
++ new = &parent->rb_left;
++ else if (cmp > 0)
++ new = &parent->rb_right;
++ else
++ goto failed;
++
++ goto add_node;
++ } else {
++ /* the only stable_node deleted, the tree node
++ * was not deleted.
++ */
++ goto tree_node_reuse;
++ }
++ }
++
++ /* well, search the collision subtree */
++ new = &tree_node->sub_root.rb_node;
++ parent = NULL;
++ BUG_ON(!*new);
++ while (*new) {
++ int cmp;
++
++ stable_node = rb_entry(*new, struct stable_node, node);
++
++ cmp = hash_cmp(new_node->hash_max,
++ stable_node->hash_max);
++
++ if (cmp < 0) {
++ parent = *new;
++ new = &parent->rb_left;
++ } else if (cmp > 0) {
++ parent = *new;
++ new = &parent->rb_right;
++ } else {
++ /* oh, no, still a collision */
++ goto failed;
++ }
++ }
++
++ goto add_node;
++ }
++
++ /* no tree node found */
++ tree_node = alloc_tree_node(tree_node_listp);
++ if (!tree_node) {
++ pr_err("UKSM: memory allocation error!\n");
++ goto failed;
++ } else {
++ tree_node->hash = hash;
++ rb_link_node(&tree_node->node, parent, new);
++ rb_insert_color(&tree_node->node, root_treep);
++
++tree_node_reuse:
++ /* prepare for stable node insertion */
++ parent = NULL;
++ new = &tree_node->sub_root.rb_node;
++ }
++
++add_node:
++ rb_link_node(&new_node->node, parent, new);
++ rb_insert_color(&new_node->node, &tree_node->sub_root);
++ new_node->tree_node = tree_node;
++ tree_node->count++;
++ return;
++
++failed:
++ /* This can only happen when two nodes have collided
++ * in two levels.
++ */
++ new_node->tree_node = NULL;
++ return;
++}
++
++static inline void free_all_tree_nodes(struct list_head *list)
++{
++ struct tree_node *node, *tmp;
++
++ list_for_each_entry_safe(node, tmp, list, all_list) {
++ free_tree_node(node);
++ }
++}
++
++/**
++ * stable_tree_delta_hash() - Delta hash the stable tree from previous hash
++ * strength to the current hash_strength. It re-structures the hole tree.
++ */
++static inline void stable_tree_delta_hash(u32 prev_hash_strength)
++{
++ struct stable_node *node, *tmp;
++ struct rb_root *root_new_treep;
++ struct list_head *new_tree_node_listp;
++
++ stable_tree_index = (stable_tree_index + 1) % 2;
++ root_new_treep = &root_stable_tree[stable_tree_index];
++ new_tree_node_listp = &stable_tree_node_list[stable_tree_index];
++ *root_new_treep = RB_ROOT;
++ BUG_ON(!list_empty(new_tree_node_listp));
++
++ /*
++ * we need to be safe, the node could be removed by get_uksm_page()
++ */
++ list_for_each_entry_safe(node, tmp, &stable_node_list, all_list) {
++ void *addr;
++ struct page *node_page;
++ u32 hash;
++
++ /*
++ * We are completely re-structuring the stable nodes to a new
++ * stable tree. We don't want to touch the old tree unlinks and
++ * old tree_nodes. The old tree_nodes will be freed at once.
++ */
++ node_page = get_uksm_page(node, 0, 0);
++ if (!node_page)
++ continue;
++
++ if (node->tree_node) {
++ hash = node->tree_node->hash;
++
++ addr = kmap_atomic(node_page);
++
++ hash = delta_hash(addr, prev_hash_strength,
++ hash_strength, hash);
++ kunmap_atomic(addr);
++ } else {
++ /*
++ *it was not inserted to rbtree due to collision in last
++ *round scan.
++ */
++ hash = page_hash(node_page, hash_strength, 0);
++ }
++
++ stable_node_reinsert(node, node_page, root_new_treep,
++ new_tree_node_listp, hash);
++ put_page(node_page);
++ }
++
++ root_stable_treep = root_new_treep;
++ free_all_tree_nodes(stable_tree_node_listp);
++ BUG_ON(!list_empty(stable_tree_node_listp));
++ stable_tree_node_listp = new_tree_node_listp;
++}
++
++static inline void inc_hash_strength(unsigned long delta)
++{
++ hash_strength += 1 << delta;
++ if (hash_strength > HASH_STRENGTH_MAX)
++ hash_strength = HASH_STRENGTH_MAX;
++}
++
++static inline void dec_hash_strength(unsigned long delta)
++{
++ unsigned long change = 1 << delta;
++
++ if (hash_strength <= change + 1)
++ hash_strength = 1;
++ else
++ hash_strength -= change;
++}
++
++static inline void inc_hash_strength_delta(void)
++{
++ hash_strength_delta++;
++ if (hash_strength_delta > HASH_STRENGTH_DELTA_MAX)
++ hash_strength_delta = HASH_STRENGTH_DELTA_MAX;
++}
++
++static inline unsigned long get_current_neg_ratio(void)
++{
++ u64 pos = benefit.pos;
++ u64 neg = benefit.neg;
++
++ if (!neg)
++ return 0;
++
++ if (!pos || neg > pos)
++ return 100;
++
++ if (neg > div64_u64(U64_MAX, 100))
++ pos = div64_u64(pos, 100);
++ else
++ neg *= 100;
++
++ return div64_u64(neg, pos);
++}
++
++static inline unsigned long get_current_benefit(void)
++{
++ u64 pos = benefit.pos;
++ u64 neg = benefit.neg;
++ u64 scanned = benefit.scanned;
++
++ if (neg > pos)
++ return 0;
++
++ return div64_u64((pos - neg), scanned);
++}
++
++static inline int judge_rshash_direction(void)
++{
++ u64 current_neg_ratio, stable_benefit;
++ u64 current_benefit, delta = 0;
++ int ret = STILL;
++
++ /*
++ * Try to probe a value after the boot, and in case the system
++ * are still for a long time.
++ */
++ if ((fully_scanned_round & 0xFFULL) == 10) {
++ ret = OBSCURE;
++ goto out;
++ }
++
++ current_neg_ratio = get_current_neg_ratio();
++
++ if (current_neg_ratio == 0) {
++ rshash_neg_cont_zero++;
++ if (rshash_neg_cont_zero > 2)
++ return GO_DOWN;
++ else
++ return STILL;
++ }
++ rshash_neg_cont_zero = 0;
++
++ if (current_neg_ratio > 90) {
++ ret = GO_UP;
++ goto out;
++ }
++
++ current_benefit = get_current_benefit();
++ stable_benefit = rshash_state.stable_benefit;
++
++ if (!stable_benefit) {
++ ret = OBSCURE;
++ goto out;
++ }
++
++ if (current_benefit > stable_benefit)
++ delta = current_benefit - stable_benefit;
++ else if (current_benefit < stable_benefit)
++ delta = stable_benefit - current_benefit;
++
++ delta = div64_u64(100 * delta, stable_benefit);
++
++ if (delta > 50) {
++ rshash_cont_obscure++;
++ if (rshash_cont_obscure > 2)
++ return OBSCURE;
++ else
++ return STILL;
++ }
++
++out:
++ rshash_cont_obscure = 0;
++ return ret;
++}
++
++/**
++ * rshash_adjust() - The main function to control the random sampling state
++ * machine for hash strength adapting.
++ *
++ * return true if hash_strength has changed.
++ */
++static inline int rshash_adjust(void)
++{
++ unsigned long prev_hash_strength = hash_strength;
++
++ if (!encode_benefit())
++ return 0;
++
++ switch (rshash_state.state) {
++ case RSHASH_STILL:
++ switch (judge_rshash_direction()) {
++ case GO_UP:
++ if (rshash_state.pre_direct == GO_DOWN)
++ hash_strength_delta = 0;
++
++ inc_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ rshash_state.stable_benefit = get_current_benefit();
++ rshash_state.pre_direct = GO_UP;
++ break;
++
++ case GO_DOWN:
++ if (rshash_state.pre_direct == GO_UP)
++ hash_strength_delta = 0;
++
++ dec_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ rshash_state.stable_benefit = get_current_benefit();
++ rshash_state.pre_direct = GO_DOWN;
++ break;
++
++ case OBSCURE:
++ rshash_state.stable_point = hash_strength;
++ rshash_state.turn_point_down = hash_strength;
++ rshash_state.turn_point_up = hash_strength;
++ rshash_state.turn_benefit_down = get_current_benefit();
++ rshash_state.turn_benefit_up = get_current_benefit();
++ rshash_state.lookup_window_index = 0;
++ rshash_state.state = RSHASH_TRYDOWN;
++ dec_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ break;
++
++ case STILL:
++ break;
++ default:
++ BUG();
++ }
++ break;
++
++ case RSHASH_TRYDOWN:
++ if (rshash_state.lookup_window_index++ % 5 == 0)
++ rshash_state.below_count = 0;
++
++ if (get_current_benefit() < rshash_state.stable_benefit)
++ rshash_state.below_count++;
++ else if (get_current_benefit() >
++ rshash_state.turn_benefit_down) {
++ rshash_state.turn_point_down = hash_strength;
++ rshash_state.turn_benefit_down = get_current_benefit();
++ }
++
++ if (rshash_state.below_count >= 3 ||
++ judge_rshash_direction() == GO_UP ||
++ hash_strength == 1) {
++ hash_strength = rshash_state.stable_point;
++ hash_strength_delta = 0;
++ inc_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ rshash_state.lookup_window_index = 0;
++ rshash_state.state = RSHASH_TRYUP;
++ hash_strength_delta = 0;
++ } else {
++ dec_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ }
++ break;
++
++ case RSHASH_TRYUP:
++ if (rshash_state.lookup_window_index++ % 5 == 0)
++ rshash_state.below_count = 0;
++
++ if (get_current_benefit() < rshash_state.turn_benefit_down)
++ rshash_state.below_count++;
++ else if (get_current_benefit() > rshash_state.turn_benefit_up) {
++ rshash_state.turn_point_up = hash_strength;
++ rshash_state.turn_benefit_up = get_current_benefit();
++ }
++
++ if (rshash_state.below_count >= 3 ||
++ judge_rshash_direction() == GO_DOWN ||
++ hash_strength == HASH_STRENGTH_MAX) {
++ hash_strength = rshash_state.turn_benefit_up >
++ rshash_state.turn_benefit_down ?
++ rshash_state.turn_point_up :
++ rshash_state.turn_point_down;
++
++ rshash_state.state = RSHASH_PRE_STILL;
++ } else {
++ inc_hash_strength(hash_strength_delta);
++ inc_hash_strength_delta();
++ }
++
++ break;
++
++ case RSHASH_NEW:
++ case RSHASH_PRE_STILL:
++ rshash_state.stable_benefit = get_current_benefit();
++ rshash_state.state = RSHASH_STILL;
++ hash_strength_delta = 0;
++ break;
++ default:
++ BUG();
++ }
++
++ /* rshash_neg = rshash_pos = 0; */
++ reset_benefit();
++
++ if (prev_hash_strength != hash_strength)
++ stable_tree_delta_hash(prev_hash_strength);
++
++ return prev_hash_strength != hash_strength;
++}
++
++/**
++ * round_update_ladder() - The main function to do update of all the
++ * adjustments whenever a scan round is finished.
++ */
++static noinline void round_update_ladder(void)
++{
++ int i;
++ unsigned long dedup;
++ struct vma_slot *slot, *tmp_slot;
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++)
++ uksm_scan_ladder[i].flags &= ~UKSM_RUNG_ROUND_FINISHED;
++
++ list_for_each_entry_safe(slot, tmp_slot, &vma_slot_dedup, dedup_list) {
++
++ /* slot may be rung_rm_slot() when mm exits */
++ if (slot->snode) {
++ dedup = cal_dedup_ratio_old(slot);
++ if (dedup && dedup >= uksm_abundant_threshold)
++ vma_rung_up(slot);
++ }
++
++ slot->pages_bemerged = 0;
++ slot->pages_cowed = 0;
++
++ list_del_init(&slot->dedup_list);
++ }
++}
++
++static void uksm_del_vma_slot(struct vma_slot *slot)
++{
++ int i, j;
++ struct rmap_list_entry *entry;
++
++ if (slot->snode) {
++ /*
++ * In case it just failed when entering the rung, it's not
++ * necessary.
++ */
++ rung_rm_slot(slot);
++ }
++
++ if (!list_empty(&slot->dedup_list))
++ list_del(&slot->dedup_list);
++
++ if (!slot->rmap_list_pool || !slot->pool_counts) {
++ /* In case it OOMed in uksm_vma_enter() */
++ goto out;
++ }
++
++ for (i = 0; i < slot->pool_size; i++) {
++ void *addr;
++
++ if (!slot->rmap_list_pool[i])
++ continue;
++
++ addr = kmap(slot->rmap_list_pool[i]);
++ for (j = 0; j < PAGE_SIZE / sizeof(*entry); j++) {
++ entry = (struct rmap_list_entry *)addr + j;
++ if (is_addr(entry->addr))
++ continue;
++ if (!entry->item)
++ continue;
++
++ remove_rmap_item_from_tree(entry->item);
++ free_rmap_item(entry->item);
++ slot->pool_counts[i]--;
++ }
++ BUG_ON(slot->pool_counts[i]);
++ kunmap(slot->rmap_list_pool[i]);
++ __free_page(slot->rmap_list_pool[i]);
++ }
++ kfree(slot->rmap_list_pool);
++ kfree(slot->pool_counts);
++
++out:
++ slot->rung = NULL;
++ if (slot->flags & UKSM_SLOT_IN_UKSM) {
++ BUG_ON(uksm_pages_total < slot->pages);
++ uksm_pages_total -= slot->pages;
++ }
++
++ if (slot->fully_scanned_round == fully_scanned_round)
++ scanned_virtual_pages -= slot->pages;
++ else
++ scanned_virtual_pages -= slot->pages_scanned;
++ free_vma_slot(slot);
++}
++
++
++#define SPIN_LOCK_PERIOD 32
++static struct vma_slot *cleanup_slots[SPIN_LOCK_PERIOD];
++static inline void cleanup_vma_slots(void)
++{
++ struct vma_slot *slot;
++ int i;
++
++ i = 0;
++ spin_lock(&vma_slot_list_lock);
++ while (!list_empty(&vma_slot_del)) {
++ slot = list_entry(vma_slot_del.next,
++ struct vma_slot, slot_list);
++ list_del(&slot->slot_list);
++ cleanup_slots[i++] = slot;
++ if (i == SPIN_LOCK_PERIOD) {
++ spin_unlock(&vma_slot_list_lock);
++ while (--i >= 0)
++ uksm_del_vma_slot(cleanup_slots[i]);
++ i = 0;
++ spin_lock(&vma_slot_list_lock);
++ }
++ }
++ spin_unlock(&vma_slot_list_lock);
++
++ while (--i >= 0)
++ uksm_del_vma_slot(cleanup_slots[i]);
++}
++
++/*
++ * Expotional moving average formula
++ */
++static inline unsigned long ema(unsigned long curr, unsigned long last_ema)
++{
++ /*
++ * For a very high burst, even the ema cannot work well, a false very
++ * high per-page time estimation can result in feedback in very high
++ * overhead of context switch and rung update -- this will then lead
++ * to higher per-paper time, this may not converge.
++ *
++ * Instead, we try to approach this value in a binary manner.
++ */
++ if (curr > last_ema * 10)
++ return last_ema * 2;
++
++ return (EMA_ALPHA * curr + (100 - EMA_ALPHA) * last_ema) / 100;
++}
++
++/*
++ * convert cpu ratio in 1/TIME_RATIO_SCALE configured by user to
++ * nanoseconds based on current uksm_sleep_jiffies.
++ */
++static inline unsigned long cpu_ratio_to_nsec(unsigned int ratio)
++{
++ return NSEC_PER_USEC * jiffies_to_usecs(uksm_sleep_jiffies) /
++ (TIME_RATIO_SCALE - ratio) * ratio;
++}
++
++
++static inline unsigned long rung_real_ratio(int cpu_time_ratio)
++{
++ unsigned long ret;
++
++ BUG_ON(!cpu_time_ratio);
++
++ if (cpu_time_ratio > 0)
++ ret = cpu_time_ratio;
++ else
++ ret = (unsigned long)(-cpu_time_ratio) *
++ uksm_max_cpu_percentage / 100UL;
++
++ return ret ? ret : 1;
++}
++
++static noinline void uksm_calc_scan_pages(void)
++{
++ struct scan_rung *ladder = uksm_scan_ladder;
++ unsigned long sleep_usecs, nsecs;
++ unsigned long ratio;
++ int i;
++ unsigned long per_page;
++
++ if (uksm_ema_page_time > 100000 ||
++ (((unsigned long) uksm_eval_round & (256UL - 1)) == 0UL))
++ uksm_ema_page_time = UKSM_PAGE_TIME_DEFAULT;
++
++ per_page = uksm_ema_page_time;
++ BUG_ON(!per_page);
++
++ /*
++ * For every 8 eval round, we try to probe a uksm_sleep_jiffies value
++ * based on saved user input.
++ */
++ if (((unsigned long) uksm_eval_round & (8UL - 1)) == 0UL)
++ uksm_sleep_jiffies = uksm_sleep_saved;
++
++ /* We require a rung scan at least 1 page in a period. */
++ nsecs = per_page;
++ ratio = rung_real_ratio(ladder[0].cpu_ratio);
++ if (cpu_ratio_to_nsec(ratio) < nsecs) {
++ sleep_usecs = nsecs * (TIME_RATIO_SCALE - ratio) / ratio
++ / NSEC_PER_USEC;
++ uksm_sleep_jiffies = usecs_to_jiffies(sleep_usecs) + 1;
++ }
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ ratio = rung_real_ratio(ladder[i].cpu_ratio);
++ ladder[i].pages_to_scan = cpu_ratio_to_nsec(ratio) /
++ per_page;
++ BUG_ON(!ladder[i].pages_to_scan);
++ uksm_calc_rung_step(&ladder[i], per_page, ratio);
++ }
++}
++
++/*
++ * From the scan time of this round (ns) to next expected min sleep time
++ * (ms), be careful of the possible overflows. ratio is taken from
++ * rung_real_ratio()
++ */
++static inline
++unsigned int scan_time_to_sleep(unsigned long long scan_time, unsigned long ratio)
++{
++ scan_time >>= 20; /* to msec level now */
++ BUG_ON(scan_time > (ULONG_MAX / TIME_RATIO_SCALE));
++
++ return (unsigned int) ((unsigned long) scan_time *
++ (TIME_RATIO_SCALE - ratio) / ratio);
++}
++
++#define __round_mask(x, y) ((__typeof__(x))((y)-1))
++#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
++
++static void uksm_vma_enter(struct vma_slot **slots, unsigned long num)
++{
++ struct scan_rung *rung;
++
++ rung = &uksm_scan_ladder[0];
++ rung_add_new_slots(rung, slots, num);
++}
++
++static struct vma_slot *batch_slots[SLOT_TREE_NODE_STORE_SIZE];
++
++static void uksm_enter_all_slots(void)
++{
++ struct vma_slot *slot;
++ unsigned long index;
++ struct list_head empty_vma_list;
++ int i;
++
++ i = 0;
++ index = 0;
++ INIT_LIST_HEAD(&empty_vma_list);
++
++ spin_lock(&vma_slot_list_lock);
++ while (!list_empty(&vma_slot_new)) {
++ slot = list_entry(vma_slot_new.next,
++ struct vma_slot, slot_list);
++
++ if (!slot->vma->anon_vma) {
++ list_move(&slot->slot_list, &empty_vma_list);
++ } else if (vma_can_enter(slot->vma)) {
++ batch_slots[index++] = slot;
++ list_del_init(&slot->slot_list);
++ } else {
++ list_move(&slot->slot_list, &vma_slot_noadd);
++ }
++
++ if (++i == SPIN_LOCK_PERIOD ||
++ (index && !(index % SLOT_TREE_NODE_STORE_SIZE))) {
++ spin_unlock(&vma_slot_list_lock);
++
++ if (index && !(index % SLOT_TREE_NODE_STORE_SIZE)) {
++ uksm_vma_enter(batch_slots, index);
++ index = 0;
++ }
++ i = 0;
++ cond_resched();
++ spin_lock(&vma_slot_list_lock);
++ }
++ }
++
++ list_splice(&empty_vma_list, &vma_slot_new);
++
++ spin_unlock(&vma_slot_list_lock);
++
++ if (index)
++ uksm_vma_enter(batch_slots, index);
++
++}
++
++static inline int rung_round_finished(struct scan_rung *rung)
++{
++ return rung->flags & UKSM_RUNG_ROUND_FINISHED;
++}
++
++static inline void judge_slot(struct vma_slot *slot)
++{
++ struct scan_rung *rung = slot->rung;
++ unsigned long dedup;
++ int deleted;
++
++ dedup = cal_dedup_ratio(slot);
++ if (vma_fully_scanned(slot) && uksm_thrash_threshold)
++ deleted = vma_rung_enter(slot, &uksm_scan_ladder[0]);
++ else if (dedup && dedup >= uksm_abundant_threshold)
++ deleted = vma_rung_up(slot);
++ else
++ deleted = vma_rung_down(slot);
++
++ slot->pages_merged = 0;
++ slot->pages_cowed = 0;
++ slot->this_sampled = 0;
++
++ if (vma_fully_scanned(slot))
++ slot->pages_scanned = 0;
++
++ slot->last_scanned = slot->pages_scanned;
++
++ /* If its deleted in above, then rung was already advanced. */
++ if (!deleted)
++ advance_current_scan(rung);
++}
++
++
++static inline int hash_round_finished(void)
++{
++ if (scanned_virtual_pages > (uksm_pages_total >> 2)) {
++ scanned_virtual_pages = 0;
++ if (uksm_pages_scanned)
++ fully_scanned_round++;
++
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++#define UKSM_MMSEM_BATCH 5
++#define BUSY_RETRY 100
++
++/**
++ * uksm_do_scan() - the main worker function.
++ */
++static noinline void uksm_do_scan(void)
++{
++ struct vma_slot *slot, *iter;
++ struct mm_struct *busy_mm;
++ unsigned char round_finished, all_rungs_emtpy;
++ int i, err, mmsem_batch;
++ unsigned long pcost;
++ long long delta_exec;
++ unsigned long vpages, max_cpu_ratio;
++ unsigned long long start_time, end_time, scan_time;
++ unsigned int expected_jiffies;
++
++ might_sleep();
++
++ vpages = 0;
++
++ start_time = task_sched_runtime(current);
++ max_cpu_ratio = 0;
++ mmsem_batch = 0;
++
++ for (i = 0; i < SCAN_LADDER_SIZE;) {
++ struct scan_rung *rung = &uksm_scan_ladder[i];
++ unsigned long ratio;
++ int busy_retry;
++
++ if (!rung->pages_to_scan) {
++ i++;
++ continue;
++ }
++
++ if (!rung->vma_root.num) {
++ rung->pages_to_scan = 0;
++ i++;
++ continue;
++ }
++
++ ratio = rung_real_ratio(rung->cpu_ratio);
++ if (ratio > max_cpu_ratio)
++ max_cpu_ratio = ratio;
++
++ busy_retry = BUSY_RETRY;
++ /*
++ * Do not consider rung_round_finished() here, just used up the
++ * rung->pages_to_scan quota.
++ */
++ while (rung->pages_to_scan && rung->vma_root.num &&
++ likely(!freezing(current))) {
++ int reset = 0;
++
++ slot = rung->current_scan;
++
++ BUG_ON(vma_fully_scanned(slot));
++
++ if (mmsem_batch)
++ err = 0;
++ else
++ err = try_down_read_slot_mmap_sem(slot);
++
++ if (err == -ENOENT) {
++rm_slot:
++ rung_rm_slot(slot);
++ continue;
++ }
++
++ busy_mm = slot->mm;
++
++ if (err == -EBUSY) {
++ /* skip other vmas on the same mm */
++ do {
++ reset = advance_current_scan(rung);
++ iter = rung->current_scan;
++ busy_retry--;
++ if (iter->vma->vm_mm != busy_mm ||
++ !busy_retry || reset)
++ break;
++ } while (1);
++
++ if (iter->vma->vm_mm != busy_mm) {
++ continue;
++ } else {
++ /* scan round finsished */
++ break;
++ }
++ }
++
++ BUG_ON(!vma_can_enter(slot->vma));
++ if (uksm_test_exit(slot->vma->vm_mm)) {
++ mmsem_batch = 0;
++ mmap_read_unlock(slot->vma->vm_mm);
++ goto rm_slot;
++ }
++
++ if (mmsem_batch)
++ mmsem_batch--;
++ else
++ mmsem_batch = UKSM_MMSEM_BATCH;
++
++ /* Ok, we have take the mmap_sem, ready to scan */
++ scan_vma_one_page(slot);
++ rung->pages_to_scan--;
++ vpages++;
++
++ if (rung->current_offset + rung->step > slot->pages - 1
++ || vma_fully_scanned(slot)) {
++ mmap_read_unlock(slot->vma->vm_mm);
++ judge_slot(slot);
++ mmsem_batch = 0;
++ } else {
++ rung->current_offset += rung->step;
++ if (!mmsem_batch)
++ mmap_read_unlock(slot->vma->vm_mm);
++ }
++
++ busy_retry = BUSY_RETRY;
++ cond_resched();
++ }
++
++ if (mmsem_batch) {
++ mmap_read_unlock(slot->vma->vm_mm);
++ mmsem_batch = 0;
++ }
++
++ if (freezing(current))
++ break;
++
++ cond_resched();
++ }
++ end_time = task_sched_runtime(current);
++ delta_exec = end_time - start_time;
++
++ if (freezing(current))
++ return;
++
++ cleanup_vma_slots();
++ uksm_enter_all_slots();
++
++ round_finished = 1;
++ all_rungs_emtpy = 1;
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ struct scan_rung *rung = &uksm_scan_ladder[i];
++
++ if (rung->vma_root.num) {
++ all_rungs_emtpy = 0;
++ if (!rung_round_finished(rung))
++ round_finished = 0;
++ }
++ }
++
++ if (all_rungs_emtpy)
++ round_finished = 0;
++
++ if (round_finished) {
++ round_update_ladder();
++ uksm_eval_round++;
++
++ if (hash_round_finished() && rshash_adjust()) {
++ /* Reset the unstable root iff hash strength changed */
++ uksm_hash_round++;
++ root_unstable_tree = RB_ROOT;
++ free_all_tree_nodes(&unstable_tree_node_list);
++ }
++
++ /*
++ * A number of pages can hang around indefinitely on per-cpu
++ * pagevecs, raised page count preventing write_protect_page
++ * from merging them. Though it doesn't really matter much,
++ * it is puzzling to see some stuck in pages_volatile until
++ * other activity jostles them out, and they also prevented
++ * LTP's KSM test from succeeding deterministically; so drain
++ * them here (here rather than on entry to uksm_do_scan(),
++ * so we don't IPI too often when pages_to_scan is set low).
++ */
++ lru_add_drain_all();
++ }
++
++
++ if (vpages && delta_exec > 0) {
++ pcost = (unsigned long) delta_exec / vpages;
++ if (likely(uksm_ema_page_time))
++ uksm_ema_page_time = ema(pcost, uksm_ema_page_time);
++ else
++ uksm_ema_page_time = pcost;
++ }
++
++ uksm_calc_scan_pages();
++ uksm_sleep_real = uksm_sleep_jiffies;
++ /* in case of radical cpu bursts, apply the upper bound */
++ end_time = task_sched_runtime(current);
++ if (max_cpu_ratio && end_time > start_time) {
++ scan_time = end_time - start_time;
++ expected_jiffies = msecs_to_jiffies(
++ scan_time_to_sleep(scan_time, max_cpu_ratio));
++
++ if (expected_jiffies > uksm_sleep_real)
++ uksm_sleep_real = expected_jiffies;
++
++ /* We have a 1 second up bound for responsiveness. */
++ if (jiffies_to_msecs(uksm_sleep_real) > MSEC_PER_SEC)
++ uksm_sleep_real = msecs_to_jiffies(1000);
++ }
++
++ return;
++}
++
++static int ksmd_should_run(void)
++{
++ return uksm_run & UKSM_RUN_MERGE;
++}
++
++static int uksm_scan_thread(void *nothing)
++{
++ set_freezable();
++ set_user_nice(current, 5);
++
++ while (!kthread_should_stop()) {
++ mutex_lock(&uksm_thread_mutex);
++ if (ksmd_should_run())
++ uksm_do_scan();
++ mutex_unlock(&uksm_thread_mutex);
++
++ try_to_freeze();
++
++ if (ksmd_should_run()) {
++ schedule_timeout_interruptible(uksm_sleep_real);
++ uksm_sleep_times++;
++ } else {
++ wait_event_freezable(uksm_thread_wait,
++ ksmd_should_run() || kthread_should_stop());
++ }
++ }
++ return 0;
++}
++
++void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc)
++{
++ struct stable_node *stable_node;
++ struct node_vma *node_vma;
++ struct rmap_item *rmap_item;
++ int search_new_forks = 0;
++ unsigned long address;
++
++ VM_BUG_ON_PAGE(!PageKsm(page), page);
++ VM_BUG_ON_PAGE(!PageLocked(page), page);
++
++ stable_node = page_stable_node(page);
++ if (!stable_node)
++ return;
++again:
++ hlist_for_each_entry(node_vma, &stable_node->hlist, hlist) {
++ hlist_for_each_entry(rmap_item, &node_vma->rmap_hlist, hlist) {
++ struct anon_vma *anon_vma = rmap_item->anon_vma;
++ struct anon_vma_chain *vmac;
++ struct vm_area_struct *vma;
++
++ cond_resched();
++ anon_vma_lock_read(anon_vma);
++ anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
++ 0, ULONG_MAX) {
++ cond_resched();
++ vma = vmac->vma;
++ address = get_rmap_addr(rmap_item);
++
++ if (address < vma->vm_start ||
++ address >= vma->vm_end)
++ continue;
++
++ if ((rmap_item->slot->vma == vma) ==
++ search_new_forks)
++ continue;
++
++ if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
++ continue;
++
++ if (!rwc->rmap_one(page, vma, address, rwc->arg)) {
++ anon_vma_unlock_read(anon_vma);
++ return;
++ }
++
++ if (rwc->done && rwc->done(page)) {
++ anon_vma_unlock_read(anon_vma);
++ return;
++ }
++ }
++ anon_vma_unlock_read(anon_vma);
++ }
++ }
++ if (!search_new_forks++)
++ goto again;
++}
++
++#ifdef CONFIG_MIGRATION
++/* Common ksm interface but may be specific to uksm */
++void ksm_migrate_page(struct page *newpage, struct page *oldpage)
++{
++ struct stable_node *stable_node;
++
++ VM_BUG_ON_PAGE(!PageLocked(oldpage), oldpage);
++ VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
++ VM_BUG_ON(newpage->mapping != oldpage->mapping);
++
++ stable_node = page_stable_node(newpage);
++ if (stable_node) {
++ VM_BUG_ON(stable_node->kpfn != page_to_pfn(oldpage));
++ stable_node->kpfn = page_to_pfn(newpage);
++ /*
++ * newpage->mapping was set in advance; now we need smp_wmb()
++ * to make sure that the new stable_node->kpfn is visible
++ * to get_ksm_page() before it can see that oldpage->mapping
++ * has gone stale (or that PageSwapCache has been cleared).
++ */
++ smp_wmb();
++ set_page_stable_node(oldpage, NULL);
++ }
++}
++#endif /* CONFIG_MIGRATION */
++
++#ifdef CONFIG_MEMORY_HOTREMOVE
++static struct stable_node *uksm_check_stable_tree(unsigned long start_pfn,
++ unsigned long end_pfn)
++{
++ struct rb_node *node;
++
++ for (node = rb_first(root_stable_treep); node; node = rb_next(node)) {
++ struct stable_node *stable_node;
++
++ stable_node = rb_entry(node, struct stable_node, node);
++ if (stable_node->kpfn >= start_pfn &&
++ stable_node->kpfn < end_pfn)
++ return stable_node;
++ }
++ return NULL;
++}
++
++static int uksm_memory_callback(struct notifier_block *self,
++ unsigned long action, void *arg)
++{
++ struct memory_notify *mn = arg;
++ struct stable_node *stable_node;
++
++ switch (action) {
++ case MEM_GOING_OFFLINE:
++ /*
++ * Keep it very simple for now: just lock out ksmd and
++ * MADV_UNMERGEABLE while any memory is going offline.
++ * mutex_lock_nested() is necessary because lockdep was alarmed
++ * that here we take uksm_thread_mutex inside notifier chain
++ * mutex, and later take notifier chain mutex inside
++ * uksm_thread_mutex to unlock it. But that's safe because both
++ * are inside mem_hotplug_mutex.
++ */
++ mutex_lock_nested(&uksm_thread_mutex, SINGLE_DEPTH_NESTING);
++ break;
++
++ case MEM_OFFLINE:
++ /*
++ * Most of the work is done by page migration; but there might
++ * be a few stable_nodes left over, still pointing to struct
++ * pages which have been offlined: prune those from the tree.
++ */
++ while ((stable_node = uksm_check_stable_tree(mn->start_pfn,
++ mn->start_pfn + mn->nr_pages)) != NULL)
++ remove_node_from_stable_tree(stable_node, 1, 1);
++ /* fallthrough */
++
++ case MEM_CANCEL_OFFLINE:
++ mutex_unlock(&uksm_thread_mutex);
++ break;
++ }
++ return NOTIFY_OK;
++}
++#endif /* CONFIG_MEMORY_HOTREMOVE */
++
++#ifdef CONFIG_SYSFS
++/*
++ * This all compiles without CONFIG_SYSFS, but is a waste of space.
++ */
++
++#define UKSM_ATTR_RO(_name) \
++ static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
++#define UKSM_ATTR(_name) \
++ static struct kobj_attribute _name##_attr = \
++ __ATTR(_name, 0644, _name##_show, _name##_store)
++
++static ssize_t max_cpu_percentage_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%u\n", uksm_max_cpu_percentage);
++}
++
++static ssize_t max_cpu_percentage_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long max_cpu_percentage;
++ int err;
++
++ err = kstrtoul(buf, 10, &max_cpu_percentage);
++ if (err || max_cpu_percentage > 100)
++ return -EINVAL;
++
++ if (max_cpu_percentage == 100)
++ max_cpu_percentage = 99;
++ else if (max_cpu_percentage < 10)
++ max_cpu_percentage = 10;
++
++ uksm_max_cpu_percentage = max_cpu_percentage;
++
++ return count;
++}
++UKSM_ATTR(max_cpu_percentage);
++
++static ssize_t sleep_millisecs_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%u\n", jiffies_to_msecs(uksm_sleep_jiffies));
++}
++
++static ssize_t sleep_millisecs_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long msecs;
++ int err;
++
++ err = kstrtoul(buf, 10, &msecs);
++ if (err || msecs > MSEC_PER_SEC)
++ return -EINVAL;
++
++ uksm_sleep_jiffies = msecs_to_jiffies(msecs);
++ uksm_sleep_saved = uksm_sleep_jiffies;
++
++ return count;
++}
++UKSM_ATTR(sleep_millisecs);
++
++
++static ssize_t cpu_governor_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ int n = sizeof(uksm_cpu_governor_str) / sizeof(char *);
++ int i;
++
++ buf[0] = '\0';
++ for (i = 0; i < n ; i++) {
++ if (uksm_cpu_governor == i)
++ strcat(buf, "[");
++
++ strcat(buf, uksm_cpu_governor_str[i]);
++
++ if (uksm_cpu_governor == i)
++ strcat(buf, "]");
++
++ strcat(buf, " ");
++ }
++ strcat(buf, "\n");
++
++ return strlen(buf);
++}
++
++static inline void init_performance_values(void)
++{
++ int i;
++ struct scan_rung *rung;
++ struct uksm_cpu_preset_s *preset = uksm_cpu_preset + uksm_cpu_governor;
++
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = uksm_scan_ladder + i;
++ rung->cpu_ratio = preset->cpu_ratio[i];
++ rung->cover_msecs = preset->cover_msecs[i];
++ }
++
++ uksm_max_cpu_percentage = preset->max_cpu;
++}
++
++static ssize_t cpu_governor_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int n = sizeof(uksm_cpu_governor_str) / sizeof(char *);
++
++ for (n--; n >= 0 ; n--) {
++ if (!strncmp(buf, uksm_cpu_governor_str[n],
++ strlen(uksm_cpu_governor_str[n])))
++ break;
++ }
++
++ if (n < 0)
++ return -EINVAL;
++ else
++ uksm_cpu_governor = n;
++
++ init_performance_values();
++
++ return count;
++}
++UKSM_ATTR(cpu_governor);
++
++static ssize_t run_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return sprintf(buf, "%u\n", uksm_run);
++}
++
++static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int err;
++ unsigned long flags;
++
++ err = kstrtoul(buf, 10, &flags);
++ if (err || flags > UINT_MAX)
++ return -EINVAL;
++ if (flags > UKSM_RUN_MERGE)
++ return -EINVAL;
++
++ mutex_lock(&uksm_thread_mutex);
++ if (uksm_run != flags)
++ uksm_run = flags;
++ mutex_unlock(&uksm_thread_mutex);
++
++ if (flags & UKSM_RUN_MERGE)
++ wake_up_interruptible(&uksm_thread_wait);
++
++ return count;
++}
++UKSM_ATTR(run);
++
++static ssize_t abundant_threshold_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%u\n", uksm_abundant_threshold);
++}
++
++static ssize_t abundant_threshold_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int err;
++ unsigned long flags;
++
++ err = kstrtoul(buf, 10, &flags);
++ if (err || flags > 99)
++ return -EINVAL;
++
++ uksm_abundant_threshold = flags;
++
++ return count;
++}
++UKSM_ATTR(abundant_threshold);
++
++static ssize_t thrash_threshold_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%u\n", uksm_thrash_threshold);
++}
++
++static ssize_t thrash_threshold_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int err;
++ unsigned long flags;
++
++ err = kstrtoul(buf, 10, &flags);
++ if (err || flags > 99)
++ return -EINVAL;
++
++ uksm_thrash_threshold = flags;
++
++ return count;
++}
++UKSM_ATTR(thrash_threshold);
++
++static ssize_t cpu_ratios_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ int i, size;
++ struct scan_rung *rung;
++ char *p = buf;
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = &uksm_scan_ladder[i];
++
++ if (rung->cpu_ratio > 0)
++ size = sprintf(p, "%d ", rung->cpu_ratio);
++ else
++ size = sprintf(p, "MAX/%d ",
++ TIME_RATIO_SCALE / -rung->cpu_ratio);
++
++ p += size;
++ }
++
++ *p++ = '\n';
++ *p = '\0';
++
++ return p - buf;
++}
++
++static ssize_t cpu_ratios_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int i, cpuratios[SCAN_LADDER_SIZE], err;
++ unsigned long value;
++ struct scan_rung *rung;
++ char *p, *end = NULL;
++
++ p = kzalloc(count, GFP_KERNEL);
++ if (!p)
++ return -ENOMEM;
++
++ memcpy(p, buf, count);
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ if (i != SCAN_LADDER_SIZE - 1) {
++ end = strchr(p, ' ');
++ if (!end)
++ return -EINVAL;
++
++ *end = '\0';
++ }
++
++ if (strstr(p, "MAX/")) {
++ p = strchr(p, '/') + 1;
++ err = kstrtoul(p, 10, &value);
++ if (err || value > TIME_RATIO_SCALE || !value)
++ return -EINVAL;
++
++ cpuratios[i] = -(int) (TIME_RATIO_SCALE / value);
++ } else {
++ err = kstrtoul(p, 10, &value);
++ if (err || value > TIME_RATIO_SCALE || !value)
++ return -EINVAL;
++
++ cpuratios[i] = value;
++ }
++
++ p = end + 1;
++ }
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = &uksm_scan_ladder[i];
++
++ rung->cpu_ratio = cpuratios[i];
++ }
++
++ return count;
++}
++UKSM_ATTR(cpu_ratios);
++
++static ssize_t eval_intervals_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ int i, size;
++ struct scan_rung *rung;
++ char *p = buf;
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = &uksm_scan_ladder[i];
++ size = sprintf(p, "%u ", rung->cover_msecs);
++ p += size;
++ }
++
++ *p++ = '\n';
++ *p = '\0';
++
++ return p - buf;
++}
++
++static ssize_t eval_intervals_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ int i, err;
++ unsigned long values[SCAN_LADDER_SIZE];
++ struct scan_rung *rung;
++ char *p, *end = NULL;
++ ssize_t ret = count;
++
++ p = kzalloc(count + 2, GFP_KERNEL);
++ if (!p)
++ return -ENOMEM;
++
++ memcpy(p, buf, count);
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ if (i != SCAN_LADDER_SIZE - 1) {
++ end = strchr(p, ' ');
++ if (!end) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ *end = '\0';
++ }
++
++ err = kstrtoul(p, 10, &values[i]);
++ if (err) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ p = end + 1;
++ }
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = &uksm_scan_ladder[i];
++
++ rung->cover_msecs = values[i];
++ }
++
++out:
++ kfree(p);
++ return ret;
++}
++UKSM_ATTR(eval_intervals);
++
++static ssize_t ema_per_page_time_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lu\n", uksm_ema_page_time);
++}
++UKSM_ATTR_RO(ema_per_page_time);
++
++static ssize_t pages_shared_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lu\n", uksm_pages_shared);
++}
++UKSM_ATTR_RO(pages_shared);
++
++static ssize_t pages_sharing_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lu\n", uksm_pages_sharing);
++}
++UKSM_ATTR_RO(pages_sharing);
++
++static ssize_t pages_unshared_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lu\n", uksm_pages_unshared);
++}
++UKSM_ATTR_RO(pages_unshared);
++
++static ssize_t full_scans_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%llu\n", fully_scanned_round);
++}
++UKSM_ATTR_RO(full_scans);
++
++static ssize_t pages_scanned_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ unsigned long base = 0;
++ u64 delta, ret;
++
++ if (pages_scanned_stored) {
++ base = pages_scanned_base;
++ ret = pages_scanned_stored;
++ delta = uksm_pages_scanned >> base;
++ if (CAN_OVERFLOW_U64(ret, delta)) {
++ ret >>= 1;
++ delta >>= 1;
++ base++;
++ ret += delta;
++ }
++ } else {
++ ret = uksm_pages_scanned;
++ }
++
++ while (ret > ULONG_MAX) {
++ ret >>= 1;
++ base++;
++ }
++
++ if (base)
++ return sprintf(buf, "%lu * 2^%lu\n", (unsigned long)ret, base);
++ else
++ return sprintf(buf, "%lu\n", (unsigned long)ret);
++}
++UKSM_ATTR_RO(pages_scanned);
++
++static ssize_t hash_strength_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lu\n", hash_strength);
++}
++UKSM_ATTR_RO(hash_strength);
++
++static ssize_t sleep_times_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%llu\n", uksm_sleep_times);
++}
++UKSM_ATTR_RO(sleep_times);
++
++
++static struct attribute *uksm_attrs[] = {
++ &max_cpu_percentage_attr.attr,
++ &sleep_millisecs_attr.attr,
++ &cpu_governor_attr.attr,
++ &run_attr.attr,
++ &ema_per_page_time_attr.attr,
++ &pages_shared_attr.attr,
++ &pages_sharing_attr.attr,
++ &pages_unshared_attr.attr,
++ &full_scans_attr.attr,
++ &pages_scanned_attr.attr,
++ &hash_strength_attr.attr,
++ &sleep_times_attr.attr,
++ &thrash_threshold_attr.attr,
++ &abundant_threshold_attr.attr,
++ &cpu_ratios_attr.attr,
++ &eval_intervals_attr.attr,
++ NULL,
++};
++
++static struct attribute_group uksm_attr_group = {
++ .attrs = uksm_attrs,
++ .name = "uksm",
++};
++#endif /* CONFIG_SYSFS */
++
++static inline void init_scan_ladder(void)
++{
++ int i;
++ struct scan_rung *rung;
++
++ for (i = 0; i < SCAN_LADDER_SIZE; i++) {
++ rung = uksm_scan_ladder + i;
++ slot_tree_init_root(&rung->vma_root);
++ }
++
++ init_performance_values();
++ uksm_calc_scan_pages();
++}
++
++static inline int cal_positive_negative_costs(void)
++{
++ struct page *p1, *p2;
++ unsigned char *addr1, *addr2;
++ unsigned long i, time_start, hash_cost;
++ unsigned long loopnum = 0;
++
++ /*IMPORTANT: volatile is needed to prevent over-optimization by gcc. */
++ volatile u32 hash;
++ volatile int ret;
++
++ p1 = alloc_page(GFP_KERNEL);
++ if (!p1)
++ return -ENOMEM;
++
++ p2 = alloc_page(GFP_KERNEL);
++ if (!p2)
++ return -ENOMEM;
++
++ addr1 = kmap_atomic(p1);
++ addr2 = kmap_atomic(p2);
++ memset(addr1, prandom_u32(), PAGE_SIZE);
++ memcpy(addr2, addr1, PAGE_SIZE);
++
++ /* make sure that the two pages differ in last byte */
++ addr2[PAGE_SIZE-1] = ~addr2[PAGE_SIZE-1];
++ kunmap_atomic(addr2);
++ kunmap_atomic(addr1);
++
++ time_start = jiffies;
++ while (jiffies - time_start < 100) {
++ for (i = 0; i < 100; i++)
++ hash = page_hash(p1, HASH_STRENGTH_FULL, 0);
++ loopnum += 100;
++ }
++ hash_cost = (jiffies - time_start);
++
++ time_start = jiffies;
++ for (i = 0; i < loopnum; i++)
++ ret = pages_identical_with_cost(p1, p2);
++ memcmp_cost = HASH_STRENGTH_FULL * (jiffies - time_start);
++ memcmp_cost /= hash_cost;
++ pr_info("UKSM: relative memcmp_cost = %lu "
++ "hash=%u cmp_ret=%d.\n",
++ memcmp_cost, hash, ret);
++
++ __free_page(p1);
++ __free_page(p2);
++ return 0;
++}
++
++static int init_zeropage_hash_table(void)
++{
++ struct page *page;
++ char *addr;
++ int i;
++
++ page = alloc_page(GFP_KERNEL);
++ if (!page)
++ return -ENOMEM;
++
++ addr = kmap_atomic(page);
++ memset(addr, 0, PAGE_SIZE);
++ kunmap_atomic(addr);
++
++ zero_hash_table = kmalloc_array(HASH_STRENGTH_MAX, sizeof(u32),
++ GFP_KERNEL);
++ if (!zero_hash_table)
++ return -ENOMEM;
++
++ for (i = 0; i < HASH_STRENGTH_MAX; i++)
++ zero_hash_table[i] = page_hash(page, i, 0);
++
++ __free_page(page);
++
++ return 0;
++}
++
++static inline int init_random_sampling(void)
++{
++ unsigned long i;
++
++ random_nums = kmalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!random_nums)
++ return -ENOMEM;
++
++ for (i = 0; i < HASH_STRENGTH_FULL; i++)
++ random_nums[i] = i;
++
++ for (i = 0; i < HASH_STRENGTH_FULL; i++) {
++ unsigned long rand_range, swap_index, tmp;
++
++ rand_range = HASH_STRENGTH_FULL - i;
++ swap_index = i + prandom_u32() % rand_range;
++ tmp = random_nums[i];
++ random_nums[i] = random_nums[swap_index];
++ random_nums[swap_index] = tmp;
++ }
++
++ rshash_state.state = RSHASH_NEW;
++ rshash_state.below_count = 0;
++ rshash_state.lookup_window_index = 0;
++
++ return cal_positive_negative_costs();
++}
++
++static int __init uksm_slab_init(void)
++{
++ rmap_item_cache = UKSM_KMEM_CACHE(rmap_item, 0);
++ if (!rmap_item_cache)
++ goto out;
++
++ stable_node_cache = UKSM_KMEM_CACHE(stable_node, 0);
++ if (!stable_node_cache)
++ goto out_free1;
++
++ node_vma_cache = UKSM_KMEM_CACHE(node_vma, 0);
++ if (!node_vma_cache)
++ goto out_free2;
++
++ vma_slot_cache = UKSM_KMEM_CACHE(vma_slot, 0);
++ if (!vma_slot_cache)
++ goto out_free3;
++
++ tree_node_cache = UKSM_KMEM_CACHE(tree_node, 0);
++ if (!tree_node_cache)
++ goto out_free4;
++
++ return 0;
++
++out_free4:
++ kmem_cache_destroy(vma_slot_cache);
++out_free3:
++ kmem_cache_destroy(node_vma_cache);
++out_free2:
++ kmem_cache_destroy(stable_node_cache);
++out_free1:
++ kmem_cache_destroy(rmap_item_cache);
++out:
++ return -ENOMEM;
++}
++
++static void __init uksm_slab_free(void)
++{
++ kmem_cache_destroy(stable_node_cache);
++ kmem_cache_destroy(rmap_item_cache);
++ kmem_cache_destroy(node_vma_cache);
++ kmem_cache_destroy(vma_slot_cache);
++ kmem_cache_destroy(tree_node_cache);
++}
++
++/* Common interface to ksm, different to it. */
++int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end, int advice, unsigned long *vm_flags)
++{
++ int err;
++
++ switch (advice) {
++ case MADV_MERGEABLE:
++ return 0; /* just ignore the advice */
++
++ case MADV_UNMERGEABLE:
++ if (!(*vm_flags & VM_MERGEABLE) || !uksm_flags_can_scan(*vm_flags))
++ return 0; /* just ignore the advice */
++
++ if (vma->anon_vma) {
++ err = unmerge_uksm_pages(vma, start, end);
++ if (err)
++ return err;
++ }
++
++ uksm_remove_vma(vma);
++ *vm_flags &= ~VM_MERGEABLE;
++ break;
++ }
++
++ return 0;
++}
++
++/* Common interface to ksm, actually the same. */
++struct page *ksm_might_need_to_copy(struct page *page,
++ struct vm_area_struct *vma, unsigned long address)
++{
++ struct anon_vma *anon_vma = page_anon_vma(page);
++ struct page *new_page;
++
++ if (PageKsm(page)) {
++ if (page_stable_node(page))
++ return page; /* no need to copy it */
++ } else if (!anon_vma) {
++ return page; /* no need to copy it */
++ } else if (anon_vma->root == vma->anon_vma->root &&
++ page->index == linear_page_index(vma, address)) {
++ return page; /* still no need to copy it */
++ }
++ if (!PageUptodate(page))
++ return page; /* let do_swap_page report the error */
++
++ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
++ if (new_page) {
++ copy_user_highpage(new_page, page, address, vma);
++
++ SetPageDirty(new_page);
++ __SetPageUptodate(new_page);
++ __SetPageLocked(new_page);
++ }
++
++ return new_page;
++}
++
++/* Copied from mm/ksm.c and required from 5.1 */
++bool reuse_ksm_page(struct page *page,
++ struct vm_area_struct *vma,
++ unsigned long address)
++{
++#ifdef CONFIG_DEBUG_VM
++ if (WARN_ON(is_zero_pfn(page_to_pfn(page))) ||
++ WARN_ON(!page_mapped(page)) ||
++ WARN_ON(!PageLocked(page))) {
++ dump_page(page, "reuse_ksm_page");
++ return false;
++ }
++#endif
++
++ if (PageSwapCache(page) || !page_stable_node(page))
++ return false;
++ /* Prohibit parallel get_ksm_page() */
++ if (!page_ref_freeze(page, 1))
++ return false;
++
++ page_move_anon_rmap(page, vma);
++ page->index = linear_page_index(vma, address);
++ page_ref_unfreeze(page, 1);
++
++ return true;
++}
++
++static int __init uksm_init(void)
++{
++ struct task_struct *uksm_thread;
++ int err;
++
++ uksm_sleep_jiffies = msecs_to_jiffies(100);
++ uksm_sleep_saved = uksm_sleep_jiffies;
++
++ slot_tree_init();
++ init_scan_ladder();
++
++
++ err = init_random_sampling();
++ if (err)
++ goto out_free2;
++
++ err = uksm_slab_init();
++ if (err)
++ goto out_free1;
++
++ err = init_zeropage_hash_table();
++ if (err)
++ goto out_free0;
++
++ uksm_thread = kthread_run(uksm_scan_thread, NULL, "uksmd");
++ if (IS_ERR(uksm_thread)) {
++ pr_err("uksm: creating kthread failed\n");
++ err = PTR_ERR(uksm_thread);
++ goto out_free;
++ }
++
++#ifdef CONFIG_SYSFS
++ err = sysfs_create_group(mm_kobj, &uksm_attr_group);
++ if (err) {
++ pr_err("uksm: register sysfs failed\n");
++ kthread_stop(uksm_thread);
++ goto out_free;
++ }
++#else
++ uksm_run = UKSM_RUN_MERGE; /* no way for user to start it */
++
++#endif /* CONFIG_SYSFS */
++
++#ifdef CONFIG_MEMORY_HOTREMOVE
++ /*
++ * Choose a high priority since the callback takes uksm_thread_mutex:
++ * later callbacks could only be taking locks which nest within that.
++ */
++ hotplug_memory_notifier(uksm_memory_callback, 100);
++#endif
++ return 0;
++
++out_free:
++ kfree(zero_hash_table);
++out_free0:
++ uksm_slab_free();
++out_free1:
++ kfree(random_nums);
++out_free2:
++ kfree(uksm_scan_ladder);
++ return err;
++}
++
++#ifdef MODULE
++subsys_initcall(ksm_init);
++#else
++late_initcall(uksm_init);
++#endif
++
+diff --git a/mm/vmstat.c b/mm/vmstat.c
+index 8ce262034..c0bc68578 100644
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1237,6 +1237,9 @@ const char * const vmstat_text[] = {
+ "nr_swapcached",
+ #endif
+
++#ifdef CONFIG_UKSM
++ "nr_uksm_zero_pages",
++#endif
+ /* enum writeback_stat_item counters */
+ "nr_dirty_threshold",
+ "nr_dirty_background_threshold",
+--
+2.33.1.711.g9d530dc002
+
diff --git a/system/easy-kernel/0260-reduce-swappiness.patch b/system/easy-kernel/0260-reduce-swappiness.patch
new file mode 100644
index 000000000..eeb0243ae
--- /dev/null
+++ b/system/easy-kernel/0260-reduce-swappiness.patch
@@ -0,0 +1,11 @@
+--- linux-5.15/mm/vmscan.c 2021-11-01 07:53:10.000000000 +1100
++++ linux-5.15-ckvm/mm/vmscan.c 2021-12-23 18:53:51.735282731 +1100
+@@ -174,7 +174,7 @@
+ /*
+ * From 0 .. 200. Higher means more swappy.
+ */
+-int vm_swappiness = 60;
++int vm_swappiness = 24;
+
+ static void set_task_reclaim_state(struct task_struct *task,
+ struct reclaim_state *rs)
diff --git a/system/easy-kernel/0300-tmp513-regression-fix.patch b/system/easy-kernel/0300-tmp513-regression-fix.patch
new file mode 100644
index 000000000..433568579
--- /dev/null
+++ b/system/easy-kernel/0300-tmp513-regression-fix.patch
@@ -0,0 +1,30 @@
+From dc328d75a6f37f4ff11a81ae16b1ec88c3197640 Mon Sep 17 00:00:00 2001
+From: Mike Pagano <mpagano@gentoo.org>
+Date: Mon, 23 Mar 2020 08:20:06 -0400
+Subject: [PATCH 1/1] This driver requires REGMAP_I2C to build. Select it by
+ default in Kconfig. Reported at gentoo bugzilla:
+ https://bugs.gentoo.org/710790
+Cc: mpagano@gentoo.org
+
+Reported-by: Phil Stracchino <phils@caerllewys.net>
+
+Signed-off-by: Mike Pagano <mpagano@gentoo.org>
+---
+ drivers/hwmon/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index 47ac20aee06f..530b4f29ba85 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1769,6 +1769,7 @@ config SENSORS_TMP421
+ config SENSORS_TMP513
+ tristate "Texas Instruments TMP513 and compatibles"
+ depends on I2C
++ select REGMAP_I2C
+ help
+ If you say yes here you get support for Texas Instruments TMP512,
+ and TMP513 temperature and power supply sensor chips.
+--
+2.24.1
+
diff --git a/system/easy-kernel/0500-print-fw-info.patch b/system/easy-kernel/0500-print-fw-info.patch
new file mode 100644
index 000000000..a630cfbea
--- /dev/null
+++ b/system/easy-kernel/0500-print-fw-info.patch
@@ -0,0 +1,14 @@
+--- a/drivers/base/firmware_loader/main.c 2021-08-24 15:42:07.025482085 -0400
++++ b/drivers/base/firmware_loader/main.c 2021-08-24 15:44:40.782975313 -0400
+@@ -809,6 +809,11 @@ _request_firmware(const struct firmware
+
+ ret = _request_firmware_prepare(&fw, name, device, buf, size,
+ offset, opt_flags);
++
++#ifdef CONFIG_GENTOO_PRINT_FIRMWARE_INFO
++ printk(KERN_NOTICE "Loading firmware: %s\n", name);
++#endif
++
+ if (ret <= 0) /* error or already assigned */
+ goto out;
+
diff --git a/system/easy-kernel/0502-gcc9-kcflags.patch b/system/easy-kernel/0502-gcc9-kcflags.patch
new file mode 100644
index 000000000..becfda363
--- /dev/null
+++ b/system/easy-kernel/0502-gcc9-kcflags.patch
@@ -0,0 +1,680 @@
+From d31d2b0747ab55e65c2366d51149a0ec9896155e Mon Sep 17 00:00:00 2001
+From: graysky <graysky@archlinux.us>
+Date: Tue, 14 Sep 2021 15:35:34 -0400
+Subject: [PATCH] more uarches for kernel 5.15+
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+FEATURES
+This patch adds additional CPU options to the Linux kernel accessible under:
+ Processor type and features --->
+ Processor family --->
+
+With the release of gcc 11.1 and clang 12.0, several generic 64-bit levels are
+offered which are good for supported Intel or AMD CPUs:
+• x86-64-v2
+• x86-64-v3
+• x86-64-v4
+
+Users of glibc 2.33 and above can see which level is supported by current
+hardware by running:
+ /lib/ld-linux-x86-64.so.2 --help | grep supported
+
+Alternatively, compare the flags from /proc/cpuinfo to this list.[1]
+
+CPU-specific microarchitectures include:
+• AMD Improved K8-family
+• AMD K10-family
+• AMD Family 10h (Barcelona)
+• AMD Family 14h (Bobcat)
+• AMD Family 16h (Jaguar)
+• AMD Family 15h (Bulldozer)
+• AMD Family 15h (Piledriver)
+• AMD Family 15h (Steamroller)
+• AMD Family 15h (Excavator)
+• AMD Family 17h (Zen)
+• AMD Family 17h (Zen 2)
+• AMD Family 19h (Zen 3)†
+• Intel Silvermont low-power processors
+• Intel Goldmont low-power processors (Apollo Lake and Denverton)
+• Intel Goldmont Plus low-power processors (Gemini Lake)
+• Intel 1st Gen Core i3/i5/i7 (Nehalem)
+• Intel 1.5 Gen Core i3/i5/i7 (Westmere)
+• Intel 2nd Gen Core i3/i5/i7 (Sandybridge)
+• Intel 3rd Gen Core i3/i5/i7 (Ivybridge)
+• Intel 4th Gen Core i3/i5/i7 (Haswell)
+• Intel 5th Gen Core i3/i5/i7 (Broadwell)
+• Intel 6th Gen Core i3/i5/i7 (Skylake)
+• Intel 6th Gen Core i7/i9 (Skylake X)
+• Intel 8th Gen Core i3/i5/i7 (Cannon Lake)
+• Intel 10th Gen Core i7/i9 (Ice Lake)
+• Intel Xeon (Cascade Lake)
+• Intel Xeon (Cooper Lake)*
+• Intel 3rd Gen 10nm++ i3/i5/i7/i9-family (Tiger Lake)*
+• Intel 3rd Gen 10nm++ Xeon (Sapphire Rapids)‡
+• Intel 11th Gen i3/i5/i7/i9-family (Rocket Lake)‡
+• Intel 12th Gen i3/i5/i7/i9-family (Alder Lake)‡
+
+Notes: If not otherwise noted, gcc >=9.1 is required for support.
+ *Requires gcc >=10.1 or clang >=10.0
+ †Required gcc >=10.3 or clang >=12.0
+ ‡Required gcc >=11.1 or clang >=12.0
+
+It also offers to compile passing the 'native' option which, "selects the CPU
+to generate code for at compilation time by determining the processor type of
+the compiling machine. Using -march=native enables all instruction subsets
+supported by the local machine and will produce code optimized for the local
+machine under the constraints of the selected instruction set."[2]
+
+Users of Intel CPUs should select the 'Intel-Native' option and users of AMD
+CPUs should select the 'AMD-Native' option.
+
+MINOR NOTES RELATING TO INTEL ATOM PROCESSORS
+This patch also changes -march=atom to -march=bonnell in accordance with the
+gcc v4.9 changes. Upstream is using the deprecated -match=atom flags when I
+believe it should use the newer -march=bonnell flag for atom processors.[3]
+
+It is not recommended to compile on Atom-CPUs with the 'native' option.[4] The
+recommendation is to use the 'atom' option instead.
+
+BENEFITS
+Small but real speed increases are measurable using a make endpoint comparing
+a generic kernel to one built with one of the respective microarchs.
+
+See the following experimental evidence supporting this statement:
+https://github.com/graysky2/kernel_gcc_patch
+
+REQUIREMENTS
+linux version >=5.15
+gcc version >=9.0 or clang version >=9.0
+
+ACKNOWLEDGMENTS
+This patch builds on the seminal work by Jeroen.[5]
+
+REFERENCES
+1. https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/77566eb03bc6a326811cb7e9
+2. https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-x86-Options
+3. https://bugzilla.kernel.org/show_bug.cgi?id=77461
+4. https://github.com/graysky2/kernel_gcc_patch/issues/15
+5. http://www.linuxforge.net/docs/linux/linux-gcc.php
+
+Signed-off-by: graysky <graysky@archlinux.us>
+---
+From 1bfa1ef4e3a93e540a64cd1020863019dff3046e Mon Sep 17 00:00:00 2001
+From: graysky <graysky@archlinux.us>
+Date: Sun, 14 Nov 2021 16:08:29 -0500
+Subject: [PATCH] iiii
+
+---
+ arch/x86/Kconfig.cpu | 332 ++++++++++++++++++++++++++++++--
+ arch/x86/Makefile | 40 +++-
+ arch/x86/include/asm/vermagic.h | 66 +++++++
+ 3 files changed, 424 insertions(+), 14 deletions(-)
+
+diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
+index eefc434351db..331f7631339a 100644
+--- a/arch/x86/Kconfig.cpu
++++ b/arch/x86/Kconfig.cpu
+@@ -157,7 +157,7 @@ config MPENTIUM4
+
+
+ config MK6
+- bool "K6/K6-II/K6-III"
++ bool "AMD K6/K6-II/K6-III"
+ depends on X86_32
+ help
+ Select this for an AMD K6-family processor. Enables use of
+@@ -165,7 +165,7 @@ config MK6
+ flags to GCC.
+
+ config MK7
+- bool "Athlon/Duron/K7"
++ bool "AMD Athlon/Duron/K7"
+ depends on X86_32
+ help
+ Select this for an AMD Athlon K7-family processor. Enables use of
+@@ -173,12 +173,98 @@ config MK7
+ flags to GCC.
+
+ config MK8
+- bool "Opteron/Athlon64/Hammer/K8"
++ bool "AMD Opteron/Athlon64/Hammer/K8"
+ help
+ Select this for an AMD Opteron or Athlon64 Hammer-family processor.
+ Enables use of some extended instructions, and passes appropriate
+ optimization flags to GCC.
+
++config MK8SSE3
++ bool "AMD Opteron/Athlon64/Hammer/K8 with SSE3"
++ help
++ Select this for improved AMD Opteron or Athlon64 Hammer-family processors.
++ Enables use of some extended instructions, and passes appropriate
++ optimization flags to GCC.
++
++config MK10
++ bool "AMD 61xx/7x50/PhenomX3/X4/II/K10"
++ help
++ Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50,
++ Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor.
++ Enables use of some extended instructions, and passes appropriate
++ optimization flags to GCC.
++
++config MBARCELONA
++ bool "AMD Barcelona"
++ help
++ Select this for AMD Family 10h Barcelona processors.
++
++ Enables -march=barcelona
++
++config MBOBCAT
++ bool "AMD Bobcat"
++ help
++ Select this for AMD Family 14h Bobcat processors.
++
++ Enables -march=btver1
++
++config MJAGUAR
++ bool "AMD Jaguar"
++ help
++ Select this for AMD Family 16h Jaguar processors.
++
++ Enables -march=btver2
++
++config MBULLDOZER
++ bool "AMD Bulldozer"
++ help
++ Select this for AMD Family 15h Bulldozer processors.
++
++ Enables -march=bdver1
++
++config MPILEDRIVER
++ bool "AMD Piledriver"
++ help
++ Select this for AMD Family 15h Piledriver processors.
++
++ Enables -march=bdver2
++
++config MSTEAMROLLER
++ bool "AMD Steamroller"
++ help
++ Select this for AMD Family 15h Steamroller processors.
++
++ Enables -march=bdver3
++
++config MEXCAVATOR
++ bool "AMD Excavator"
++ help
++ Select this for AMD Family 15h Excavator processors.
++
++ Enables -march=bdver4
++
++config MZEN
++ bool "AMD Zen"
++ help
++ Select this for AMD Family 17h Zen processors.
++
++ Enables -march=znver1
++
++config MZEN2
++ bool "AMD Zen 2"
++ help
++ Select this for AMD Family 17h Zen 2 processors.
++
++ Enables -march=znver2
++
++config MZEN3
++ bool "AMD Zen 3"
++ depends on (CC_IS_GCC && GCC_VERSION >= 100300) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ help
++ Select this for AMD Family 19h Zen 3 processors.
++
++ Enables -march=znver3
++
+ config MCRUSOE
+ bool "Crusoe"
+ depends on X86_32
+@@ -270,7 +356,7 @@ config MPSC
+ in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
+
+ config MCORE2
+- bool "Core 2/newer Xeon"
++ bool "Intel Core 2"
+ help
+
+ Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and
+@@ -278,6 +364,8 @@ config MCORE2
+ family in /proc/cpuinfo. Newer ones have 6 and older ones 15
+ (not a typo)
+
++ Enables -march=core2
++
+ config MATOM
+ bool "Intel Atom"
+ help
+@@ -287,6 +375,182 @@ config MATOM
+ accordingly optimized code. Use a recent GCC with specific Atom
+ support in order to fully benefit from selecting this option.
+
++config MNEHALEM
++ bool "Intel Nehalem"
++ select X86_P6_NOP
++ help
++
++ Select this for 1st Gen Core processors in the Nehalem family.
++
++ Enables -march=nehalem
++
++config MWESTMERE
++ bool "Intel Westmere"
++ select X86_P6_NOP
++ help
++
++ Select this for the Intel Westmere formerly Nehalem-C family.
++
++ Enables -march=westmere
++
++config MSILVERMONT
++ bool "Intel Silvermont"
++ select X86_P6_NOP
++ help
++
++ Select this for the Intel Silvermont platform.
++
++ Enables -march=silvermont
++
++config MGOLDMONT
++ bool "Intel Goldmont"
++ select X86_P6_NOP
++ help
++
++ Select this for the Intel Goldmont platform including Apollo Lake and Denverton.
++
++ Enables -march=goldmont
++
++config MGOLDMONTPLUS
++ bool "Intel Goldmont Plus"
++ select X86_P6_NOP
++ help
++
++ Select this for the Intel Goldmont Plus platform including Gemini Lake.
++
++ Enables -march=goldmont-plus
++
++config MSANDYBRIDGE
++ bool "Intel Sandy Bridge"
++ select X86_P6_NOP
++ help
++
++ Select this for 2nd Gen Core processors in the Sandy Bridge family.
++
++ Enables -march=sandybridge
++
++config MIVYBRIDGE
++ bool "Intel Ivy Bridge"
++ select X86_P6_NOP
++ help
++
++ Select this for 3rd Gen Core processors in the Ivy Bridge family.
++
++ Enables -march=ivybridge
++
++config MHASWELL
++ bool "Intel Haswell"
++ select X86_P6_NOP
++ help
++
++ Select this for 4th Gen Core processors in the Haswell family.
++
++ Enables -march=haswell
++
++config MBROADWELL
++ bool "Intel Broadwell"
++ select X86_P6_NOP
++ help
++
++ Select this for 5th Gen Core processors in the Broadwell family.
++
++ Enables -march=broadwell
++
++config MSKYLAKE
++ bool "Intel Skylake"
++ select X86_P6_NOP
++ help
++
++ Select this for 6th Gen Core processors in the Skylake family.
++
++ Enables -march=skylake
++
++config MSKYLAKEX
++ bool "Intel Skylake X"
++ select X86_P6_NOP
++ help
++
++ Select this for 6th Gen Core processors in the Skylake X family.
++
++ Enables -march=skylake-avx512
++
++config MCANNONLAKE
++ bool "Intel Cannon Lake"
++ select X86_P6_NOP
++ help
++
++ Select this for 8th Gen Core processors
++
++ Enables -march=cannonlake
++
++config MICELAKE
++ bool "Intel Ice Lake"
++ select X86_P6_NOP
++ help
++
++ Select this for 10th Gen Core processors in the Ice Lake family.
++
++ Enables -march=icelake-client
++
++config MCASCADELAKE
++ bool "Intel Cascade Lake"
++ select X86_P6_NOP
++ help
++
++ Select this for Xeon processors in the Cascade Lake family.
++
++ Enables -march=cascadelake
++
++config MCOOPERLAKE
++ bool "Intel Cooper Lake"
++ depends on (CC_IS_GCC && GCC_VERSION > 100100) || (CC_IS_CLANG && CLANG_VERSION >= 100000)
++ select X86_P6_NOP
++ help
++
++ Select this for Xeon processors in the Cooper Lake family.
++
++ Enables -march=cooperlake
++
++config MTIGERLAKE
++ bool "Intel Tiger Lake"
++ depends on (CC_IS_GCC && GCC_VERSION > 100100) || (CC_IS_CLANG && CLANG_VERSION >= 100000)
++ select X86_P6_NOP
++ help
++
++ Select this for third-generation 10 nm process processors in the Tiger Lake family.
++
++ Enables -march=tigerlake
++
++config MSAPPHIRERAPIDS
++ bool "Intel Sapphire Rapids"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ select X86_P6_NOP
++ help
++
++ Select this for third-generation 10 nm process processors in the Sapphire Rapids family.
++
++ Enables -march=sapphirerapids
++
++config MROCKETLAKE
++ bool "Intel Rocket Lake"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ select X86_P6_NOP
++ help
++
++ Select this for eleventh-generation processors in the Rocket Lake family.
++
++ Enables -march=rocketlake
++
++config MALDERLAKE
++ bool "Intel Alder Lake"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ select X86_P6_NOP
++ help
++
++ Select this for twelfth-generation processors in the Alder Lake family.
++
++ Enables -march=alderlake
++
+ config GENERIC_CPU
+ bool "Generic-x86-64"
+ depends on X86_64
+@@ -294,6 +558,50 @@ config GENERIC_CPU
+ Generic x86-64 CPU.
+ Run equally well on all x86-64 CPUs.
+
++config GENERIC_CPU2
++ bool "Generic-x86-64-v2"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ depends on X86_64
++ help
++ Generic x86-64 CPU.
++ Run equally well on all x86-64 CPUs with min support of x86-64-v2.
++
++config GENERIC_CPU3
++ bool "Generic-x86-64-v3"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ depends on X86_64
++ help
++ Generic x86-64-v3 CPU with v3 instructions.
++ Run equally well on all x86-64 CPUs with min support of x86-64-v3.
++
++config GENERIC_CPU4
++ bool "Generic-x86-64-v4"
++ depends on (CC_IS_GCC && GCC_VERSION > 110000) || (CC_IS_CLANG && CLANG_VERSION >= 120000)
++ depends on X86_64
++ help
++ Generic x86-64 CPU with v4 instructions.
++ Run equally well on all x86-64 CPUs with min support of x86-64-v4.
++
++config MNATIVE_INTEL
++ bool "Intel-Native optimizations autodetected by the compiler"
++ help
++
++ Clang 3.8, GCC 4.2 and above support -march=native, which automatically detects
++ the optimum settings to use based on your processor. Do NOT use this
++ for AMD CPUs. Intel Only!
++
++ Enables -march=native
++
++config MNATIVE_AMD
++ bool "AMD-Native optimizations autodetected by the compiler"
++ help
++
++ Clang 3.8, GCC 4.2 and above support -march=native, which automatically detects
++ the optimum settings to use based on your processor. Do NOT use this
++ for Intel CPUs. AMD Only!
++
++ Enables -march=native
++
+ endchoice
+
+ config X86_GENERIC
+@@ -318,7 +626,7 @@ config X86_INTERNODE_CACHE_SHIFT
+ config X86_L1_CACHE_SHIFT
+ int
+ default "7" if MPENTIUM4 || MPSC
+- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
++ default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD || X86_GENERIC || GENERIC_CPU || GENERIC_CPU2 || GENERIC_CPU3 || GENERIC_CPU4
+ default "4" if MELAN || M486SX || M486 || MGEODEGX1
+ default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+
+@@ -336,11 +644,11 @@ config X86_ALIGNMENT_16
+
+ config X86_INTEL_USERCOPY
+ def_bool y
+- depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
++ depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL
+
+ config X86_USE_PPRO_CHECKSUM
+ def_bool y
+- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
++ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD
+
+ config X86_USE_3DNOW
+ def_bool y
+@@ -360,26 +668,26 @@ config X86_USE_3DNOW
+ config X86_P6_NOP
+ def_bool y
+ depends on X86_64
+- depends on (MCORE2 || MPENTIUM4 || MPSC)
++ depends on (MCORE2 || MPENTIUM4 || MPSC || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL)
+
+ config X86_TSC
+ def_bool y
+- depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
++ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD) || X86_64
+
+ config X86_CMPXCHG64
+ def_bool y
+- depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586TSC || M586MMX || MATOM || MGEODE_LX || MGEODEGX1 || MK6 || MK7 || MK8
++ depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586TSC || M586MMX || MATOM || MGEODE_LX || MGEODEGX1 || MK6 || MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD
+
+ # this should be set for all -march=.. options where the compiler
+ # generates cmov.
+ config X86_CMOV
+ def_bool y
+- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
++ depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD)
+
+ 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 || MCRUSOE || MCORE2 || MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MJAGUAR || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MZEN3 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MCOOPERLAKE || MTIGERLAKE || MSAPPHIRERAPIDS || MROCKETLAKE || MALDERLAKE || MNATIVE_INTEL || MNATIVE_AMD)
+ default "5" if X86_32 && X86_CMPXCHG64
+ default "4"
+
+diff --git a/arch/x86/Makefile b/arch/x86/Makefile
+index 42243869216d..ab1ad6959b96 100644
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -119,8 +119,44 @@ else
+ # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
+ cflags-$(CONFIG_MK8) += -march=k8
+ cflags-$(CONFIG_MPSC) += -march=nocona
+- cflags-$(CONFIG_MCORE2) += -march=core2
+- cflags-$(CONFIG_MATOM) += -march=atom
++ cflags-$(CONFIG_MK8SSE3) += -march=k8-sse3
++ cflags-$(CONFIG_MK10) += -march=amdfam10
++ cflags-$(CONFIG_MBARCELONA) += -march=barcelona
++ cflags-$(CONFIG_MBOBCAT) += -march=btver1
++ cflags-$(CONFIG_MJAGUAR) += -march=btver2
++ cflags-$(CONFIG_MBULLDOZER) += -march=bdver1
++ cflags-$(CONFIG_MPILEDRIVER) += -march=bdver2 -mno-tbm
++ cflags-$(CONFIG_MSTEAMROLLER) += -march=bdver3 -mno-tbm
++ cflags-$(CONFIG_MEXCAVATOR) += -march=bdver4 -mno-tbm
++ cflags-$(CONFIG_MZEN) += -march=znver1
++ cflags-$(CONFIG_MZEN2) += -march=znver2
++ cflags-$(CONFIG_MZEN3) += -march=znver3
++ cflags-$(CONFIG_MNATIVE_INTEL) += -march=native
++ cflags-$(CONFIG_MNATIVE_AMD) += -march=native
++ cflags-$(CONFIG_MATOM) += -march=bonnell
++ cflags-$(CONFIG_MCORE2) += -march=core2
++ cflags-$(CONFIG_MNEHALEM) += -march=nehalem
++ cflags-$(CONFIG_MWESTMERE) += -march=westmere
++ cflags-$(CONFIG_MSILVERMONT) += -march=silvermont
++ cflags-$(CONFIG_MGOLDMONT) += -march=goldmont
++ cflags-$(CONFIG_MGOLDMONTPLUS) += -march=goldmont-plus
++ cflags-$(CONFIG_MSANDYBRIDGE) += -march=sandybridge
++ cflags-$(CONFIG_MIVYBRIDGE) += -march=ivybridge
++ cflags-$(CONFIG_MHASWELL) += -march=haswell
++ cflags-$(CONFIG_MBROADWELL) += -march=broadwell
++ cflags-$(CONFIG_MSKYLAKE) += -march=skylake
++ cflags-$(CONFIG_MSKYLAKEX) += -march=skylake-avx512
++ cflags-$(CONFIG_MCANNONLAKE) += -march=cannonlake
++ cflags-$(CONFIG_MICELAKE) += -march=icelake-client
++ cflags-$(CONFIG_MCASCADELAKE) += -march=cascadelake
++ cflags-$(CONFIG_MCOOPERLAKE) += -march=cooperlake
++ cflags-$(CONFIG_MTIGERLAKE) += -march=tigerlake
++ cflags-$(CONFIG_MSAPPHIRERAPIDS) += -march=sapphirerapids
++ cflags-$(CONFIG_MROCKETLAKE) += -march=rocketlake
++ cflags-$(CONFIG_MALDERLAKE) += -march=alderlake
++ cflags-$(CONFIG_GENERIC_CPU2) += -march=x86-64-v2
++ cflags-$(CONFIG_GENERIC_CPU3) += -march=x86-64-v3
++ cflags-$(CONFIG_GENERIC_CPU4) += -march=x86-64-v4
+ cflags-$(CONFIG_GENERIC_CPU) += -mtune=generic
+ KBUILD_CFLAGS += $(cflags-y)
+
+diff --git a/arch/x86/include/asm/vermagic.h b/arch/x86/include/asm/vermagic.h
+index 75884d2cdec3..4e6a08d4c7e5 100644
+--- a/arch/x86/include/asm/vermagic.h
++++ b/arch/x86/include/asm/vermagic.h
+@@ -17,6 +17,48 @@
+ #define MODULE_PROC_FAMILY "586MMX "
+ #elif defined CONFIG_MCORE2
+ #define MODULE_PROC_FAMILY "CORE2 "
++#elif defined CONFIG_MNATIVE_INTEL
++#define MODULE_PROC_FAMILY "NATIVE_INTEL "
++#elif defined CONFIG_MNATIVE_AMD
++#define MODULE_PROC_FAMILY "NATIVE_AMD "
++#elif defined CONFIG_MNEHALEM
++#define MODULE_PROC_FAMILY "NEHALEM "
++#elif defined CONFIG_MWESTMERE
++#define MODULE_PROC_FAMILY "WESTMERE "
++#elif defined CONFIG_MSILVERMONT
++#define MODULE_PROC_FAMILY "SILVERMONT "
++#elif defined CONFIG_MGOLDMONT
++#define MODULE_PROC_FAMILY "GOLDMONT "
++#elif defined CONFIG_MGOLDMONTPLUS
++#define MODULE_PROC_FAMILY "GOLDMONTPLUS "
++#elif defined CONFIG_MSANDYBRIDGE
++#define MODULE_PROC_FAMILY "SANDYBRIDGE "
++#elif defined CONFIG_MIVYBRIDGE
++#define MODULE_PROC_FAMILY "IVYBRIDGE "
++#elif defined CONFIG_MHASWELL
++#define MODULE_PROC_FAMILY "HASWELL "
++#elif defined CONFIG_MBROADWELL
++#define MODULE_PROC_FAMILY "BROADWELL "
++#elif defined CONFIG_MSKYLAKE
++#define MODULE_PROC_FAMILY "SKYLAKE "
++#elif defined CONFIG_MSKYLAKEX
++#define MODULE_PROC_FAMILY "SKYLAKEX "
++#elif defined CONFIG_MCANNONLAKE
++#define MODULE_PROC_FAMILY "CANNONLAKE "
++#elif defined CONFIG_MICELAKE
++#define MODULE_PROC_FAMILY "ICELAKE "
++#elif defined CONFIG_MCASCADELAKE
++#define MODULE_PROC_FAMILY "CASCADELAKE "
++#elif defined CONFIG_MCOOPERLAKE
++#define MODULE_PROC_FAMILY "COOPERLAKE "
++#elif defined CONFIG_MTIGERLAKE
++#define MODULE_PROC_FAMILY "TIGERLAKE "
++#elif defined CONFIG_MSAPPHIRERAPIDS
++#define MODULE_PROC_FAMILY "SAPPHIRERAPIDS "
++#elif defined CONFIG_ROCKETLAKE
++#define MODULE_PROC_FAMILY "ROCKETLAKE "
++#elif defined CONFIG_MALDERLAKE
++#define MODULE_PROC_FAMILY "ALDERLAKE "
+ #elif defined CONFIG_MATOM
+ #define MODULE_PROC_FAMILY "ATOM "
+ #elif defined CONFIG_M686
+@@ -35,6 +77,30 @@
+ #define MODULE_PROC_FAMILY "K7 "
+ #elif defined CONFIG_MK8
+ #define MODULE_PROC_FAMILY "K8 "
++#elif defined CONFIG_MK8SSE3
++#define MODULE_PROC_FAMILY "K8SSE3 "
++#elif defined CONFIG_MK10
++#define MODULE_PROC_FAMILY "K10 "
++#elif defined CONFIG_MBARCELONA
++#define MODULE_PROC_FAMILY "BARCELONA "
++#elif defined CONFIG_MBOBCAT
++#define MODULE_PROC_FAMILY "BOBCAT "
++#elif defined CONFIG_MBULLDOZER
++#define MODULE_PROC_FAMILY "BULLDOZER "
++#elif defined CONFIG_MPILEDRIVER
++#define MODULE_PROC_FAMILY "PILEDRIVER "
++#elif defined CONFIG_MSTEAMROLLER
++#define MODULE_PROC_FAMILY "STEAMROLLER "
++#elif defined CONFIG_MJAGUAR
++#define MODULE_PROC_FAMILY "JAGUAR "
++#elif defined CONFIG_MEXCAVATOR
++#define MODULE_PROC_FAMILY "EXCAVATOR "
++#elif defined CONFIG_MZEN
++#define MODULE_PROC_FAMILY "ZEN "
++#elif defined CONFIG_MZEN2
++#define MODULE_PROC_FAMILY "ZEN2 "
++#elif defined CONFIG_MZEN3
++#define MODULE_PROC_FAMILY "ZEN3 "
+ #elif defined CONFIG_MELAN
+ #define MODULE_PROC_FAMILY "ELAN "
+ #elif defined CONFIG_MCRUSOE
+--
+2.33.1
diff --git a/system/easy-kernel/1000-version.patch b/system/easy-kernel/1000-version.patch
new file mode 100644
index 000000000..18de49341
--- /dev/null
+++ b/system/easy-kernel/1000-version.patch
@@ -0,0 +1,1840 @@
+diff -Naur linux-5.15-stock/Makefile linux-5.15-branded/Makefile
+--- linux-5.15-stock/Makefile 2021-12-06 03:06:49.989061729 +0000
++++ linux-5.15-branded/Makefile 2021-12-06 03:13:56.038836580 +0000
+@@ -2,8 +2,8 @@
+ VERSION = 5
+ PATCHLEVEL = 15
+ SUBLEVEL = 11
+-EXTRAVERSION =
+-NAME = Trick or Treat
++EXTRAVERSION = -mc1
++NAME = Ponder the Icosahedron
+
+ # *DOCUMENTATION*
+ # To see a list of typical targets execute "make help"
+diff -Naur --no-dereference linux-5.15/drivers/video/logo/logo_linux_clut224.ppm linux-5.15-branded/drivers/video/logo/logo_linux_clut224.ppm
+--- linux-5.15/drivers/video/logo/logo_linux_clut224.ppm 2021-12-06 18:46:13.000000000 +0000
++++ linux-5.15-branded/drivers/video/logo/logo_linux_clut224.ppm 2021-12-06 00:49:44.869630412 +0000
+@@ -1,1604 +1,219 @@
+-P3
+-# Standard 224-color Linux logo
+-80 80
++P2
++72 72
+ 255
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 6 6 6 10 10 10 10 10 10
+- 10 10 10 6 6 6 6 6 6 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 10 10 10 14 14 14
+- 22 22 22 26 26 26 30 30 30 34 34 34
+- 30 30 30 30 30 30 26 26 26 18 18 18
+- 14 14 14 10 10 10 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 26 26 26 42 42 42
+- 54 54 54 66 66 66 78 78 78 78 78 78
+- 78 78 78 74 74 74 66 66 66 54 54 54
+- 42 42 42 26 26 26 18 18 18 10 10 10
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 22 22 22 42 42 42 66 66 66 86 86 86
+- 66 66 66 38 38 38 38 38 38 22 22 22
+- 26 26 26 34 34 34 54 54 54 66 66 66
+- 86 86 86 70 70 70 46 46 46 26 26 26
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 26 26 26
+- 50 50 50 82 82 82 58 58 58 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 54 54 54 86 86 86 66 66 66
+- 38 38 38 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 22 22 22 50 50 50
+- 78 78 78 34 34 34 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 6 6 6 70 70 70
+- 78 78 78 46 46 46 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 42 42 42 82 82 82
+- 26 26 26 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 14 14 14
+- 46 46 46 34 34 34 6 6 6 2 2 6
+- 42 42 42 78 78 78 42 42 42 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 30 30 30 66 66 66 58 58 58
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 26 26 26
+- 86 86 86 101 101 101 46 46 46 10 10 10
+- 2 2 6 58 58 58 70 70 70 34 34 34
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 42 42 42 86 86 86 10 10 10
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 30 30 30
+- 94 94 94 94 94 94 58 58 58 26 26 26
+- 2 2 6 6 6 6 78 78 78 54 54 54
+- 22 22 22 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 62 62 62 62 62 62 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 26 26 26
+- 54 54 54 38 38 38 18 18 18 10 10 10
+- 2 2 6 2 2 6 34 34 34 82 82 82
+- 38 38 38 14 14 14 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 30 30 30 78 78 78 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 10 10 10 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 78 78 78
+- 50 50 50 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 14 14 14 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 54 54 54
+- 66 66 66 26 26 26 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 82 82 82 2 2 6 2 2 6
+- 2 2 6 6 6 6 10 10 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 14 14 14 10 10 10 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 18 18 18
+- 82 82 82 34 34 34 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 2 2 6
+- 6 6 6 6 6 6 22 22 22 34 34 34
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 34 34 34
+- 10 10 10 50 50 50 22 22 22 2 2 6
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 86 86 86 42 42 42 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 2 2 6
+- 38 38 38 116 116 116 94 94 94 22 22 22
+- 22 22 22 2 2 6 2 2 6 2 2 6
+- 14 14 14 86 86 86 138 138 138 162 162 162
+-154 154 154 38 38 38 26 26 26 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 86 86 86 46 46 46 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 14 14 14
+-134 134 134 198 198 198 195 195 195 116 116 116
+- 10 10 10 2 2 6 2 2 6 6 6 6
+-101 98 89 187 187 187 210 210 210 218 218 218
+-214 214 214 134 134 134 14 14 14 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 86 86 86 50 50 50 18 18 18 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 54 54 54
+-218 218 218 195 195 195 226 226 226 246 246 246
+- 58 58 58 2 2 6 2 2 6 30 30 30
+-210 210 210 253 253 253 174 174 174 123 123 123
+-221 221 221 234 234 234 74 74 74 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 82 82 82 2 2 6 106 106 106
+-170 170 170 26 26 26 86 86 86 226 226 226
+-123 123 123 10 10 10 14 14 14 46 46 46
+-231 231 231 190 190 190 6 6 6 70 70 70
+- 90 90 90 238 238 238 158 158 158 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 86 86 86 6 6 6 116 116 116
+-106 106 106 6 6 6 70 70 70 149 149 149
+-128 128 128 18 18 18 38 38 38 54 54 54
+-221 221 221 106 106 106 2 2 6 14 14 14
+- 46 46 46 190 190 190 198 198 198 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 62 62 62 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 94 94 94 14 14 14 101 101 101
+-128 128 128 2 2 6 18 18 18 116 116 116
+-118 98 46 121 92 8 121 92 8 98 78 10
+-162 162 162 106 106 106 2 2 6 2 2 6
+- 2 2 6 195 195 195 195 195 195 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 62 62 62 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 1
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 90 90 90 14 14 14 58 58 58
+-210 210 210 26 26 26 54 38 6 154 114 10
+-226 170 11 236 186 11 225 175 15 184 144 12
+-215 174 15 175 146 61 37 26 9 2 2 6
+- 70 70 70 246 246 246 138 138 138 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 66 66 66 26 26 26 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 14 14 14 10 10 10
+-195 195 195 188 164 115 192 133 9 225 175 15
+-239 182 13 234 190 10 232 195 16 232 200 30
+-245 207 45 241 208 19 232 195 16 184 144 12
+-218 194 134 211 206 186 42 42 42 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 50 50 50 74 74 74 30 30 30 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 86 86 86 14 14 14 2 2 6
+-121 87 25 192 133 9 219 162 10 239 182 13
+-236 186 11 232 195 16 241 208 19 244 214 54
+-246 218 60 246 218 38 246 215 20 241 208 19
+-241 208 19 226 184 13 121 87 25 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 50 50 50 82 82 82 34 34 34 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 82 82 82 30 30 30 61 42 6
+-180 123 7 206 145 10 230 174 11 239 182 13
+-234 190 10 238 202 15 241 208 19 246 218 74
+-246 218 38 246 215 20 246 215 20 246 215 20
+-226 184 13 215 174 15 184 144 12 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 26 26 26 94 94 94 42 42 42 14 14 14
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 50 50 50 104 69 6
+-192 133 9 216 158 10 236 178 12 236 186 11
+-232 195 16 241 208 19 244 214 54 245 215 43
+-246 215 20 246 215 20 241 208 19 198 155 10
+-200 144 11 216 158 10 156 118 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 90 90 90 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 46 46 46 22 22 22
+-137 92 6 210 162 10 239 182 13 238 190 10
+-238 202 15 241 208 19 246 215 20 246 215 20
+-241 208 19 203 166 17 185 133 11 210 150 10
+-216 158 10 210 150 10 102 78 10 2 2 6
+- 6 6 6 54 54 54 14 14 14 2 2 6
+- 2 2 6 62 62 62 74 74 74 30 30 30
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 78 78 78 50 50 50 6 6 6
+- 94 70 30 139 102 15 190 146 13 226 184 13
+-232 200 30 232 195 16 215 174 15 190 146 13
+-168 122 10 192 133 9 210 150 10 213 154 11
+-202 150 34 182 157 106 101 98 89 2 2 6
+- 2 2 6 78 78 78 116 116 116 58 58 58
+- 2 2 6 22 22 22 90 90 90 46 46 46
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 50 50 50 6 6 6
+-128 128 128 174 154 114 156 107 11 168 122 10
+-198 155 10 184 144 12 197 138 11 200 144 11
+-206 145 10 206 145 10 197 138 11 188 164 115
+-195 195 195 198 198 198 174 174 174 14 14 14
+- 2 2 6 22 22 22 116 116 116 116 116 116
+- 22 22 22 2 2 6 74 74 74 70 70 70
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 101 101 101 26 26 26 10 10 10
+-138 138 138 190 190 190 174 154 114 156 107 11
+-197 138 11 200 144 11 197 138 11 192 133 9
+-180 123 7 190 142 34 190 178 144 187 187 187
+-202 202 202 221 221 221 214 214 214 66 66 66
+- 2 2 6 2 2 6 50 50 50 62 62 62
+- 6 6 6 2 2 6 10 10 10 90 90 90
+- 50 50 50 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 34 34 34
+- 74 74 74 74 74 74 2 2 6 6 6 6
+-144 144 144 198 198 198 190 190 190 178 166 146
+-154 121 60 156 107 11 156 107 11 168 124 44
+-174 154 114 187 187 187 190 190 190 210 210 210
+-246 246 246 253 253 253 253 253 253 182 182 182
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 62 62 62
+- 74 74 74 34 34 34 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 10 10 10 22 22 22 54 54 54
+- 94 94 94 18 18 18 2 2 6 46 46 46
+-234 234 234 221 221 221 190 190 190 190 190 190
+-190 190 190 187 187 187 187 187 187 190 190 190
+-190 190 190 195 195 195 214 214 214 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+- 82 82 82 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 14 14 14
+- 86 86 86 54 54 54 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 46 46 46 90 90 90
+- 46 46 46 18 18 18 6 6 6 182 182 182
+-253 253 253 246 246 246 206 206 206 190 190 190
+-190 190 190 190 190 190 190 190 190 190 190 190
+-206 206 206 231 231 231 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-202 202 202 14 14 14 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 42 42 42 86 86 86 42 42 42 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 14 14 14 38 38 38 74 74 74 66 66 66
+- 2 2 6 6 6 6 90 90 90 250 250 250
+-253 253 253 253 253 253 238 238 238 198 198 198
+-190 190 190 190 190 190 195 195 195 221 221 221
+-246 246 246 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 82 82 82 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 78 78 78 70 70 70 34 34 34
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 34 34 34 66 66 66 78 78 78 6 6 6
+- 2 2 6 18 18 18 218 218 218 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-226 226 226 231 231 231 246 246 246 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 178 178 178 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 18 18 18 90 90 90 62 62 62
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 26 26 26
+- 58 58 58 90 90 90 18 18 18 2 2 6
+- 2 2 6 110 110 110 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 231 231 231 18 18 18 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 94 94 94
+- 54 54 54 26 26 26 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 22 22 22 50 50 50
+- 90 90 90 26 26 26 2 2 6 2 2 6
+- 14 14 14 195 195 195 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 242 242 242 54 54 54 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+- 86 86 86 50 50 50 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 38 38 38 82 82 82
+- 34 34 34 2 2 6 2 2 6 2 2 6
+- 42 42 42 195 195 195 246 246 246 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 242 242 242 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 246 246 246 238 238 238
+-226 226 226 231 231 231 101 101 101 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 38 38 38 82 82 82 42 42 42 14 14 14
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 26 26 26 62 62 62 66 66 66
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 70 70 70 170 170 170 206 206 206 234 234 234
+-246 246 246 250 250 250 250 250 250 238 238 238
+-226 226 226 231 231 231 238 238 238 250 250 250
+-250 250 250 250 250 250 246 246 246 231 231 231
+-214 214 214 206 206 206 202 202 202 202 202 202
+-198 198 198 202 202 202 182 182 182 18 18 18
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 62 62 62 66 66 66 30 30 30
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 42 42 42 82 82 82 18 18 18
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 94 94 94 182 182 182 218 218 218 242 242 242
+-250 250 250 253 253 253 253 253 253 250 250 250
+-234 234 234 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-238 238 238 226 226 226 210 210 210 202 202 202
+-195 195 195 195 195 195 210 210 210 158 158 158
+- 6 6 6 14 14 14 50 50 50 14 14 14
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 86 86 86 46 46 46
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 54 54 54 70 70 70 2 2 6
+- 2 2 6 10 10 10 2 2 6 22 22 22
+-166 166 166 231 231 231 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-231 231 231 206 206 206 198 198 198 226 226 226
+- 94 94 94 2 2 6 6 6 6 38 38 38
+- 30 30 30 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 62 62 62 66 66 66
+- 26 26 26 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 74 74 74 50 50 50 2 2 6
+- 26 26 26 26 26 26 2 2 6 106 106 106
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 246 246 246 218 218 218 202 202 202
+-210 210 210 14 14 14 2 2 6 2 2 6
+- 30 30 30 22 22 22 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 86 86 86
+- 42 42 42 14 14 14 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 90 90 90 22 22 22 2 2 6
+- 42 42 42 2 2 6 18 18 18 218 218 218
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 250 250 250 221 221 221
+-218 218 218 101 101 101 2 2 6 14 14 14
+- 18 18 18 38 38 38 10 10 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 78 78 78
+- 58 58 58 22 22 22 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 54 54 54 82 82 82 2 2 6 26 26 26
+- 22 22 22 2 2 6 123 123 123 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-238 238 238 198 198 198 6 6 6 38 38 38
+- 58 58 58 26 26 26 38 38 38 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 78 78 78 30 30 30 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 30 30 30
+- 74 74 74 58 58 58 2 2 6 42 42 42
+- 2 2 6 22 22 22 231 231 231 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 246 246 246 46 46 46 38 38 38
+- 42 42 42 14 14 14 38 38 38 14 14 14
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 86 86 86 46 46 46 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 42 42 42
+- 90 90 90 18 18 18 18 18 18 26 26 26
+- 2 2 6 116 116 116 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 250 250 250 238 238 238
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 94 94 94 6 6 6
+- 2 2 6 2 2 6 10 10 10 34 34 34
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 10 10 10 26 26 26 66 66 66
+- 82 82 82 2 2 6 38 38 38 6 6 6
+- 14 14 14 210 210 210 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 246 246 246 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 144 144 144 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 42 42 42 74 74 74 30 30 30 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 42 42 42 90 90 90
+- 26 26 26 6 6 6 42 42 42 2 2 6
+- 74 74 74 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 242 242 242 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 182 182 182 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 10 10 10 86 86 86 38 38 38 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 26 26 26 66 66 66 82 82 82
+- 2 2 6 22 22 22 18 18 18 2 2 6
+-149 149 149 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 206 206 206 2 2 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 86 86 86 46 46 46 14 14 14
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 18 18 18 46 46 46 86 86 86 18 18 18
+- 2 2 6 34 34 34 10 10 10 6 6 6
+-210 210 210 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 221 221 221 6 6 6
+- 2 2 6 2 2 6 6 6 6 30 30 30
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 82 82 82 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 26 26 26 66 66 66 62 62 62 2 2 6
+- 2 2 6 38 38 38 10 10 10 26 26 26
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 238 238 238
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 6 6 6
+- 2 2 6 2 2 6 10 10 10 30 30 30
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 58 58 58 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 78 78 78 6 6 6 2 2 6
+- 2 2 6 46 46 46 14 14 14 42 42 42
+-246 246 246 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 10 10 10
+- 2 2 6 2 2 6 22 22 22 14 14 14
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 62 62 62 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 74 74 74 2 2 6 2 2 6
+- 14 14 14 70 70 70 34 34 34 62 62 62
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 14 14 14
+- 2 2 6 2 2 6 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 62 62 62 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 54 54 54 62 62 62 2 2 6 2 2 6
+- 2 2 6 30 30 30 46 46 46 70 70 70
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 226 226 226 10 10 10
+- 2 2 6 6 6 6 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 58 58 58 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 58 58 58 62 62 62 2 2 6 2 2 6
+- 2 2 6 2 2 6 30 30 30 78 78 78
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 206 206 206 2 2 6
+- 22 22 22 34 34 34 18 14 6 22 22 22
+- 26 26 26 18 18 18 6 6 6 2 2 6
+- 2 2 6 82 82 82 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 26 26 26
+- 62 62 62 106 106 106 74 54 14 185 133 11
+-210 162 10 121 92 8 6 6 6 62 62 62
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 158 158 158 18 18 18
+- 14 14 14 2 2 6 2 2 6 2 2 6
+- 6 6 6 18 18 18 66 66 66 38 38 38
+- 6 6 6 94 94 94 50 50 50 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 10 10 10 10 10 10 18 18 18 38 38 38
+- 78 78 78 142 134 106 216 158 10 242 186 14
+-246 190 14 246 190 14 156 118 10 10 10 10
+- 90 90 90 238 238 238 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 230 190
+-238 204 91 238 204 91 181 142 44 37 26 9
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 38 38 38 46 46 46
+- 26 26 26 106 106 106 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 22 22 22
+- 30 30 30 38 38 38 50 50 50 70 70 70
+-106 106 106 190 142 34 226 170 11 242 186 14
+-246 190 14 246 190 14 246 190 14 154 114 10
+- 6 6 6 74 74 74 226 226 226 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 228 184 62
+-241 196 14 241 208 19 232 195 16 38 30 10
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 30 30 30 26 26 26
+-203 166 17 154 142 90 66 66 66 26 26 26
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 38 38 38 58 58 58
+- 78 78 78 86 86 86 101 101 101 123 123 123
+-175 146 61 210 150 10 234 174 13 246 186 14
+-246 190 14 246 190 14 246 190 14 238 190 10
+-102 78 10 2 2 6 46 46 46 198 198 198
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 224 178 62
+-242 186 14 241 196 14 210 166 10 22 18 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 6 6 6 121 92 8
+-238 202 15 232 195 16 82 82 82 34 34 34
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 38 38 38 70 70 70 154 122 46
+-190 142 34 200 144 11 197 138 11 197 138 11
+-213 154 11 226 170 11 242 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-225 175 15 46 32 6 2 2 6 22 22 22
+-158 158 158 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 242 242 242 224 178 62
+-239 182 13 236 186 11 213 154 11 46 32 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 61 42 6 225 175 15
+-238 190 10 236 186 11 112 100 78 42 42 42
+- 14 14 14 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 54 54 54 154 122 46 213 154 11
+-226 170 11 230 174 11 226 170 11 226 170 11
+-236 178 12 242 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-241 196 14 184 144 12 10 10 10 2 2 6
+- 6 6 6 116 116 116 242 242 242 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 231 231 231 198 198 198 214 170 54
+-236 178 12 236 178 12 210 150 10 137 92 6
+- 18 14 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 70 47 6 200 144 11 236 178 12
+-239 182 13 239 182 13 124 112 88 58 58 58
+- 22 22 22 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 70 70 70 180 133 36 226 170 11
+-239 182 13 242 186 14 242 186 14 246 186 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 232 195 16 98 70 6 2 2 6
+- 2 2 6 2 2 6 66 66 66 221 221 221
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 206 206 206 198 198 198 214 166 58
+-230 174 11 230 174 11 216 158 10 192 133 9
+-163 110 8 116 81 8 102 78 10 116 81 8
+-167 114 7 197 138 11 226 170 11 239 182 13
+-242 186 14 242 186 14 162 146 94 78 78 78
+- 34 34 34 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 30 30 30 78 78 78 190 142 34 226 170 11
+-239 182 13 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 241 196 14 203 166 17 22 18 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+-218 218 218 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 206 206 206 198 198 198 202 162 69
+-226 170 11 236 178 12 224 166 10 210 150 10
+-200 144 11 197 138 11 192 133 9 197 138 11
+-210 150 10 226 170 11 242 186 14 246 190 14
+-246 190 14 246 186 14 225 175 15 124 112 88
+- 62 62 62 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 174 135 50 224 166 10
+-239 182 13 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 241 196 14 139 102 15
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 78 78 78 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 214 214 214 198 198 198 190 150 46
+-219 162 10 236 178 12 234 174 13 224 166 10
+-216 158 10 213 154 11 213 154 11 216 158 10
+-226 170 11 239 182 13 246 190 14 246 190 14
+-246 190 14 246 190 14 242 186 14 206 162 42
+-101 101 101 58 58 58 30 30 30 14 14 14
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 74 74 74 174 135 50 216 158 10
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 241 196 14 226 184 13
+- 61 42 6 2 2 6 2 2 6 2 2 6
+- 22 22 22 238 238 238 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 226 226 226 187 187 187 180 133 36
+-216 158 10 236 178 12 239 182 13 236 178 12
+-230 174 11 226 170 11 226 170 11 230 174 11
+-236 178 12 242 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 186 14 239 182 13
+-206 162 42 106 106 106 66 66 66 34 34 34
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 26 26 26 70 70 70 163 133 67 213 154 11
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 241 196 14
+-190 146 13 18 14 6 2 2 6 2 2 6
+- 46 46 46 246 246 246 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 221 221 221 86 86 86 156 107 11
+-216 158 10 236 178 12 242 186 14 246 186 14
+-242 186 14 239 182 13 239 182 13 242 186 14
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-242 186 14 225 175 15 142 122 72 66 66 66
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 26 26 26 70 70 70 163 133 67 210 150 10
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-232 195 16 121 92 8 34 34 34 106 106 106
+-221 221 221 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-242 242 242 82 82 82 18 14 6 163 110 8
+-216 158 10 236 178 12 242 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 242 186 14 163 133 67
+- 46 46 46 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 163 133 67 210 150 10
+-236 178 12 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-241 196 14 215 174 15 190 178 144 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 218 218 218
+- 58 58 58 2 2 6 22 18 6 167 114 7
+-216 158 10 236 178 12 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 186 14 242 186 14 190 150 46
+- 54 54 54 22 22 22 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 38 38 38 86 86 86 180 133 36 213 154 11
+-236 178 12 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 232 195 16 190 146 13 214 214 214
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 170 170 170 26 26 26
+- 2 2 6 2 2 6 37 26 9 163 110 8
+-219 162 10 239 182 13 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 236 178 12 224 166 10 142 122 72
+- 46 46 46 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 109 106 95 192 133 9 224 166 10
+-242 186 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-242 186 14 226 184 13 210 162 10 142 110 46
+-226 226 226 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-198 198 198 66 66 66 2 2 6 2 2 6
+- 2 2 6 2 2 6 50 34 6 156 107 11
+-219 162 10 239 182 13 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 242 186 14
+-234 174 13 213 154 11 154 122 46 66 66 66
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 58 58 58 154 121 60 206 145 10 234 174 13
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 236 178 12 210 162 10 163 110 8
+- 61 42 6 138 138 138 218 218 218 250 250 250
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 210 210 210 144 144 144 66 66 66
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 61 42 6 163 110 8
+-216 158 10 236 178 12 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 239 182 13 230 174 11 216 158 10
+-190 142 34 124 112 88 70 70 70 38 38 38
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 62 62 62 168 124 44 206 145 10 224 166 10
+-236 178 12 239 182 13 242 186 14 242 186 14
+-246 186 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 236 178 12 216 158 10 175 118 6
+- 80 54 7 2 2 6 6 6 6 30 30 30
+- 54 54 54 62 62 62 50 50 50 38 38 38
+- 14 14 14 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 80 54 7 167 114 7
+-213 154 11 236 178 12 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 242 186 14 239 182 13 239 182 13
+-230 174 11 210 150 10 174 135 50 124 112 88
+- 82 82 82 54 54 54 34 34 34 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 158 118 36 192 133 9 200 144 11
+-216 158 10 219 162 10 224 166 10 226 170 11
+-230 174 11 236 178 12 239 182 13 239 182 13
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 230 174 11 210 150 10 163 110 8
+-104 69 6 10 10 10 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 91 60 6 167 114 7
+-206 145 10 230 174 11 242 186 14 246 190 14
+-246 190 14 246 190 14 246 186 14 242 186 14
+-239 182 13 230 174 11 224 166 10 213 154 11
+-180 133 36 124 112 88 86 86 86 58 58 58
+- 38 38 38 22 22 22 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 34 34 34 70 70 70 138 110 50 158 118 36
+-167 114 7 180 123 7 192 133 9 197 138 11
+-200 144 11 206 145 10 213 154 11 219 162 10
+-224 166 10 230 174 11 239 182 13 242 186 14
+-246 186 14 246 186 14 246 186 14 246 186 14
+-239 182 13 216 158 10 185 133 11 152 99 6
+-104 69 6 18 14 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 80 54 7 152 99 6
+-192 133 9 219 162 10 236 178 12 239 182 13
+-246 186 14 242 186 14 239 182 13 236 178 12
+-224 166 10 206 145 10 192 133 9 154 121 60
+- 94 94 94 62 62 62 42 42 42 22 22 22
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 18 18 18 34 34 34 58 58 58 78 78 78
+-101 98 89 124 112 88 142 110 46 156 107 11
+-163 110 8 167 114 7 175 118 6 180 123 7
+-185 133 11 197 138 11 210 150 10 219 162 10
+-226 170 11 236 178 12 236 178 12 234 174 13
+-219 162 10 197 138 11 163 110 8 130 83 6
+- 91 60 6 10 10 10 2 2 6 2 2 6
+- 18 18 18 38 38 38 38 38 38 38 38 38
+- 38 38 38 38 38 38 38 38 38 38 38 38
+- 38 38 38 38 38 38 26 26 26 2 2 6
+- 2 2 6 6 6 6 70 47 6 137 92 6
+-175 118 6 200 144 11 219 162 10 230 174 11
+-234 174 13 230 174 11 219 162 10 210 150 10
+-192 133 9 163 110 8 124 112 88 82 82 82
+- 50 50 50 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 22 22 22 34 34 34
+- 42 42 42 58 58 58 74 74 74 86 86 86
+-101 98 89 122 102 70 130 98 46 121 87 25
+-137 92 6 152 99 6 163 110 8 180 123 7
+-185 133 11 197 138 11 206 145 10 200 144 11
+-180 123 7 156 107 11 130 83 6 104 69 6
+- 50 34 6 54 54 54 110 110 110 101 98 89
+- 86 86 86 82 82 82 78 78 78 78 78 78
+- 78 78 78 78 78 78 78 78 78 78 78 78
+- 78 78 78 82 82 82 86 86 86 94 94 94
+-106 106 106 101 101 101 86 66 34 124 80 6
+-156 107 11 180 123 7 192 133 9 200 144 11
+-206 145 10 200 144 11 192 133 9 175 118 6
+-139 102 15 109 106 95 70 70 70 42 42 42
+- 22 22 22 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 10 10 10
+- 14 14 14 22 22 22 30 30 30 38 38 38
+- 50 50 50 62 62 62 74 74 74 90 90 90
+-101 98 89 112 100 78 121 87 25 124 80 6
+-137 92 6 152 99 6 152 99 6 152 99 6
+-138 86 6 124 80 6 98 70 6 86 66 30
+-101 98 89 82 82 82 58 58 58 46 46 46
+- 38 38 38 34 34 34 34 34 34 34 34 34
+- 34 34 34 34 34 34 34 34 34 34 34 34
+- 34 34 34 34 34 34 38 38 38 42 42 42
+- 54 54 54 82 82 82 94 86 76 91 60 6
+-134 86 6 156 107 11 167 114 7 175 118 6
+-175 118 6 167 114 7 152 99 6 121 87 25
+-101 98 89 62 62 62 34 34 34 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 6 6 6 10 10 10
+- 18 18 18 22 22 22 30 30 30 42 42 42
+- 50 50 50 66 66 66 86 86 86 101 98 89
+-106 86 58 98 70 6 104 69 6 104 69 6
+-104 69 6 91 60 6 82 62 34 90 90 90
+- 62 62 62 38 38 38 22 22 22 14 14 14
+- 10 10 10 10 10 10 10 10 10 10 10 10
+- 10 10 10 10 10 10 6 6 6 10 10 10
+- 10 10 10 10 10 10 10 10 10 14 14 14
+- 22 22 22 42 42 42 70 70 70 89 81 66
+- 80 54 7 104 69 6 124 80 6 137 92 6
+-134 86 6 116 81 8 100 82 52 86 86 86
+- 58 58 58 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 10 10 10 14 14 14
+- 18 18 18 26 26 26 38 38 38 54 54 54
+- 70 70 70 86 86 86 94 86 76 89 81 66
+- 89 81 66 86 86 86 74 74 74 50 50 50
+- 30 30 30 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 34 34 34 58 58 58
+- 82 82 82 89 81 66 89 81 66 89 81 66
+- 94 86 66 94 86 76 74 74 74 50 50 50
+- 26 26 26 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 6 6 6 14 14 14 18 18 18
+- 30 30 30 38 38 38 46 46 46 54 54 54
+- 50 50 50 42 42 42 30 30 30 18 18 18
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 26 26 26
+- 38 38 38 50 50 50 58 58 58 58 58 58
+- 54 54 54 42 42 42 30 30 30 18 18 18
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 6 6 6 10 10 10 14 14 14 18 18 18
+- 18 18 18 14 14 14 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 14 14 14 18 18 18 22 22 22 22 22 22
+- 18 18 18 14 14 14 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 162 242 242 105 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 188 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 153 255 255 105 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 116 255 255 92 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 37 255 255 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 237 255 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 214 255 67 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 199 255 68 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 181 255 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 181 255 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 210 250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 150 234 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 69 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 26 73 86 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 79 22 0 0 0 23 132
++224 229 152 26 0 0 119 212 254 255 255 255 79 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 92 190 255 255 242 62 0 116 239 255
++255 255 255 221 117 215 255 255 255 255 229 241 255 0 0 0 0 0 0 0 0 0 0 0 35 106
++143 131 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 149 255 255 244 255 224 191 255 255 255
++229 83 144 255 255 255 255 237 133 44 0 141 255 131 0 0 0 0 0 0 0 0 50 175 255 255
++255 255 255 148 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 145 119 197 255 255 255 255 246 131
++8 0 147 255 255 255 128 13 0 0 0 181 255 151 0 0 0 0 0 0 20 154 255 255 255 255
++255 226 226 255 150 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 249 255 255 255 153 30 0
++0 0 212 255 232 44 0 0 0 0 0 234 255 120 0 0 0 0 0 42 233 255 255 255 233 126
++77 3 0 207 248 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 92 255 240 139 83 0 0 0
++0 38 255 255 161 0 0 0 0 0 33 255 255 74 0 0 0 0 16 239 255 255 244 121 11 0
++0 0 0 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 255 195 0 0 0 0 0
++0 120 255 255 108 0 0 0 0 0 77 255 255 29 0 0 0 0 212 255 255 179 26 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 48 42
++53 98 104 90 67 36 3 0 0 0 0 0 0 0 0 0 0 9 253 255 122 0 0 0 0 0
++0 210 255 255 57 0 0 0 0 0 174 255 238 1 0 0 0 171 255 255 180 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 40 123 160 183 221 255 255 249
++254 255 255 255 255 255 231 204 151 79 2 0 0 0 0 0 0 144 255 255 26 0 0 0 0 0
++14 255 255 243 5 0 0 0 0 30 255 255 217 0 0 0 101 255 255 243 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 99 250 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 237 138 3 0 0 0 0 0 33 255 255 158 0 0 0 0 0 0
++94 255 255 176 0 0 0 0 0 154 255 255 137 0 0 12 255 255 255 51 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 54 161 187 238 255 255 255 255 255 255
++218 211 178 191 178 134 97 49 0 0 0 0 0 0 0 0 193 255 251 16 0 0 0 0 0 0
++222 255 255 90 0 0 0 0 6 251 255 255 26 0 0 79 255 255 107 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 13 71 95 113 119 106 64
++7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 255 255 105 0 0 0 0 0 0 90
++255 255 255 25 0 0 0 0 125 255 255 168 0 0 0 146 255 210 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 229 255 225 0 0 0 0 0 0 0 246
++255 255 183 0 0 0 0 13 239 255 255 30 0 0 0 192 255 108 0 0 0 0 0 0 0 0
++0 0 0 0 62 134 10 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 176 255 255 73 0 0 0 0 0 0 194 255
++255 255 42 0 0 0 0 109 255 255 78 0 0 0 0 217 255 76 0 0 0 0 0 0 0 0
++0 0 71 170 255 206 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 101 255 255 148 0 0 0 0 0 0 70 255 255
++255 147 0 0 0 0 0 238 255 148 0 0 0 0 0 230 255 30 0 0 0 0 0 0 0 0
++35 192 255 255 204 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 14 251 255 192 0 0 0 0 0 0 0 217 255 255
++203 0 0 0 0 0 0 143 136 0 0 0 0 0 0 166 255 127 0 0 0 0 0 0 25 111
++250 255 255 209 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 165 255 249 0 0 0 0 0 0 0 123 255 255 197
++6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 255 255 189 111 34 33 97 158 247 255
++255 255 255 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 55 255 253 63 0 0 0 0 0 0 0 166 210 91 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 255 255 255 255 255 255 255 255 255
++255 241 78 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 59 169 56 0 0 0 0 0 0 0 0 2 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 205 255 255 255 255 255 255 255
++205 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 161 238 249 247 200 105
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 23 20 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 118 195 124 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 1 3 0 0 0 91 118 31 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 1 0 0 28 132 126 149 161 82 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 79 73 81 58 4 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 105 112 123 131 138 18 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 118 132 85 55 76 73 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 21 47 75 82 90 91 106 51 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 20 5 0 0 0 5 179 194 171 171 170 152 157 175 56 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 158 76 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 228 164 0 0 0 0 64 188 202 211 195 179 182 184 188 195 36
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 233 228 0 0 0 0 48 48 0 3 0 0 0 3 13 59 30
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 219 255 10 0 0 0 7 36 88 130 140 122 136 174 179 181 203
++195 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 221 255 39 0 0 0 69 161 183 141 112 126 159 126 71 60 50
++67 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 239 255 44 0 0 0 0 0 0 0 0 0 0 0 59 63 6
++0 56 63 43 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 30 255 255 69 0 0 1 131 180 171 177 181 189 196 216 202 197 196
++209 200 175 174 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 76 255 255 100 0 0 1 74 138 123 102 94 85 81 42 0 0 20
++43 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 107 255 255 150 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 137 255 255 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 128 242 241 221 4 0 0 0 0 0 0 0 0 0 0 0 0 0
++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/system/easy-kernel/APKBUILD b/system/easy-kernel/APKBUILD
index 580e59ff9..cc2ff00d7 100644
--- a/system/easy-kernel/APKBUILD
+++ b/system/easy-kernel/APKBUILD
@@ -2,9 +2,9 @@
# Maintainer: Adelie Platform Group <adelie-devel@lists.adelielinux.org>
# KEEP THIS IN SYNC with the other easy-kernel packages.
_kflavour=""
-_patchver=1
+_patchver=1 # must match 1000-version.patch ???
_pkgname=easy-kernel$_kflavour
-pkgver=5.4.66
+pkgver=5.15.11
pkgrel=0
pkgname=$_pkgname-$pkgver-mc$_patchver
pkgdesc="The Linux kernel, packaged for your convenience"
@@ -17,12 +17,10 @@ makedepends="bc bison flex gzip kmod lzop openssl-dev rsync xz"
provides="easy-kernel$_kflavour=$pkgver-r$pkgrel"
replaces="easy-kernel-power8 easy-kernel-power8-64k"
subpackages="$_pkgname-modules-$pkgver-mc$_patchver:modules
- $_pkgname-src-$pkgver-mc$_patchver:src
- linux-headers:headers"
+ $_pkgname-src-$pkgver-mc$_patchver:src"
_pkgmajver=${pkgver%%.*}
_pkgminver=${pkgver%.*}
source="https://cdn.kernel.org/pub/linux/kernel/v${_pkgmajver}.x/linux-${_pkgminver}.tar.xz
- https://distfiles.adelielinux.org/source/linux-${_pkgminver}-mc$_patchver-patches.tar.xz
config-aarch64
config-armv7
config-m68k
@@ -31,17 +29,29 @@ source="https://cdn.kernel.org/pub/linux/kernel/v${_pkgmajver}.x/linux-${_pkgmin
config-ppc64
config-sparc64
config-x86_64
- kernel.h
- uapi-iphdr.patch
+
+ 0100-linux-5.15.11.patch
+ 0120-XATTR_USER_PREFIX.patch
+ 0122-link-security-restrictions.patch
+ 0124-bluetooth-keysize-check.patch
+ 0126-sign-file-libressl.patch
+ 0130-lrng.patch
+ 0250-projectc-5.15-r1.patch
+ 0255-ultra-ksm.patch
+ 0260-reduce-swappiness.patch
+ 0300-tmp513-regression-fix.patch
+ 0500-print-fw-info.patch
+ 0502-gcc9-kcflags.patch
+ 1000-version.patch
+
+ no-require-gnu-tar.patch
+ no-require-lilo.patch
no-autoload-fb.conf
"
builddir="$srcdir/linux-${_pkgminver}"
prepare() {
- for patch in "$srcdir/linux-${_pkgminver}-mc$_patchver-patches"/*; do
- patch -p1 -i "$patch"
- done
default_prepare
cd "$srcdir"
@@ -98,7 +108,7 @@ modules() {
provides="easy-kernel$_kflavour-modules=$pkgver-r$pkgrel"
autodeps=0 # modules should not depend on src just for symlink
mkdir -p "$subpkgdir"/lib
- mv "$pkgdir"/lib/modules "$subpkgdir"/lib/
+ mv "$pkgdir"/lib/modules "$subpkgdir"/lib
rm "$subpkgdir"/lib/modules/$pkgver-mc$_patchver-easy$_kflavour/build
rm "$subpkgdir"/lib/modules/$pkgver-mc$_patchver-easy$_kflavour/source
ln -s "../../../usr/src/linux-$pkgver-mc$_patchver$_kflavour" \
@@ -111,26 +121,6 @@ modules() {
"$subpkgdir"/etc/modprobe.d/no-autoload-fb.conf
}
-headers() {
- pkgdesc="System headers provided by the Linux kernel"
- cd "$builddir"
-
- mkdir -p "$subpkgdir"/usr
- make headers_install INSTALL_HDR_PATH="$subpkgdir/usr"
-
- find "$subpkgdir/usr" \( -name .install -o -name ..install.cmd \) -exec \
- rm -f {} \;
-
- # provided by libdrm
- rm -rf "$subpkgdir"/usr/include/drm
-
- # needed for spl, VMware on x86, etc
- install -D -m644 "$builddir"/include/generated/utsrelease.h \
- "$subpkgdir"/usr/include/linux/utsrelease.h
-
- install -m644 "$srcdir"/kernel.h "$subpkgdir"/usr/include/linux/kernel.h
-}
-
src() {
pkgdesc="Kernel source code used to build the kernel"
provides="easy-kernel$_kflavour-src=$pkgver-r$pkgrel"
@@ -138,16 +128,28 @@ src() {
mv "$srcdir"/linux-src "$subpkgdir"/usr/src/linux-$pkgver-mc$_patchver$_kflavour
}
-sha512sums="9f60f77e8ab972b9438ac648bed17551c8491d6585a5e85f694b2eaa4c623fbc61eb18419b2656b6795eac5deec0edaa04547fc6723fbda52256bd7f3486898f linux-5.4.tar.xz
-e6a7a5933dbe638be42a1308fd64895e53fe38be1238016a560985127106356570e6ea6ba94e6fbfb5924e24728232487c91ff1affcc79af1d724b8c813f5036 linux-5.4-mc1-patches.tar.xz
+sha512sums="d25ad40b5bcd6a4c6042fd0fd84e196e7a58024734c3e9a484fd0d5d54a0c1d87db8a3c784eff55e43b6f021709dc685eb0efa18d2aec327e4f88a79f405705a linux-5.15.tar.xz
1559875f5abc07d478d7deb9a2b1eccbb2e1a37b300ed6e41b28787f3653a18d92fbff4fad74df300cf7d6c027ba4c98a65050e60ce6da8f2a48e01bbf56dee8 config-aarch64
9f5279d20fc6eaad78ab27b7fb86553e310369c8a68a2ff60c7cd9895febd3002cae748ad3a8b4fddbb62c6e829104138fc2bbca939e1c88c0bfcf7aa42809bf config-armv7
93ca6d54fc377db12dfa7cf230d362f82d635cd05166815389ef4fb2b065f8b2bba1a78d234bd6a7445dd9b475f2c0ca01e3d4528881cfd2c10040dab174cf6a config-m68k
5945f918daf441e1f92012b608d560b693f09d8fa36eb6c7ecb9935dec6163c5e64e04d7345b3b9c958a15d62878f33ac88a4e24d5fcc60381455842636bd1c7 config-pmmx
3f9ac256e11b9e469086cbc0d3ec84e7bed4ec79fe40111418eb70786c9d62e8ef8d208472fa65f91b883b959112e40ace18d98314dfa9eeaace6aa821834f8b config-ppc
-c61fa4613d0d75a5387d12c2f72dc8ba1e6635cc47cc9fb46253095c6417241ef59639ddf9ad220947804ef0dca921de7df5057b1d02d156bf955b213851aaff config-ppc64
+6a79665fbfbbb720d619c88d4145cb75b47b690aa5c341617651ebec3ece35f0bd5a53c7ea62b9be92e83f1cc43c781b3fac4c91ea860e725a2ab4ac0911a834 config-ppc64
f43ae12574c81f6e0161c547eff93d70ff4686e6ec1654edbdea10447e424218a33b81c664828f82617e4ef522128f2e0460da0c9523538724048174b53a7313 config-sparc64
-557db84d1f45c91ed3e3ab5d0e7100766060507ae98632b735580813974e136343500f9683bb51dc3994277716651821523b476bc5143e636ebde14aa5e67f48 config-x86_64
-61dcd633d72876566b7738dd08856b26850c935b4a81ab2364711335fe01c397083160f530b3382bbc239c6a8135be6a032e93039083ec2cefdae2902429a2e0 kernel.h
-6f309a18c65c991240265afd200cc79a706f5d9e5d072838a9a641ab3676a5e4c32033f9767fc723ff4c45ee462169a0f77bd7dfe63b547d521dadd073f827a7 uapi-iphdr.patch
+19e35f80a23ed08613d61d2a5df78257664c66f4fee84d9464ab8587b9e0845596e428bfb770c9b4254aef4bc33cbde8e9fb4a2fa7f591cfca083733717948e2 config-x86_64
+508045b7150e025dbf3682528b62ee6162e3bd1acf4ff4b53c3b395f14bff0bb4769c4d8e4ea30604785a79ebb66953c4576574e15d1a5ade1c482d4c191fdf8 0100-linux-5.15.11.patch
+3ed100909f9aed72836a3c712e45e0116cd3c4331961a76a27b867a7098d0df9458387b656c9ea01385c3c37585436e48168ac35666b0e46dca7da05e5e38a61 0120-XATTR_USER_PREFIX.patch
+c97a3799a2d5e4da9c9dfe129756da629fba8183479b02ca82f9b6d9993f17a165a96bd35ac50eb25fb293785b9b529a95165b1a2eb79c05134bee8ccf22a5d3 0122-link-security-restrictions.patch
+dc47b18749d95a456f8bc47fd6a0618c286b646b38466c3d950dfbeb25adf3fc1a794e95552e4da1abb58e49f0bd841f7222e71c4d04cb0264ca23476ca9caef 0124-bluetooth-keysize-check.patch
+79eaf814d76402a445efc961666a7c7c74207e552b0cb32d93d5cb828da580f7dbe93509dc9f53321c7844663205a8dce4e518ba047e4c57fc55f5c3498088ec 0126-sign-file-libressl.patch
+27b0a76966f5ea36217a1686e9504e5cf34a319d7036f856c94ddc22f5e737b3c49bf8cc50508c20f476c4b24607eba194305d7073c50faad00046b0d72350a1 0130-lrng.patch
+c7760c874532a3268353bfc87977cfe8a58ae7dde85809c6dae2190a458c752401f8faf4119723b5583fb4f1834b34c278826b23c29c03412f7db431e6f2b20e 0250-projectc-5.15-r1.patch
+4c901fe38e197b0397702ec46329fac6cdd5b7ff6e2601f76f0cbabcf452581936c58028c3a93471782541ad3045b10d1030fad4b25121f35d091495d17fd308 0255-ultra-ksm.patch
+5f74e6a72876d3cf3b3188a43b999b981b6ea0ca401ad72b3c7d5cc65bf505f50e7ee17d435ec95b7a012dc92e6540aea1bdb501f48690c242705c47d2403513 0260-reduce-swappiness.patch
+4e637935c2f37cc18f347293e3c94b18f90e2caccca726304a95c4891257a5b2bb3093aee7a97571038b29c0c987cc60a9a80aefd0d4c9a063b33d102f03579e 0300-tmp513-regression-fix.patch
+a43fd7004715f4efd545fe27abad46cc6f8c4c5f3ba9ab27c74a004e74bd5e4106beaecd54ca785fee03a0b466021acfdba0afa07e9ee2965493334a24403ffc 0500-print-fw-info.patch
+f0e532539e93d19fc65b417b4a0663e3757823340b968f63bd3a2665f99524feebb843ecf88ccf6909f93a8e7e9290721677c8f43bc3a2a37d99a51c1281a469 0502-gcc9-kcflags.patch
+e48fdbae750c83aa64523e5f1e97f1969ec565946672ceff271ae12f099347556e421f6520ffab6d98363b11c46363de9707896197e792cf2b65a50bbb122503 1000-version.patch
+03a73db9eda84a52315499cb511f730946939d2de1b3aa52c60f9bd3a364377a65ddf2b62f505689a84d3e2f0fc7da5ca90429629d93d9909360ee0c3c599bbe no-require-gnu-tar.patch
+aadf8a3cc46a08e3a396ebd45656aee235103db7a2155cc6980df20b750151a9938b8b73c9319c6cd1b5f8aba6ce707f857a47dabf69df8d91dd93d440cffcb5 no-require-lilo.patch
7bb07eb22002cc48caf0cd55d17ce4097aa583e0ca4048c11c92e1519761b2ae982ffe98311543d4b0dfc991c8bc411b2e1c7be9488b6c6f19ffaa08e69e2f47 no-autoload-fb.conf"
diff --git a/system/easy-kernel/config-ppc64 b/system/easy-kernel/config-ppc64
index 019b86bb3..d57e298cf 100644
--- a/system/easy-kernel/config-ppc64
+++ b/system/easy-kernel/config-ppc64
@@ -1,19 +1,23 @@
#
# Automatically generated file; DO NOT EDIT.
-# Linux/powerpc 5.4.66-mc1 Kernel Configuration
-#
-
-#
-# Compiler: gcc (Adelie 8.3.0) 8.3.0
+# Linux/powerpc 5.15.11-mc1 Kernel Configuration
#
+CONFIG_CC_VERSION_TEXT="gcc (Adelie 8.3.0) 8.3.0"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=80300
CONFIG_CLANG_VERSION=0
+CONFIG_AS_IS_GNU=y
+CONFIG_AS_VERSION=23200
+CONFIG_LD_IS_BFD=y
+CONFIG_LD_VERSION=23200
+CONFIG_LLD_VERSION=0
CONFIG_CC_CAN_LINK=y
+CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO=y
CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
CONFIG_IRQ_WORK=y
-CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_BUILDTIME_TABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y
#
@@ -21,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
#
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
+# CONFIG_WERROR is not set
CONFIG_LOCALVERSION="-easy"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_BUILD_SALT=""
@@ -28,12 +33,14 @@ CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_XZ is not set
+CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="adelie"
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_WATCH_QUEUE is not set
CONFIG_CROSS_MEMORY_ATTACH=y
# CONFIG_USELIB is not set
# CONFIG_AUDIT is not set
@@ -48,7 +55,10 @@ CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_EDGE_EOI_HANDLER=y
CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_DOMAIN_NOMAP=y
CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
# CONFIG_GENERIC_IRQ_DEBUGFS is not set
@@ -72,9 +82,25 @@ CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
# end of Timers subsystem
+CONFIG_BPF=y
+CONFIG_HAVE_EBPF_JIT=y
+
+#
+# BPF subsystem
+#
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_JIT=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BPF_JIT_DEFAULT_ON=y
+# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
+# CONFIG_BPF_PRELOAD is not set
+# CONFIG_BPF_LSM is not set
+# end of BPF subsystem
+
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+CONFIG_SCHED_CORE=y
#
# CPU/Task time and stats accounting
@@ -102,6 +128,8 @@ CONFIG_TREE_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
+CONFIG_TASKS_RCU_GENERIC=y
+CONFIG_TASKS_TRACE_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
# end of RCU Subsystem
@@ -113,28 +141,29 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+# CONFIG_PRINTK_INDEX is not set
#
# Scheduler features
#
+# CONFIG_SCHED_ALT is not set
# CONFIG_UCLAMP_TASK is not set
# end of Scheduler features
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
-CONFIG_NUMA_BALANCING=y
-CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_CC_HAS_INT128=y
+# CONFIG_NUMA_BALANCING is not set
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
-CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_CFS_BANDWIDTH=y
-CONFIG_RT_GROUP_SCHED=y
+# CONFIG_CFS_BANDWIDTH is not set
+# CONFIG_RT_GROUP_SCHED is not set
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
@@ -145,16 +174,18 @@ CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_MISC=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
+CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
-CONFIG_SCHED_AUTOGROUP=y
+# CONFIG_SCHED_AUTOGROUP is not set
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
@@ -165,30 +196,29 @@ CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
+CONFIG_RD_ZSTD=y
+CONFIG_BOOT_CONFIG=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y
# CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is not set
+CONFIG_LD_ORPHAN_WARN=y
CONFIG_SYSCTL=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
-CONFIG_BPF=y
CONFIG_EXPERT=y
CONFIG_MULTIUSER=y
# CONFIG_SGETMASK_SYSCALL is not set
# CONFIG_SYSFS_SYSCALL is not set
-# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
CONFIG_PRINTK=y
-CONFIG_PRINTK_NMI=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_FUTEX_PI=y
-CONFIG_HAVE_FUTEX_CMPXCHG=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
@@ -201,10 +231,10 @@ CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_BASE_RELATIVE=y
-CONFIG_BPF_SYSCALL=y
-CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_USERFAULTFD=y
CONFIG_ARCH_HAS_MEMBARRIER_CALLBACKS=y
+CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
+CONFIG_KCMP=y
CONFIG_RSEQ=y
# CONFIG_DEBUG_RSEQ is not set
# CONFIG_EMBEDDED is not set
@@ -219,7 +249,6 @@ CONFIG_PERF_EVENTS=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_SLUB_DEBUG is not set
-# CONFIG_SLUB_MEMCG_SYSFS_ON is not set
# CONFIG_COMPAT_BRK is not set
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -249,10 +278,10 @@ CONFIG_GENERIC_CPU=y
# CONFIG_POWER8_CPU is not set
# CONFIG_POWER9_CPU is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_PPC_FPU_REGS=y
CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
CONFIG_VSX=y
-CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_PPC_RADIX_MMU=y
CONFIG_PPC_RADIX_MMU_DEFAULT=y
CONFIG_PPC_HAVE_KUEP=y
@@ -260,9 +289,10 @@ CONFIG_PPC_KUEP=y
CONFIG_PPC_HAVE_KUAP=y
CONFIG_PPC_KUAP=y
# CONFIG_PPC_KUAP_DEBUG is not set
-CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
+CONFIG_PPC_PKEY=y
CONFIG_PPC_MM_SLICES=y
CONFIG_PPC_HAVE_PMU_SUPPORT=y
+# CONFIG_PMU_SYSFS is not set
CONFIG_PPC_PERF_CTRS=y
CONFIG_FORCE_SMP=y
CONFIG_SMP=y
@@ -281,10 +311,10 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_NR_IRQS=512
CONFIG_NMI_IPI=y
CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_PPC=y
@@ -299,6 +329,7 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_EPAPR_BOOT=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -306,7 +337,6 @@ CONFIG_ARCH_SUSPEND_NONZERO_CPU=y
CONFIG_PPC_DCR_MMIO=y
CONFIG_PPC_DCR=y
CONFIG_PPC_OF_PLATFORM_PCI=y
-CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_PPC_DAWR=y
CONFIG_PGTABLE_LEVELS=4
@@ -327,6 +357,7 @@ CONFIG_OPAL_PRD=y
# CONFIG_PPC_MEMTRACE is not set
# CONFIG_SCOM_DEBUGFS is not set
CONFIG_PPC_PSERIES=y
+CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_PPC_SPLPAR=y
# CONFIG_DTL is not set
CONFIG_PSERIES_ENERGY=m
@@ -381,7 +412,6 @@ CONFIG_PPC_PMI=y
CONFIG_CBE_CPUFREQ_SPU_GOVERNOR=m
# end of Cell Broadband Engine options
-CONFIG_OPROFILE_CELL=y
CONFIG_KVM_GUEST=y
CONFIG_EPAPR_PARAVIRT=y
CONFIG_PPC_NATIVE=y
@@ -403,6 +433,7 @@ CONFIG_MPIC_U3_HT_IRQS=y
CONFIG_EEH=y
CONFIG_PPC_970_NAP=y
CONFIG_PPC_P7_NAP=y
+CONFIG_PPC_BOOK3S_IDLE=y
CONFIG_PPC_INDIRECT_PIO=y
CONFIG_PPC_INDIRECT_MMIO=y
CONFIG_PPC_IO_WORKAROUNDS=y
@@ -460,7 +491,6 @@ CONFIG_POWERNV_CPUIDLE=y
# end of CPUIdle driver
CONFIG_GEN_RTC=y
-# CONFIG_SIMPLE_GPIO is not set
# end of Platform support
#
@@ -472,13 +502,11 @@ CONFIG_HZ_100=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
CONFIG_SCHED_HRTICK=y
-CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y
CONFIG_PPC_TRANSACTIONAL_MEM=y
# CONFIG_LD_HEAD_STUB_CATCH is not set
CONFIG_HOTPLUG_CPU=y
+CONFIG_PPC_QUEUED_SPINLOCKS=y
CONFIG_ARCH_CPU_PROBE_RELEASE=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_PPC64_SUPPORTS_MEMORY_FAILURE is not set
CONFIG_KEXEC=y
CONFIG_KEXEC_FILE=y
@@ -497,21 +525,18 @@ CONFIG_HAVE_MEMORYLESS_NODES=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_ILLEGAL_POINTER_VALUE=0x5deadbeef0000000
CONFIG_ARCH_MEMORY_PROBE=y
-CONFIG_NODES_SPAN_OTHER_NODES=y
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_64K_PAGES is not set
CONFIG_PPC_PAGE_SHIFT=12
CONFIG_THREAD_SHIFT=14
-CONFIG_ETEXT_SHIFT=12
CONFIG_DATA_SHIFT=12
CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_PPC_PROT_SAO_LPAR is not set
CONFIG_PPC_COPRO_BASE=y
CONFIG_SCHED_SMT=y
CONFIG_PPC_DENORMALISATION=y
-# CONFIG_CMDLINE_BOOL is not set
CONFIG_CMDLINE=""
CONFIG_EXTRA_TARGETS=""
CONFIG_ARCH_WANTS_FREEZER_CONTROL=y
@@ -520,6 +545,7 @@ CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
+CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_PM_STD_PARTITION=""
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
@@ -533,8 +559,8 @@ CONFIG_PM_ADVANCED_DEBUG=y
CONFIG_PM_SLEEP_DEBUG=y
CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
CONFIG_ENERGY_MODEL=y
-CONFIG_SECCOMP=y
CONFIG_PPC_MEM_KEYS=y
+CONFIG_PPC_RTAS_FILTER=y
# end of Kernel options
CONFIG_ISA_DMA_API=y
@@ -571,9 +597,6 @@ CONFIG_KVM_BOOK3S_64_PR=m
# CONFIG_KVM_BOOK3S_HV_EXIT_TIMING is not set
CONFIG_KVM_XICS=y
CONFIG_KVM_XIVE=y
-CONFIG_VHOST_NET=m
-CONFIG_VHOST=m
-# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
#
# General architecture-dependent options
@@ -581,9 +604,6 @@ CONFIG_VHOST=m
CONFIG_CRASH_CORE=y
CONFIG_KEXEC_CORE=y
CONFIG_KEXEC_ELF=y
-CONFIG_HAVE_IMA_KEXEC=y
-CONFIG_OPROFILE=m
-CONFIG_HAVE_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_STATIC_KEYS_SELFTEST is not set
@@ -599,9 +619,11 @@ CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
+CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
@@ -612,44 +634,55 @@ CONFIG_HAVE_HARDLOCKUP_DETECTOR_ARCH=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_RCU_TABLE_FREE=y
-CONFIG_HAVE_MMU_GATHER_PAGE_SIZE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
+CONFIG_MMU_GATHER_TABLE_FREE=y
+CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
+CONFIG_MMU_GATHER_PAGE_SIZE=y
+CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_WEAK_RELEASE_ACQUIRE=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
+CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
+# CONFIG_SECCOMP_CACHE_DEBUG is not set
CONFIG_HAVE_STACKPROTECTOR=y
-CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y
+CONFIG_LTO_NONE=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING=y
CONFIG_ARCH_HAS_SCALED_CPUTIME=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOVE_PUD=y
+CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
CONFIG_HAVE_ARCH_SOFT_DIRTY=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_ARCH_MMAP_RND_BITS=18
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
-CONFIG_HAVE_COPY_THREAD_TLS=y
+CONFIG_HAVE_RELIABLE_STACKTRACE=y
CONFIG_HAVE_ARCH_NVRAM_OPS=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_OLD_SIGSUSPEND=y
CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_ARCH_HAS_PHYS_TO_DMA=y
-CONFIG_REFCOUNT_FULL=y
# CONFIG_LOCK_EVENT_COUNTS is not set
+CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
#
# GCOV-based kernel profiling
@@ -658,8 +691,11 @@ CONFIG_REFCOUNT_FULL=y
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling
-CONFIG_PLUGIN_HOSTCC=""
CONFIG_HAVE_GCC_PLUGINS=y
+CONFIG_GCC_PLUGINS=y
+# CONFIG_GCC_PLUGIN_CYC_COMPLEXITY is not set
+# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set
+# CONFIG_GCC_PLUGIN_RANDSTRUCT is not set
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@@ -682,29 +718,33 @@ CONFIG_MODULE_SIG_ALL=y
# CONFIG_MODULE_SIG_SHA384 is not set
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH="sha512"
-CONFIG_MODULE_COMPRESS=y
+# CONFIG_MODULE_COMPRESS_NONE is not set
# CONFIG_MODULE_COMPRESS_GZIP is not set
CONFIG_MODULE_COMPRESS_XZ=y
+# CONFIG_MODULE_COMPRESS_ZSTD is not set
# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
-# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_MODPROBE_PATH="/sbin/modprobe"
# CONFIG_TRIM_UNUSED_KSYMS is not set
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_BLOCK=y
CONFIG_BLK_RQ_ALLOC_TIME=y
-CONFIG_BLK_SCSI_REQUEST=y
-CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_CGROUP_RWSTAT=y
+CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BLK_DEV_INTEGRITY_T10=y
# CONFIG_BLK_DEV_ZONED is not set
CONFIG_BLK_DEV_THROTTLING=y
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
-# CONFIG_BLK_CMDLINE_PARSER is not set
CONFIG_BLK_WBT=y
+CONFIG_BLK_WBT_MQ=y
# CONFIG_BLK_CGROUP_IOLATENCY is not set
CONFIG_BLK_CGROUP_IOCOST=y
-CONFIG_BLK_WBT_MQ=y
+# CONFIG_BLK_CGROUP_IOPRIO is not set
CONFIG_BLK_DEBUG_FS=y
CONFIG_BLK_SED_OPAL=y
+CONFIG_BLK_INLINE_ENCRYPTION=y
+# CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK is not set
#
# Partition Types
@@ -736,6 +776,7 @@ CONFIG_BLOCK_COMPAT=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_BLK_PM=y
+CONFIG_BLOCK_HOLDER_DEPRECATED=y
#
# IO Schedulers
@@ -748,6 +789,7 @@ CONFIG_BFQ_CGROUP_DEBUG=y
# end of IO Schedulers
CONFIG_PREEMPT_NOTIFIERS=y
+CONFIG_PADATA=y
CONFIG_ASN1=y
CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_INLINE_READ_UNLOCK=y
@@ -758,8 +800,13 @@ CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_RWLOCKS=y
CONFIG_ARCH_HAS_MMIOWB=y
CONFIG_MMIOWB=y
+CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
CONFIG_FREEZER=y
#
@@ -780,26 +827,30 @@ CONFIG_COREDUMP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_HAVE_MEMORY_PRESENT=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
-CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_FAST_GUP=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_NUMA_KEEP_MEMINFO=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_SPARSE=y
# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_COMPACTION=y
+CONFIG_PAGE_REPORTING=y
CONFIG_MIGRATION=y
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
+CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y
CONFIG_CONTIG_ALLOC=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_MMU_NOTIFIER=y
@@ -810,31 +861,49 @@ CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
CONFIG_TRANSPARENT_HUGEPAGE=y
# CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS is not set
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
-CONFIG_TRANSPARENT_HUGE_PAGECACHE=y
# CONFIG_CLEANCACHE is not set
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
# CONFIG_CMA_DEBUG is not set
CONFIG_CMA_DEBUGFS=y
+# CONFIG_CMA_SYSFS is not set
CONFIG_CMA_AREAS=7
CONFIG_ZSWAP=y
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT="lzo"
+CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y
+# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD is not set
+# CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set
+CONFIG_ZSWAP_ZPOOL_DEFAULT="zbud"
+# CONFIG_ZSWAP_DEFAULT_ON is not set
CONFIG_ZPOOL=y
CONFIG_ZBUD=y
CONFIG_Z3FOLD=m
# CONFIG_ZSMALLOC is not set
+CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
# CONFIG_IDLE_PAGE_TRACKING is not set
CONFIG_ARCH_HAS_PTE_DEVMAP=y
# CONFIG_ZONE_DEVICE is not set
CONFIG_HMM_MIRROR=y
-CONFIG_FRAME_VECTOR=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
# CONFIG_PERCPU_STATS is not set
-# CONFIG_GUP_BENCHMARK is not set
+# CONFIG_GUP_TEST is not set
# CONFIG_READ_ONLY_THP_FOR_FS is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
CONFIG_ARCH_HAS_HUGEPD=y
+
+#
+# Data Access Monitoring
+#
+# CONFIG_DAMON is not set
+# end of Data Access Monitoring
# end of Memory Management options
CONFIG_NET=y
@@ -850,6 +919,7 @@ CONFIG_PACKET=y
CONFIG_PACKET_DIAG=m
CONFIG_UNIX=y
CONFIG_UNIX_SCM=y
+CONFIG_AF_UNIX_OOB=y
CONFIG_UNIX_DIAG=m
# CONFIG_TLS is not set
CONFIG_XFRM=y
@@ -860,6 +930,8 @@ CONFIG_XFRM_USER=m
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_AH=m
+CONFIG_XFRM_ESP=m
CONFIG_XFRM_IPCOMP=m
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
@@ -875,7 +947,7 @@ CONFIG_IP_ROUTE_CLASSID=y
# CONFIG_IP_PNP is not set
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE_DEMUX=m
-CONFIG_NET_IP_TUNNEL=m
+CONFIG_NET_IP_TUNNEL=y
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE_COMMON=y
@@ -885,12 +957,13 @@ CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
-CONFIG_NET_UDP_TUNNEL=m
+CONFIG_NET_UDP_TUNNEL=y
CONFIG_NET_FOU=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_ESP_OFFLOAD=m
+# CONFIG_INET_ESPINTCP is not set
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
@@ -927,6 +1000,7 @@ CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_ESP_OFFLOAD=m
+# CONFIG_INET6_ESPINTCP is not set
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_MIP6=m
# CONFIG_IPV6_ILA is not set
@@ -947,7 +1021,10 @@ CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
+# CONFIG_IPV6_RPL_LWTUNNEL is not set
+# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
# CONFIG_NETLABEL is not set
+# CONFIG_MPTCP is not set
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NET_PTP_CLASSIFY=y
# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
@@ -962,13 +1039,13 @@ CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_FAMILY_BRIDGE=y
CONFIG_NETFILTER_FAMILY_ARP=y
+# CONFIG_NETFILTER_NETLINK_HOOK is not set
CONFIG_NETFILTER_NETLINK_ACCT=m
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_NETLINK_OSF=m
CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_COMMON=m
-CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_LOG_SYSLOG=m
CONFIG_NETFILTER_CONNCOUNT=m
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_ZONES=y
@@ -1006,7 +1083,6 @@ CONFIG_NF_NAT_REDIRECT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NETFILTER_SYNPROXY=m
CONFIG_NF_TABLES=m
-CONFIG_NF_TABLES_SET=m
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=m
@@ -1038,9 +1114,11 @@ CONFIG_NF_DUP_NETDEV=m
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
# CONFIG_NFT_FIB_NETDEV is not set
+# CONFIG_NFT_REJECT_NETDEV is not set
CONFIG_NF_FLOW_TABLE_INET=m
CONFIG_NF_FLOW_TABLE=m
CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XTABLES_COMPAT=y
#
# Xtables combined modules
@@ -1229,7 +1307,6 @@ CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
-CONFIG_NF_LOG_BRIDGE=m
CONFIG_NF_CONNTRACK_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
@@ -1276,7 +1353,8 @@ CONFIG_MRP=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_BRIDGE_VLAN_FILTERING=y
-CONFIG_HAVE_NET_DSA=y
+# CONFIG_BRIDGE_MRP is not set
+# CONFIG_BRIDGE_CFM is not set
# CONFIG_NET_DSA is not set
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
@@ -1322,8 +1400,10 @@ CONFIG_NET_SCH_CAKE=m
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_HHF=m
CONFIG_NET_SCH_PIE=m
+# CONFIG_NET_SCH_FQ_PIE is not set
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_SCH_PLUG=m
+# CONFIG_NET_SCH_ETS is not set
CONFIG_NET_SCH_DEFAULT=y
# CONFIG_DEFAULT_FQ is not set
# CONFIG_DEFAULT_CODEL is not set
@@ -1372,6 +1452,7 @@ CONFIG_NET_ACT_SKBMOD=m
# CONFIG_NET_ACT_IFE is not set
CONFIG_NET_ACT_TUNNEL_KEY=m
CONFIG_NET_ACT_CT=m
+# CONFIG_NET_ACT_GATE is not set
# CONFIG_NET_TC_SKB_EXT is not set
CONFIG_NET_SCH_FIFO=y
# CONFIG_DCB is not set
@@ -1390,15 +1471,19 @@ CONFIG_NET_NSH=m
# CONFIG_HSR is not set
# CONFIG_NET_SWITCHDEV is not set
CONFIG_NET_L3_MASTER_DEV=y
+CONFIG_QRTR=m
+# CONFIG_QRTR_TUN is not set
+CONFIG_QRTR_MHI=m
# CONFIG_NET_NCSI is not set
+CONFIG_PCPU_DEV_REFCNT=y
CONFIG_RPS=y
CONFIG_RFS_ACCEL=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_XPS=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_NET_RX_BUSY_POLL=y
CONFIG_BQL=y
-CONFIG_BPF_JIT=y
# CONFIG_BPF_STREAM_PARSER is not set
CONFIG_NET_FLOW_LIMIT=y
@@ -1423,8 +1508,11 @@ CONFIG_BT_HIDP=m
CONFIG_BT_HS=y
CONFIG_BT_LE=y
CONFIG_BT_LEDS=y
-# CONFIG_BT_SELFTEST is not set
+CONFIG_BT_MSFTEXT=y
+CONFIG_BT_AOSPEXT=y
# CONFIG_BT_DEBUGFS is not set
+# CONFIG_BT_SELFTEST is not set
+# CONFIG_BT_FEATURE_DEBUG is not set
#
# Bluetooth device drivers
@@ -1451,10 +1539,12 @@ CONFIG_BT_MRVL=m
# CONFIG_BT_MRVL_SDIO is not set
CONFIG_BT_ATH3K=m
# CONFIG_BT_MTKSDIO is not set
+# CONFIG_BT_VIRTIO is not set
# end of Bluetooth device drivers
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
+# CONFIG_MCTP is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_WIRELESS_EXT=y
@@ -1489,7 +1579,6 @@ CONFIG_MAC80211_LEDS=y
# CONFIG_MAC80211_MESSAGE_TRACING is not set
# CONFIG_MAC80211_DEBUG_MENU is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
-# CONFIG_WIMAX is not set
CONFIG_RFKILL=m
CONFIG_RFKILL_LEDS=y
CONFIG_RFKILL_INPUT=y
@@ -1505,8 +1594,10 @@ CONFIG_LWTUNNEL=y
# CONFIG_LWTUNNEL_BPF is not set
CONFIG_DST_CACHE=y
CONFIG_GRO_CELLS=y
+CONFIG_NET_SELFTESTS=m
+CONFIG_NET_SOCK_MSG=y
CONFIG_FAILOVER=m
-CONFIG_HAVE_EBPF_JIT=y
+CONFIG_ETHTOOL_NETLINK=y
#
# Device Drivers
@@ -1522,7 +1613,6 @@ CONFIG_PCIEAER=y
# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIE_ECRC is not set
CONFIG_PCIEASPM=y
-CONFIG_PCIEASPM_DEBUG=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
@@ -1530,8 +1620,9 @@ CONFIG_PCIEASPM_DEFAULT=y
CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set
-# CONFIG_PCIE_BW is not set
CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PCI_MSI_ARCH_FALLBACKS=y
CONFIG_PCI_QUIRKS=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
@@ -1541,6 +1632,11 @@ CONFIG_PCI_ATS=y
CONFIG_PCI_IOV=y
# CONFIG_PCI_PRI is not set
# CONFIG_PCI_PASID is not set
+# CONFIG_PCIE_BUS_TUNE_OFF is not set
+CONFIG_PCIE_BUS_DEFAULT=y
+# CONFIG_PCIE_BUS_SAFE is not set
+# CONFIG_PCIE_BUS_PERFORMANCE is not set
+# CONFIG_PCIE_BUS_PEER2PEER is not set
CONFIG_HOTPLUG_PCI=y
# CONFIG_HOTPLUG_PCI_CPCI is not set
CONFIG_HOTPLUG_PCI_SHPC=y
@@ -1551,21 +1647,29 @@ CONFIG_HOTPLUG_PCI_RPA=m
#
# PCI controller drivers
#
-
-#
-# Cadence PCIe controllers support
-#
-# CONFIG_PCIE_CADENCE_HOST is not set
-# end of Cadence PCIe controllers support
-
# CONFIG_PCI_FTPCI100 is not set
# CONFIG_PCI_HOST_GENERIC is not set
# CONFIG_PCIE_XILINX is not set
+# CONFIG_PCIE_MICROCHIP_HOST is not set
#
# DesignWare PCI Core Support
#
+# CONFIG_PCIE_DW_PLAT_HOST is not set
+# CONFIG_PCI_MESON is not set
# end of DesignWare PCI Core Support
+
+#
+# Mobiveil PCIe Core Support
+#
+# end of Mobiveil PCIe Core Support
+
+#
+# Cadence PCIe controllers support
+#
+# CONFIG_PCIE_CADENCE_PLAT_HOST is not set
+# CONFIG_PCI_J721E_HOST is not set
+# end of Cadence PCIe controllers support
# end of PCI controller drivers
#
@@ -1580,6 +1684,7 @@ CONFIG_HOTPLUG_PCI_RPA=m
# CONFIG_PCI_SW_SWITCHTEC is not set
# end of PCI switch controller drivers
+# CONFIG_CXL_BUS is not set
# CONFIG_PCCARD is not set
# CONFIG_RAPIDIO is not set
@@ -1600,6 +1705,7 @@ CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_EXTRA_FIRMWARE=""
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_FW_CACHE=y
# end of Firmware loader
CONFIG_WANT_DEV_COREDUMP=y
@@ -1619,10 +1725,32 @@ CONFIG_DMA_SHARED_BUFFER=y
#
# Bus devices
#
-# CONFIG_SIMPLE_PM_BUS is not set
+CONFIG_MHI_BUS=m
+# CONFIG_MHI_BUS_DEBUG is not set
+# CONFIG_MHI_BUS_PCI_GENERIC is not set
# end of Bus devices
CONFIG_CONNECTOR=m
+
+#
+# Firmware Drivers
+#
+
+#
+# ARM System Control and Management Interface Protocol
+#
+# end of ARM System Control and Management Interface Protocol
+
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_FW_CFG_SYSFS is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# Tegra firmware driver
+#
+# end of Tegra firmware driver
+# end of Firmware Drivers
+
# CONFIG_GNSS is not set
CONFIG_MTD=m
# CONFIG_MTD_TESTS is not set
@@ -1642,6 +1770,10 @@ CONFIG_MTD_OF_PARTS=m
CONFIG_MTD_BLKDEVS=m
CONFIG_MTD_BLOCK=m
# CONFIG_MTD_BLOCK_RO is not set
+
+#
+# Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK.
+#
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
@@ -1699,10 +1831,21 @@ CONFIG_MTD_BLOCK2MTD=m
# CONFIG_MTD_DOCG3 is not set
# end of Self-contained MTD device drivers
+#
+# NAND
+#
# CONFIG_MTD_ONENAND is not set
# CONFIG_MTD_RAW_NAND is not set
#
+# ECC engine support
+#
+# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set
+# CONFIG_MTD_NAND_ECC_SW_BCH is not set
+# end of ECC engine support
+# end of NAND
+
+#
# LPDDR & LPDDR2 PCM memory drivers
#
# CONFIG_MTD_LPDDR is not set
@@ -1725,7 +1868,6 @@ CONFIG_OF_DYNAMIC=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_IRQ=y
CONFIG_OF_NET=y
-CONFIG_OF_MDIO=m
CONFIG_OF_RESERVED_MEM=y
# CONFIG_OF_OVERLAY is not set
CONFIG_OF_DMA_DEFAULT_COHERENT=y
@@ -1736,13 +1878,11 @@ CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
CONFIG_CDROM=y
# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
-# CONFIG_BLK_DEV_UMEM is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_DRBD is not set
CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SKD is not set
# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
@@ -1750,7 +1890,6 @@ CONFIG_BLK_DEV_RAM_SIZE=65536
# CONFIG_CDROM_PKTCDVD is not set
CONFIG_ATA_OVER_ETH=m
CONFIG_VIRTIO_BLK=y
-# CONFIG_VIRTIO_BLK_SCSI is not set
# CONFIG_BLK_DEV_RBD is not set
# CONFIG_BLK_DEV_RSXX is not set
@@ -1760,6 +1899,7 @@ CONFIG_VIRTIO_BLK=y
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
# CONFIG_NVME_MULTIPATH is not set
+# CONFIG_NVME_HWMON is not set
# CONFIG_NVME_FC is not set
# CONFIG_NVME_TCP is not set
# CONFIG_NVME_TARGET is not set
@@ -1786,9 +1926,9 @@ CONFIG_TIFM_7XX1=m
# CONFIG_HMC6352 is not set
# CONFIG_DS1682 is not set
# CONFIG_SRAM is not set
+# CONFIG_DW_XDATA_PCIE is not set
# CONFIG_PCI_ENDPOINT_TEST is not set
# CONFIG_XILINX_SDFEC is not set
-# CONFIG_PVPANIC is not set
# CONFIG_C2PORT is not set
#
@@ -1811,67 +1951,27 @@ CONFIG_EEPROM_EE1004=m
# CONFIG_SENSORS_LIS3_I2C is not set
# CONFIG_ALTERA_STAPL is not set
-
-#
-# Intel MIC & related support
-#
-
-#
-# Intel MIC Bus Driver
-#
-
-#
-# SCIF Bus Driver
-#
-
-#
-# VOP Bus Driver
-#
-# CONFIG_VOP_BUS is not set
-
-#
-# Intel MIC Host Driver
-#
-
-#
-# Intel MIC Card Driver
-#
-
-#
-# SCIF Driver
-#
-
-#
-# Intel MIC Coprocessor State Management (COSM) Drivers
-#
-
-#
-# VOP Driver
-#
-# end of Intel MIC & related support
-
# CONFIG_GENWQE is not set
# CONFIG_ECHO is not set
CONFIG_CXL_BASE=y
-CONFIG_CXL_AFU_DRIVER_OPS=y
-CONFIG_CXL_LIB=y
CONFIG_CXL=m
CONFIG_OCXL_BASE=y
CONFIG_OCXL=m
+# CONFIG_BCM_VK is not set
# CONFIG_MISC_ALCOR_PCI is not set
# CONFIG_MISC_RTSX_PCI is not set
# CONFIG_MISC_RTSX_USB is not set
# CONFIG_HABANA_AI is not set
+# CONFIG_UACCE is not set
+# CONFIG_PVPANIC is not set
# end of Misc devices
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
-
#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=y
+CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_PROC_FS=y
@@ -1883,6 +1983,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=y
CONFIG_CHR_DEV_SG=y
+CONFIG_BLK_DEV_BSG=y
CONFIG_CHR_DEV_SCH=m
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
@@ -1943,18 +2044,20 @@ CONFIG_SCSI_MPT3SAS=m
CONFIG_SCSI_MPT2SAS_MAX_SGE=128
CONFIG_SCSI_MPT3SAS_MAX_SGE=128
CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_MPI3MR=m
CONFIG_SCSI_SMARTPQI=y
CONFIG_SCSI_UFSHCD=m
# CONFIG_SCSI_UFSHCD_PCI is not set
# CONFIG_SCSI_UFSHCD_PLATFORM is not set
# CONFIG_SCSI_UFS_BSG is not set
+# CONFIG_SCSI_UFS_CRYPTO is not set
+# CONFIG_SCSI_UFS_HPB is not set
CONFIG_SCSI_HPTIOP=m
# CONFIG_SCSI_MYRB is not set
CONFIG_SCSI_SNIC=m
# CONFIG_SCSI_SNIC_DEBUG_FS is not set
CONFIG_SCSI_DMX3191D=m
# CONFIG_SCSI_FDOMAIN_PCI is not set
-CONFIG_SCSI_GDTH=m
CONFIG_SCSI_IPS=y
CONFIG_SCSI_IBMVSCSI=y
CONFIG_SCSI_INITIO=m
@@ -1982,7 +2085,9 @@ CONFIG_SCSI_VIRTIO=y
CONFIG_ATA=y
CONFIG_ATA_NONSTANDARD=y
+CONFIG_SATA_HOST=y
CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATA_FORCE=y
CONFIG_SATA_PMP=y
#
@@ -2085,6 +2190,7 @@ CONFIG_MD_RAID456=m
CONFIG_BCACHE=m
# CONFIG_BCACHE_DEBUG is not set
# CONFIG_BCACHE_CLOSURES_DEBUG is not set
+# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=m
# CONFIG_DM_DEBUG is not set
@@ -2099,6 +2205,7 @@ CONFIG_DM_THIN_PROVISIONING=m
CONFIG_DM_CACHE=m
CONFIG_DM_CACHE_SMQ=m
CONFIG_DM_WRITECACHE=m
+# CONFIG_DM_EBS is not set
CONFIG_DM_ERA=m
CONFIG_DM_CLONE=m
CONFIG_DM_MIRROR=m
@@ -2145,6 +2252,8 @@ CONFIG_MII=m
CONFIG_NET_CORE=y
CONFIG_BONDING=m
CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+# CONFIG_WIREGUARD_DEBUG is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_FC is not set
# CONFIG_IFB is not set
@@ -2161,6 +2270,7 @@ CONFIG_IPVLAN=m
CONFIG_IPVTAP=m
CONFIG_VXLAN=m
# CONFIG_GENEVE is not set
+# CONFIG_BAREUDP is not set
# CONFIG_GTP is not set
CONFIG_MACSEC=m
CONFIG_NETCONSOLE=m
@@ -2174,18 +2284,9 @@ CONFIG_VETH=m
CONFIG_VIRTIO_NET=m
# CONFIG_NLMON is not set
# CONFIG_NET_VRF is not set
+# CONFIG_MHI_NET is not set
CONFIG_SUNGEM_PHY=m
# CONFIG_ARCNET is not set
-
-#
-# CAIF transport drivers
-#
-
-#
-# Distributed Switch Architecture drivers
-#
-# end of Distributed Switch Architecture drivers
-
CONFIG_ETHERNET=y
CONFIG_NET_VENDOR_3COM=y
# CONFIG_VORTEX is not set
@@ -2205,6 +2306,7 @@ CONFIG_NET_VENDOR_AMD=y
# CONFIG_AMD8111_ETH is not set
# CONFIG_PCNET32 is not set
CONFIG_NET_VENDOR_AQUANTIA=y
+# CONFIG_AQTION is not set
CONFIG_NET_VENDOR_ARC=y
CONFIG_NET_VENDOR_ATHEROS=y
# CONFIG_ATL2 is not set
@@ -2212,7 +2314,6 @@ CONFIG_NET_VENDOR_ATHEROS=y
# CONFIG_ATL1E is not set
# CONFIG_ATL1C is not set
# CONFIG_ALX is not set
-# CONFIG_NET_VENDOR_AURORA is not set
CONFIG_NET_VENDOR_BROADCOM=y
# CONFIG_B44 is not set
# CONFIG_BCMGENET is not set
@@ -2263,9 +2364,6 @@ CONFIG_NET_VENDOR_EMULEX=y
CONFIG_NET_VENDOR_EZCHIP=y
# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set
CONFIG_NET_VENDOR_GOOGLE=y
-# CONFIG_GVE is not set
-CONFIG_NET_VENDOR_HP=y
-# CONFIG_HP100 is not set
CONFIG_NET_VENDOR_HUAWEI=y
CONFIG_NET_VENDOR_I825XX=y
CONFIG_NET_VENDOR_IBM=y
@@ -2288,7 +2386,10 @@ CONFIG_IXGB=m
# CONFIG_ICE is not set
# CONFIG_FM10K is not set
# CONFIG_IGC is not set
+CONFIG_NET_VENDOR_MICROSOFT=y
# CONFIG_JME is not set
+CONFIG_NET_VENDOR_LITEX=y
+CONFIG_LITEX_LITEETH=m
CONFIG_NET_VENDOR_MARVELL=y
# CONFIG_MVMDIO is not set
# CONFIG_SKGE is not set
@@ -2384,53 +2485,50 @@ CONFIG_NET_VENDOR_WIZNET=y
# CONFIG_WIZNET_W5100 is not set
# CONFIG_WIZNET_W5300 is not set
CONFIG_NET_VENDOR_XILINX=y
+CONFIG_XILINX_EMACLITE=m
+CONFIG_XILINX_AXI_EMAC=m
# CONFIG_XILINX_LL_TEMAC is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-CONFIG_MDIO_DEVICE=m
-CONFIG_MDIO_BUS=m
-# CONFIG_MDIO_BCM_UNIMAC is not set
-# CONFIG_MDIO_BITBANG is not set
-# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
-# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
-# CONFIG_MDIO_HISI_FEMAC is not set
-# CONFIG_MDIO_MSCC_MIIM is not set
-# CONFIG_MDIO_OCTEON is not set
-# CONFIG_MDIO_THUNDER is not set
+CONFIG_PHYLINK=m
CONFIG_PHYLIB=m
CONFIG_SWPHY=y
# CONFIG_LED_TRIGGER_PHY is not set
+CONFIG_FIXED_PHY=m
+# CONFIG_SFP is not set
#
# MII PHY device drivers
#
-# CONFIG_ADIN_PHY is not set
# CONFIG_AMD_PHY is not set
+# CONFIG_ADIN_PHY is not set
# CONFIG_AQUANTIA_PHY is not set
# CONFIG_AX88796B_PHY is not set
-# CONFIG_AT803X_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BCM54140_PHY=m
# CONFIG_BCM7XXX_PHY is not set
+CONFIG_BCM84881_PHY=m
# CONFIG_BCM87XX_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
+CONFIG_BCM_NET_PHYLIB=m
# CONFIG_CICADA_PHY is not set
# CONFIG_CORTINA_PHY is not set
# CONFIG_DAVICOM_PHY is not set
-# CONFIG_DP83822_PHY is not set
-# CONFIG_DP83TC811_PHY is not set
-# CONFIG_DP83848_PHY is not set
-# CONFIG_DP83867_PHY is not set
-CONFIG_FIXED_PHY=m
# CONFIG_ICPLUS_PHY is not set
+# CONFIG_LXT_PHY is not set
# CONFIG_INTEL_XWAY_PHY is not set
# CONFIG_LSI_ET1011C_PHY is not set
-# CONFIG_LXT_PHY is not set
# CONFIG_MARVELL_PHY is not set
# CONFIG_MARVELL_10G_PHY is not set
+CONFIG_MARVELL_88X2222_PHY=m
+CONFIG_MAXLINEAR_GPHY=m
+CONFIG_MEDIATEK_GE_PHY=m
# CONFIG_MICREL_PHY is not set
# CONFIG_MICROCHIP_PHY is not set
# CONFIG_MICROCHIP_T1_PHY is not set
# CONFIG_MICROSEMI_PHY is not set
+CONFIG_MOTORCOMM_PHY=m
# CONFIG_NATIONAL_PHY is not set
+CONFIG_NXP_C45_TJA11XX_PHY=m
# CONFIG_NXP_TJA11XX_PHY is not set
# CONFIG_QSEMI_PHY is not set
# CONFIG_REALTEK_PHY is not set
@@ -2439,8 +2537,38 @@ CONFIG_FIXED_PHY=m
# CONFIG_SMSC_PHY is not set
# CONFIG_STE10XP is not set
# CONFIG_TERANETICS_PHY is not set
+# CONFIG_DP83822_PHY is not set
+# CONFIG_DP83TC811_PHY is not set
+# CONFIG_DP83848_PHY is not set
+# CONFIG_DP83867_PHY is not set
+CONFIG_DP83869_PHY=m
# CONFIG_VITESSE_PHY is not set
# CONFIG_XILINX_GMII2RGMII is not set
+CONFIG_MDIO_DEVICE=m
+CONFIG_MDIO_BUS=m
+CONFIG_FWNODE_MDIO=m
+CONFIG_OF_MDIO=m
+CONFIG_MDIO_DEVRES=m
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_HISI_FEMAC is not set
+CONFIG_MDIO_MVUSB=m
+# CONFIG_MDIO_MSCC_MIIM is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MDIO_THUNDER is not set
+
+#
+# MDIO Multiplexers
+#
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+
+#
+# PCS device drivers
+#
+# CONFIG_PCS_XPCS is not set
+# end of PCS device drivers
+
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_DEFLATE=m
@@ -2491,8 +2619,8 @@ CONFIG_USB_NET_RNDIS_HOST=m
# CONFIG_USB_VL600 is not set
# CONFIG_USB_NET_CH9200 is not set
# CONFIG_USB_NET_AQC111 is not set
+CONFIG_USB_RTL8153_ECM=m
CONFIG_WLAN=y
-# CONFIG_WIRELESS_WDS is not set
CONFIG_WLAN_VENDOR_ADMTEK=y
CONFIG_ADM8211=m
CONFIG_ATH_COMMON=m
@@ -2542,6 +2670,10 @@ CONFIG_ATH10K_USB=m
# CONFIG_ATH10K_TRACING is not set
CONFIG_WCN36XX=m
# CONFIG_WCN36XX_DEBUGFS is not set
+CONFIG_ATH11K=m
+CONFIG_ATH11K_PCI=m
+# CONFIG_ATH11K_DEBUG is not set
+# CONFIG_ATH11K_TRACING is not set
CONFIG_WLAN_VENDOR_ATMEL=y
CONFIG_ATMEL=m
CONFIG_PCI_ATMEL=m
@@ -2642,7 +2774,6 @@ CONFIG_P54_COMMON=m
CONFIG_P54_USB=m
CONFIG_P54_PCI=m
CONFIG_P54_LEDS=y
-CONFIG_PRISM54=m
CONFIG_WLAN_VENDOR_MARVELL=y
CONFIG_LIBERTAS=m
CONFIG_LIBERTAS_USB=m
@@ -2659,12 +2790,27 @@ CONFIG_MWIFIEX_USB=m
CONFIG_MWL8K=m
CONFIG_WLAN_VENDOR_MEDIATEK=y
CONFIG_MT7601U=m
+CONFIG_MT76_CORE=m
+CONFIG_MT76_LEDS=y
+CONFIG_MT76_USB=m
+CONFIG_MT76_SDIO=m
+CONFIG_MT76_CONNAC_LIB=m
# CONFIG_MT76x0U is not set
# CONFIG_MT76x0E is not set
# CONFIG_MT76x2E is not set
# CONFIG_MT76x2U is not set
# CONFIG_MT7603E is not set
+CONFIG_MT7615_COMMON=m
# CONFIG_MT7615E is not set
+CONFIG_MT7663_USB_SDIO_COMMON=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+CONFIG_MT7921E=m
+CONFIG_WLAN_VENDOR_MICROCHIP=y
+CONFIG_WILC1000=m
+CONFIG_WILC1000_SDIO=m
+# CONFIG_WILC1000_HW_OOB_INTR is not set
CONFIG_WLAN_VENDOR_RALINK=y
CONFIG_RT2X00=m
CONFIG_RT2400PCI=m
@@ -2740,16 +2886,18 @@ CONFIG_WLAN_VENDOR_QUANTENNA=y
# CONFIG_MAC80211_HWSIM is not set
CONFIG_USB_NET_RNDIS_WLAN=m
# CONFIG_VIRT_WIFI is not set
+# CONFIG_WAN is not set
#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
+# Wireless WAN
#
-# CONFIG_WAN is not set
+# CONFIG_WWAN is not set
+# end of Wireless WAN
+
CONFIG_VMXNET3=m
# CONFIG_NETDEVSIM is not set
CONFIG_NET_FAILOVER=m
# CONFIG_ISDN is not set
-# CONFIG_NVM is not set
#
# Input device support
@@ -2757,7 +2905,6 @@ CONFIG_NET_FAILOVER=m
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=y
CONFIG_INPUT_FF_MEMLESS=y
-# CONFIG_INPUT_POLLDEV is not set
# CONFIG_INPUT_SPARSEKMAP is not set
# CONFIG_INPUT_MATRIXKMAP is not set
@@ -2817,7 +2964,6 @@ CONFIG_INPUT_MISC=y
# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
# CONFIG_INPUT_BMA150 is not set
# CONFIG_INPUT_E3X0_BUTTON is not set
-# CONFIG_INPUT_MSM_VIBRATOR is not set
# CONFIG_INPUT_MMA8450 is not set
CONFIG_INPUT_ATI_REMOTE2=m
# CONFIG_INPUT_KEYSPAN_REMOTE is not set
@@ -2827,8 +2973,11 @@ CONFIG_INPUT_ATI_REMOTE2=m
# CONFIG_INPUT_CM109 is not set
CONFIG_INPUT_UINPUT=y
# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_DA7280_HAPTICS is not set
# CONFIG_INPUT_ADXL34X is not set
# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_IQS269A is not set
+# CONFIG_INPUT_IQS626A is not set
# CONFIG_INPUT_CMA3000 is not set
# CONFIG_INPUT_DRV2665_HAPTICS is not set
# CONFIG_INPUT_DRV2667_HAPTICS is not set
@@ -2867,15 +3016,7 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-# CONFIG_TRACE_SINK is not set
-# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
-# CONFIG_NULL_TTY is not set
CONFIG_LDISC_AUTOLOAD=y
-CONFIG_DEVMEM=y
-# CONFIG_DEVKMEM is not set
#
# Serial drivers
@@ -2883,6 +3024,7 @@ CONFIG_DEVMEM=y
CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_16550A_VARIANTS=y
# CONFIG_SERIAL_8250_FINTEK is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_PCI=y
@@ -2890,7 +3032,6 @@ CONFIG_SERIAL_8250_EXAR=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_ASPEED_VUART is not set
CONFIG_SERIAL_8250_FSL=y
# CONFIG_SERIAL_8250_DW is not set
# CONFIG_SERIAL_8250_RT288X is not set
@@ -2918,8 +3059,11 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
# end of Serial drivers
-# CONFIG_SERIAL_DEV_BUS is not set
-# CONFIG_TTY_PRINTK is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NULL_TTY is not set
CONFIG_HVC_DRIVER=y
CONFIG_HVC_IRQ=y
CONFIG_HVC_CONSOLE=y
@@ -2928,6 +3072,8 @@ CONFIG_HVC_OPAL=y
CONFIG_HVC_RTAS=y
# CONFIG_HVC_UDBG is not set
CONFIG_HVCS=m
+# CONFIG_SERIAL_DEV_BUS is not set
+# CONFIG_TTY_PRINTK is not set
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_IBM_BSR is not set
CONFIG_POWERNV_OP_PANEL=m
@@ -2942,21 +3088,73 @@ CONFIG_IPMI_POWERNV=m
CONFIG_HW_RANDOM=m
CONFIG_HW_RANDOM_TIMERIOMEM=m
CONFIG_HW_RANDOM_AMD=m
+# CONFIG_HW_RANDOM_BA431 is not set
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_HW_RANDOM_PSERIES=m
CONFIG_HW_RANDOM_POWERNV=m
-CONFIG_NVRAM=y
+# CONFIG_HW_RANDOM_CCTRNG is not set
+# CONFIG_HW_RANDOM_XIPHERA is not set
# CONFIG_APPLICOM is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=256
+CONFIG_DEVMEM=y
+CONFIG_NVRAM=y
+CONFIG_DEVPORT=y
# CONFIG_HANGCHECK_TIMER is not set
# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
# CONFIG_XILLYBUS is not set
-# end of Character devices
-
+# CONFIG_XILLYUSB is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
+CONFIG_LRNG=y
+
+#
+# Specific DRNG seeding strategies
+#
+# CONFIG_LRNG_OVERSAMPLE_ENTROPY_SOURCES is not set
+CONFIG_LRNG_OVERSAMPLE_ES_BITS=0
+CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS=0
+# end of Specific DRNG seeding strategies
+
+#
+# Entropy Source Configuration
+#
+
+#
+# Interrupt Entropy Source
+#
+CONFIG_LRNG_IRQ=y
+CONFIG_LRNG_CONTINUOUS_COMPRESSION_ENABLED=y
+# CONFIG_LRNG_CONTINUOUS_COMPRESSION_DISABLED is not set
+CONFIG_LRNG_ENABLE_CONTINUOUS_COMPRESSION=y
+CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION=y
+# CONFIG_LRNG_COLLECTION_SIZE_256 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_512 is not set
+CONFIG_LRNG_COLLECTION_SIZE_1024=y
+# CONFIG_LRNG_COLLECTION_SIZE_2048 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_4096 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_8192 is not set
+CONFIG_LRNG_COLLECTION_SIZE=1024
+# CONFIG_LRNG_HEALTH_TESTS is not set
+CONFIG_LRNG_RCT_CUTOFF=31
+CONFIG_LRNG_APT_CUTOFF=325
+CONFIG_LRNG_IRQ_ENTROPY_RATE=256
+
+#
+# Jitter RNG Entropy Source
+#
+# CONFIG_LRNG_JENT is not set
+
+#
+# CPU Entropy Source
+#
+CONFIG_LRNG_CPU=y
+CONFIG_LRNG_CPU_FULL_ENT_MULTIPLIER=1
+CONFIG_LRNG_CPU_ENTROPY_RATE=8
+# end of Entropy Source Configuration
+
+# CONFIG_LRNG_DRNG_SWITCH is not set
+# CONFIG_LRNG_TESTING_MENU is not set
+# CONFIG_LRNG_SELFTEST is not set
+# end of Character devices
#
# I2C support
@@ -3023,7 +3221,7 @@ CONFIG_I2C_POWERMAC=y
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_DIOLAN_U2C is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_CP2615 is not set
# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_TINY_USB is not set
@@ -3032,6 +3230,7 @@ CONFIG_I2C_POWERMAC=y
# Other I2C/SMBus bus drivers
#
CONFIG_I2C_OPAL=y
+# CONFIG_I2C_VIRTIO is not set
# end of I2C Hardware Bus support
# CONFIG_I2C_STUB is not set
@@ -3063,16 +3262,18 @@ CONFIG_PPS=y
# PTP clock support
#
CONFIG_PTP_1588_CLOCK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
#
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
#
+# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
+# CONFIG_PTP_1588_CLOCK_IDTCM is not set
# end of PTP clock support
# CONFIG_PINCTRL is not set
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
-# CONFIG_POWER_AVS is not set
# CONFIG_POWER_RESET is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
@@ -3080,6 +3281,7 @@ CONFIG_POWER_SUPPLY_HWMON=y
# CONFIG_PDA_POWER is not set
# CONFIG_TEST_POWER is not set
# CONFIG_CHARGER_ADP5061 is not set
+# CONFIG_BATTERY_CW2015 is not set
# CONFIG_BATTERY_DS2780 is not set
# CONFIG_BATTERY_DS2781 is not set
# CONFIG_BATTERY_DS2782 is not set
@@ -3090,10 +3292,13 @@ CONFIG_POWER_SUPPLY_HWMON=y
# CONFIG_BATTERY_MAX17042 is not set
# CONFIG_CHARGER_MAX8903 is not set
# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_LTC4162L is not set
# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
# CONFIG_CHARGER_BQ2415X is not set
-# CONFIG_CHARGER_SMB347 is not set
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_RT5033 is not set
+# CONFIG_CHARGER_BD99954 is not set
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
@@ -3107,16 +3312,23 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM1177 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ADT7410 is not set
# CONFIG_SENSORS_ADT7411 is not set
# CONFIG_SENSORS_ADT7462 is not set
# CONFIG_SENSORS_ADT7470 is not set
# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AHT10 is not set
+# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
# CONFIG_SENSORS_AS370 is not set
# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
# CONFIG_SENSORS_ASPEED is not set
# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_CORSAIR_CPRO is not set
+# CONFIG_SENSORS_CORSAIR_PSU is not set
+# CONFIG_SENSORS_DRIVETEMP is not set
# CONFIG_SENSORS_DS620 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_I5K_AMB is not set
@@ -3133,6 +3345,7 @@ CONFIG_SENSORS_IBMPOWERNV=y
# CONFIG_SENSORS_POWR1220 is not set
# CONFIG_SENSORS_LINEAGE is not set
# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC2947_I2C is not set
# CONFIG_SENSORS_LTC2990 is not set
# CONFIG_SENSORS_LTC4151 is not set
# CONFIG_SENSORS_LTC4215 is not set
@@ -3140,10 +3353,12 @@ CONFIG_SENSORS_IBMPOWERNV=y
# CONFIG_SENSORS_LTC4245 is not set
# CONFIG_SENSORS_LTC4260 is not set
# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_MAX127 is not set
# CONFIG_SENSORS_MAX16065 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX1668 is not set
# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX31730 is not set
# CONFIG_SENSORS_MAX6621 is not set
# CONFIG_SENSORS_MAX6639 is not set
# CONFIG_SENSORS_MAX6642 is not set
@@ -3152,6 +3367,8 @@ CONFIG_SENSORS_IBMPOWERNV=y
# CONFIG_SENSORS_MAX31790 is not set
# CONFIG_SENSORS_MCP3021 is not set
# CONFIG_SENSORS_TC654 is not set
+# CONFIG_SENSORS_TPS23861 is not set
+# CONFIG_SENSORS_MR75203 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM73 is not set
# CONFIG_SENSORS_LM75 is not set
@@ -3169,12 +3386,15 @@ CONFIG_SENSORS_IBMPOWERNV=y
# CONFIG_SENSORS_LM95245 is not set
# CONFIG_SENSORS_NTC_THERMISTOR is not set
# CONFIG_SENSORS_NCT7802 is not set
-# CONFIG_SENSORS_NCT7904 is not set
# CONFIG_SENSORS_NPCM7XX is not set
+# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_SBTSI is not set
+# CONFIG_SENSORS_SBRMI is not set
# CONFIG_SENSORS_SHT21 is not set
# CONFIG_SENSORS_SHT3x is not set
+# CONFIG_SENSORS_SHT4x is not set
# CONFIG_SENSORS_SHTC1 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_EMC1403 is not set
@@ -3196,6 +3416,7 @@ CONFIG_SENSORS_IBMPOWERNV=y
# CONFIG_SENSORS_TMP108 is not set
# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TMP513 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83773G is not set
@@ -3249,11 +3470,15 @@ CONFIG_BCMA_DRIVER_PCI=y
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_GATEWORKS_GSC is not set
# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MP2629 is not set
# CONFIG_MFD_HI6421_PMIC is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_LPC_ICH is not set
# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_INTEL_PMT is not set
+# CONFIG_MFD_IQS62X is not set
# CONFIG_MFD_JANZ_CMODIO is not set
# CONFIG_MFD_KEMPLD is not set
# CONFIG_MFD_88PM800 is not set
@@ -3269,12 +3494,15 @@ CONFIG_BCMA_DRIVER_PCI=y
# CONFIG_MFD_MAX8925 is not set
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MT6360 is not set
# CONFIG_MFD_MT6397 is not set
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_NTXEC is not set
# CONFIG_MFD_RETU is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RT4831 is not set
# CONFIG_MFD_RT5033 is not set
# CONFIG_MFD_RC5T583 is not set
# CONFIG_MFD_RK808 is not set
@@ -3283,8 +3511,6 @@ CONFIG_BCMA_DRIVER_PCI=y
# CONFIG_MFD_SI476X_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_SKY81452 is not set
-# CONFIG_MFD_SMSC is not set
-# CONFIG_ABX500_CORE is not set
# CONFIG_MFD_STMPE is not set
# CONFIG_MFD_SYSCON is not set
# CONFIG_MFD_TI_AM335X_TSCADC is not set
@@ -3318,8 +3544,13 @@ CONFIG_BCMA_DRIVER_PCI=y
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_ROHM_BD718XX is not set
# CONFIG_MFD_ROHM_BD70528 is not set
+# CONFIG_MFD_ROHM_BD71828 is not set
+# CONFIG_MFD_ROHM_BD957XMUF is not set
# CONFIG_MFD_STPMIC1 is not set
# CONFIG_MFD_STMFX is not set
+# CONFIG_MFD_ATC260X_I2C is not set
+# CONFIG_MFD_QCOM_PM8008 is not set
+# CONFIG_MFD_RSMU_I2C is not set
# end of Multifunction device drivers
# CONFIG_REGULATOR is not set
@@ -3339,19 +3570,34 @@ CONFIG_IR_XMP_DECODER=y
# CONFIG_IR_IMON_DECODER is not set
# CONFIG_IR_RCMM_DECODER is not set
# CONFIG_RC_DEVICES is not set
+# CONFIG_MEDIA_CEC_SUPPORT is not set
CONFIG_MEDIA_SUPPORT=m
+# CONFIG_MEDIA_SUPPORT_FILTER is not set
+CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
#
-# Multimedia core support
+# Media device types
#
-# CONFIG_MEDIA_CAMERA_SUPPORT is not set
+CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_RADIO_SUPPORT=y
-# CONFIG_MEDIA_SDR_SUPPORT is not set
-# CONFIG_MEDIA_CEC_SUPPORT is not set
-# CONFIG_MEDIA_CONTROLLER is not set
+CONFIG_MEDIA_SDR_SUPPORT=y
+CONFIG_MEDIA_PLATFORM_SUPPORT=y
+CONFIG_MEDIA_TEST_SUPPORT=y
+# end of Media device types
+
+#
+# Media core support
+#
CONFIG_VIDEO_DEV=m
+# CONFIG_MEDIA_CONTROLLER is not set
+CONFIG_DVB_CORE=m
+# end of Media core support
+
+#
+# Video4Linux options
+#
CONFIG_VIDEO_V4L2=m
CONFIG_VIDEO_V4L2_I2C=y
# CONFIG_VIDEO_ADV_DEBUG is not set
@@ -3360,13 +3606,18 @@ CONFIG_VIDEO_TUNER=m
CONFIG_VIDEOBUF_GEN=m
CONFIG_VIDEOBUF_DMA_SG=m
CONFIG_VIDEOBUF_VMALLOC=m
-CONFIG_DVB_CORE=m
+# end of Video4Linux options
+
+#
+# Digital TV options
+#
# CONFIG_DVB_MMAP is not set
CONFIG_DVB_NET=y
CONFIG_DVB_MAX_ADAPTERS=16
# CONFIG_DVB_DYNAMIC_MINORS is not set
# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set
# CONFIG_DVB_ULE_DEBUG is not set
+# end of Digital TV options
#
# Media drivers
@@ -3374,6 +3625,19 @@ CONFIG_DVB_MAX_ADAPTERS=16
CONFIG_MEDIA_USB_SUPPORT=y
#
+# Webcam devices
+#
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_VIDEO_USBTV is not set
+
+#
# Analog TV USB devices
#
CONFIG_VIDEO_PVRUSB2=m
@@ -3381,7 +3645,6 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y
CONFIG_VIDEO_PVRUSB2_DVB=y
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
CONFIG_VIDEO_HDPVR=m
-# CONFIG_VIDEO_USBVISION is not set
# CONFIG_VIDEO_STK1160_COMMON is not set
# CONFIG_VIDEO_GO7007 is not set
@@ -3410,13 +3673,26 @@ CONFIG_VIDEO_CX231XX_DVB=m
# Webcam, TV (analog/digital) USB devices
#
# CONFIG_VIDEO_EM28XX is not set
+
+#
+# Software defined radio USB devices
+#
+# CONFIG_USB_AIRSPY is not set
+# CONFIG_USB_HACKRF is not set
CONFIG_MEDIA_PCI_SUPPORT=y
#
+# Media capture support
+#
+# CONFIG_VIDEO_SOLO6X10 is not set
+# CONFIG_VIDEO_TW5864 is not set
+# CONFIG_VIDEO_TW68 is not set
+# CONFIG_VIDEO_TW686X is not set
+
+#
# Media capture/analog TV support
#
CONFIG_VIDEO_IVTV=m
-# CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS is not set
CONFIG_VIDEO_IVTV_ALSA=m
# CONFIG_VIDEO_FB_IVTV is not set
# CONFIG_VIDEO_HEXIUM_GEMINI is not set
@@ -3448,7 +3724,6 @@ CONFIG_DVB_BT8XX=m
#
# Media digital TV PCI Adapters
#
-# CONFIG_DVB_AV7110 is not set
# CONFIG_DVB_BUDGET_CORE is not set
# CONFIG_DVB_B2C2_FLEXCOP_PCI is not set
# CONFIG_DVB_PLUTO2 is not set
@@ -3459,12 +3734,6 @@ CONFIG_DVB_BT8XX=m
# CONFIG_DVB_NGENE is not set
# CONFIG_DVB_DDBRIDGE is not set
# CONFIG_DVB_SMIPCIE is not set
-# CONFIG_DVB_PLATFORM_DRIVERS is not set
-
-#
-# Supported MMC/SDIO adapters
-#
-# CONFIG_SMS_SDIO_DRV is not set
CONFIG_RADIO_ADAPTERS=y
CONFIG_RADIO_TEA575X=m
# CONFIG_RADIO_SI470X is not set
@@ -3481,31 +3750,36 @@ CONFIG_RADIO_TEA575X=m
# CONFIG_RADIO_SAA7706H is not set
# CONFIG_RADIO_TEF6862 is not set
# CONFIG_RADIO_WL1273 is not set
-
-#
-# Texas Instruments WL128x FM driver (ST based)
-#
-# end of Texas Instruments WL128x FM driver (ST based)
-
CONFIG_VIDEO_CX2341X=m
CONFIG_VIDEO_TVEEPROM=m
-# CONFIG_CYPRESS_FIRMWARE is not set
CONFIG_VIDEOBUF2_CORE=m
CONFIG_VIDEOBUF2_V4L2=m
CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_VMALLOC=m
CONFIG_VIDEOBUF2_DMA_SG=m
CONFIG_VIDEOBUF2_DVB=m
+# CONFIG_V4L_PLATFORM_DRIVERS is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_DVB_PLATFORM_DRIVERS is not set
+# CONFIG_SDR_PLATFORM_DRIVERS is not set
#
-# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
+# MMC/SDIO DVB adapters
+#
+# CONFIG_SMS_SDIO_DRV is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_DVB_TEST_DRIVERS is not set
+# end of Media drivers
+
+#
+# Media ancillary drivers
#
-CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
CONFIG_MEDIA_ATTACH=y
-CONFIG_VIDEO_IR_I2C=m
#
-# I2C Encoders, decoders, sensors and other helper chips
+# IR I2C driver auto-selected by 'Autoselect ancillary drivers'
#
+CONFIG_VIDEO_IR_I2C=m
#
# Audio decoders, processors and mixers
@@ -3525,16 +3799,20 @@ CONFIG_VIDEO_WM8775=m
CONFIG_VIDEO_WM8739=m
CONFIG_VIDEO_VP27SMPX=m
# CONFIG_VIDEO_SONY_BTF_MPX is not set
+# end of Audio decoders, processors and mixers
#
# RDS decoders
#
CONFIG_VIDEO_SAA6588=m
+# end of RDS decoders
#
# Video decoders
#
# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV748X is not set
+# CONFIG_VIDEO_ADV7842 is not set
# CONFIG_VIDEO_BT819 is not set
# CONFIG_VIDEO_BT856 is not set
# CONFIG_VIDEO_BT866 is not set
@@ -3542,6 +3820,7 @@ CONFIG_VIDEO_SAA6588=m
# CONFIG_VIDEO_ML86V7667 is not set
# CONFIG_VIDEO_SAA7110 is not set
CONFIG_VIDEO_SAA711X=m
+# CONFIG_VIDEO_TC358743 is not set
# CONFIG_VIDEO_TVP514X is not set
# CONFIG_VIDEO_TVP5150 is not set
# CONFIG_VIDEO_TVP7002 is not set
@@ -3556,6 +3835,7 @@ CONFIG_VIDEO_SAA711X=m
#
CONFIG_VIDEO_SAA717X=m
CONFIG_VIDEO_CX25840=m
+# end of Video decoders
#
# Video encoders
@@ -3566,37 +3846,30 @@ CONFIG_VIDEO_SAA7127=m
# CONFIG_VIDEO_ADV7175 is not set
# CONFIG_VIDEO_ADV7343 is not set
# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV7511 is not set
+# CONFIG_VIDEO_AD9389B is not set
# CONFIG_VIDEO_AK881X is not set
# CONFIG_VIDEO_THS8200 is not set
-
-#
-# Camera sensor devices
-#
-# CONFIG_VIDEO_OV9640 is not set
-# CONFIG_VIDEO_MT9M111 is not set
-
-#
-# Lens drivers
-#
-
-#
-# Flash devices
-#
+# end of Video encoders
#
# Video improvement chips
#
CONFIG_VIDEO_UPD64031A=m
CONFIG_VIDEO_UPD64083=m
+# end of Video improvement chips
#
# Audio/Video compression chips
#
# CONFIG_VIDEO_SAA6752HS is not set
+# end of Audio/Video compression chips
#
# SDR tuner chips
#
+# CONFIG_SDR_MAX2175 is not set
+# end of SDR tuner chips
#
# Miscellaneous helper chips
@@ -3604,7 +3877,79 @@ CONFIG_VIDEO_UPD64083=m
# CONFIG_VIDEO_THS7303 is not set
CONFIG_VIDEO_M52790=m
# CONFIG_VIDEO_I2C is not set
-# end of I2C Encoders, decoders, sensors and other helper chips
+# CONFIG_VIDEO_ST_MIPID02 is not set
+# end of Miscellaneous helper chips
+
+#
+# Camera sensor devices
+#
+# CONFIG_VIDEO_HI556 is not set
+# CONFIG_VIDEO_IMX219 is not set
+# CONFIG_VIDEO_IMX258 is not set
+# CONFIG_VIDEO_IMX274 is not set
+# CONFIG_VIDEO_IMX290 is not set
+# CONFIG_VIDEO_IMX319 is not set
+# CONFIG_VIDEO_IMX355 is not set
+# CONFIG_VIDEO_OV02A10 is not set
+# CONFIG_VIDEO_OV2640 is not set
+# CONFIG_VIDEO_OV2680 is not set
+# CONFIG_VIDEO_OV2685 is not set
+# CONFIG_VIDEO_OV5645 is not set
+# CONFIG_VIDEO_OV5647 is not set
+# CONFIG_VIDEO_OV5648 is not set
+# CONFIG_VIDEO_OV6650 is not set
+# CONFIG_VIDEO_OV5670 is not set
+# CONFIG_VIDEO_OV5675 is not set
+# CONFIG_VIDEO_OV5695 is not set
+# CONFIG_VIDEO_OV7251 is not set
+# CONFIG_VIDEO_OV772X is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_OV7740 is not set
+# CONFIG_VIDEO_OV8856 is not set
+# CONFIG_VIDEO_OV8865 is not set
+# CONFIG_VIDEO_OV9640 is not set
+# CONFIG_VIDEO_OV9650 is not set
+# CONFIG_VIDEO_OV13858 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_MT9M001 is not set
+# CONFIG_VIDEO_MT9M032 is not set
+# CONFIG_VIDEO_MT9M111 is not set
+# CONFIG_VIDEO_MT9P031 is not set
+# CONFIG_VIDEO_MT9T001 is not set
+# CONFIG_VIDEO_MT9T112 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MT9V032 is not set
+# CONFIG_VIDEO_MT9V111 is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_M5MOLS is not set
+# CONFIG_VIDEO_RDACM20 is not set
+# CONFIG_VIDEO_RDACM21 is not set
+# CONFIG_VIDEO_RJ54N1 is not set
+# CONFIG_VIDEO_S5K6AA is not set
+# CONFIG_VIDEO_S5K6A3 is not set
+# CONFIG_VIDEO_S5K4ECGX is not set
+# CONFIG_VIDEO_S5K5BAF is not set
+# CONFIG_VIDEO_ET8EK8 is not set
+# end of Camera sensor devices
+
+#
+# Lens drivers
+#
+# CONFIG_VIDEO_AK7375 is not set
+# CONFIG_VIDEO_DW9714 is not set
+# CONFIG_VIDEO_DW9768 is not set
+# CONFIG_VIDEO_DW9807_VCM is not set
+# end of Lens drivers
+
+#
+# Flash devices
+#
+# CONFIG_VIDEO_ADP1653 is not set
+# CONFIG_VIDEO_LM3560 is not set
+# CONFIG_VIDEO_LM3646 is not set
+# end of Flash devices
#
# SPI helper chips
@@ -3713,7 +4058,6 @@ CONFIG_DVB_TDA10071=m
#
# DVB-T (terrestrial) frontends
#
-# CONFIG_DVB_SP8870 is not set
CONFIG_DVB_SP887X=m
# CONFIG_DVB_CX22700 is not set
CONFIG_DVB_CX22702=m
@@ -3737,6 +4081,7 @@ CONFIG_DVB_STV0367=m
# CONFIG_DVB_CXD2841ER is not set
# CONFIG_DVB_RTL2830 is not set
# CONFIG_DVB_RTL2832 is not set
+# CONFIG_DVB_RTL2832_SDR is not set
CONFIG_DVB_SI2168=m
# CONFIG_DVB_ZD1301_DEMOD is not set
@@ -3763,6 +4108,7 @@ CONFIG_DVB_S5H1409=m
# CONFIG_DVB_AU8522_DTV is not set
# CONFIG_DVB_AU8522_V4L is not set
CONFIG_DVB_S5H1411=m
+# CONFIG_DVB_MXL692 is not set
#
# ISDB-T (terrestrial) frontends
@@ -3812,12 +4158,13 @@ CONFIG_DVB_A8293=m
#
# CONFIG_DVB_CXD2099 is not set
# CONFIG_DVB_SP2 is not set
+# end of Customise DVB Frontends
#
# Tools to develop new frontends
#
# CONFIG_DVB_DUMMY_FE is not set
-# end of Customise DVB Frontends
+# end of Media ancillary drivers
#
# Graphics support
@@ -3830,7 +4177,7 @@ CONFIG_DRM=m
# CONFIG_DRM_DP_AUX_CHARDEV is not set
# CONFIG_DRM_DEBUG_SELFTEST is not set
CONFIG_DRM_KMS_HELPER=m
-CONFIG_DRM_KMS_FB_HELPER=y
+# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
@@ -3838,6 +4185,7 @@ CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_DP_CEC is not set
CONFIG_DRM_TTM=m
CONFIG_DRM_VRAM_HELPER=m
+CONFIG_DRM_TTM_HELPER=m
CONFIG_DRM_GEM_SHMEM_HELPER=y
CONFIG_DRM_SCHED=m
@@ -3861,7 +4209,6 @@ CONFIG_DRM_AMDGPU=m
CONFIG_DRM_AMDGPU_SI=y
CONFIG_DRM_AMDGPU_CIK=y
CONFIG_DRM_AMDGPU_USERPTR=y
-# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set
#
# ACP (Audio CoProcessor) Configuration
@@ -3873,25 +4220,28 @@ CONFIG_DRM_AMDGPU_USERPTR=y
# Display Engine Configuration
#
CONFIG_DRM_AMD_DC=y
-# CONFIG_DEBUG_KERNEL_DC is not set
+CONFIG_DRM_AMD_DC_DCN=y
+# CONFIG_DRM_AMD_DC_HDCP is not set
+CONFIG_DRM_AMD_DC_SI=y
+# CONFIG_DRM_AMD_SECURE_DISPLAY is not set
# end of Display Engine Configuration
+# CONFIG_HSA_AMD is not set
CONFIG_DRM_NOUVEAU=m
# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set
CONFIG_NOUVEAU_DEBUG=5
CONFIG_NOUVEAU_DEBUG_DEFAULT=3
# CONFIG_NOUVEAU_DEBUG_MMU is not set
+# CONFIG_NOUVEAU_DEBUG_PUSH is not set
CONFIG_DRM_NOUVEAU_BACKLIGHT=y
# CONFIG_DRM_VGEM is not set
# CONFIG_DRM_VKMS is not set
# CONFIG_DRM_UDL is not set
CONFIG_DRM_AST=m
CONFIG_DRM_MGAG200=m
-CONFIG_DRM_CIRRUS_QEMU=m
# CONFIG_DRM_RCAR_DW_HDMI is not set
# CONFIG_DRM_RCAR_LVDS is not set
CONFIG_DRM_QXL=m
-CONFIG_DRM_BOCHS=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_PANEL=y
@@ -3901,6 +4251,9 @@ CONFIG_DRM_PANEL=y
# CONFIG_DRM_PANEL_LVDS is not set
# CONFIG_DRM_PANEL_SIMPLE is not set
# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
+# CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set
# end of Display Panels
@@ -3911,27 +4264,47 @@ CONFIG_DRM_PANEL_BRIDGE=y
#
# Display Interface Bridges
#
-# CONFIG_DRM_ANALOGIX_ANX78XX is not set
# CONFIG_DRM_CDNS_DSI is not set
-# CONFIG_DRM_DUMB_VGA_DAC is not set
-# CONFIG_DRM_LVDS_ENCODER is not set
+# CONFIG_DRM_CHIPONE_ICN6211 is not set
+# CONFIG_DRM_CHRONTEL_CH7033 is not set
+# CONFIG_DRM_DISPLAY_CONNECTOR is not set
+# CONFIG_DRM_LONTIUM_LT8912B is not set
+# CONFIG_DRM_LONTIUM_LT9611 is not set
+# CONFIG_DRM_LONTIUM_LT9611UXC is not set
+# CONFIG_DRM_ITE_IT66121 is not set
+# CONFIG_DRM_LVDS_CODEC is not set
# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
# CONFIG_DRM_NXP_PTN3460 is not set
# CONFIG_DRM_PARADE_PS8622 is not set
+# CONFIG_DRM_PARADE_PS8640 is not set
# CONFIG_DRM_SIL_SII8620 is not set
# CONFIG_DRM_SII902X is not set
# CONFIG_DRM_SII9234 is not set
+# CONFIG_DRM_SIMPLE_BRIDGE is not set
# CONFIG_DRM_THINE_THC63LVD1024 is not set
+# CONFIG_DRM_TOSHIBA_TC358762 is not set
# CONFIG_DRM_TOSHIBA_TC358764 is not set
# CONFIG_DRM_TOSHIBA_TC358767 is not set
+# CONFIG_DRM_TOSHIBA_TC358768 is not set
+# CONFIG_DRM_TOSHIBA_TC358775 is not set
# CONFIG_DRM_TI_TFP410 is not set
+# CONFIG_DRM_TI_SN65DSI83 is not set
# CONFIG_DRM_TI_SN65DSI86 is not set
+# CONFIG_DRM_TI_TPD12S015 is not set
+# CONFIG_DRM_ANALOGIX_ANX6345 is not set
+# CONFIG_DRM_ANALOGIX_ANX78XX is not set
+# CONFIG_DRM_ANALOGIX_ANX7625 is not set
# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_CDNS_MHDP8546 is not set
# end of Display Interface Bridges
# CONFIG_DRM_ETNAVIV is not set
# CONFIG_DRM_ARCPGU is not set
+CONFIG_DRM_BOCHS=m
+CONFIG_DRM_CIRRUS_QEMU=m
# CONFIG_DRM_GM12U320 is not set
+# CONFIG_DRM_SIMPLEDRM is not set
+# CONFIG_DRM_GUD is not set
# CONFIG_DRM_LEGACY is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m
@@ -4013,14 +4386,14 @@ CONFIG_FB_SIMPLE=y
CONFIG_LCD_CLASS_DEVICE=m
# CONFIG_LCD_PLATFORM is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_GENERIC=y
-# CONFIG_BACKLIGHT_PM8941_WLED is not set
+# CONFIG_BACKLIGHT_QCOM_WLED is not set
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
# CONFIG_BACKLIGHT_LM3639 is not set
# CONFIG_BACKLIGHT_LV5207LP is not set
# CONFIG_BACKLIGHT_BD6107 is not set
# CONFIG_BACKLIGHT_ARCXCNN is not set
+# CONFIG_BACKLIGHT_LED is not set
# end of Backlight & LCD device support
CONFIG_HDMI=y
@@ -4070,6 +4443,7 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
+CONFIG_SND_CTL_LED=m
CONFIG_SND_SEQUENCER=m
# CONFIG_SND_SEQ_DUMMY is not set
CONFIG_SND_SEQUENCER_OSS=m
@@ -4152,8 +4526,8 @@ CONFIG_SND_YMFPCI=m
# HD-Audio
#
CONFIG_SND_HDA=m
+CONFIG_SND_HDA_GENERIC_LEDS=y
CONFIG_SND_HDA_INTEL=m
-# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set
# CONFIG_SND_HDA_HWDEP is not set
# CONFIG_SND_HDA_RECONFIG is not set
CONFIG_SND_HDA_INPUT_BEEP=y
@@ -4165,6 +4539,7 @@ CONFIG_SND_HDA_CODEC_SIGMATEL=m
CONFIG_SND_HDA_CODEC_VIA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_HDA_CODEC_CIRRUS=m
+# CONFIG_SND_HDA_CODEC_CS8409 is not set
CONFIG_SND_HDA_CODEC_CONEXANT=m
CONFIG_SND_HDA_CODEC_CA0110=m
CONFIG_SND_HDA_CODEC_CA0132=m
@@ -4173,11 +4548,13 @@ CONFIG_SND_HDA_CODEC_CMEDIA=m
CONFIG_SND_HDA_CODEC_SI3054=m
CONFIG_SND_HDA_GENERIC=m
CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set
# end of HD-Audio
CONFIG_SND_HDA_CORE=m
CONFIG_SND_HDA_COMPONENT=y
CONFIG_SND_HDA_PREALLOC_SIZE=64
+CONFIG_SND_INTEL_DSP_CONFIG=m
CONFIG_SND_PPC=y
CONFIG_SND_POWERMAC=m
CONFIG_SND_POWERMAC_AUTO_DRC=y
@@ -4203,6 +4580,7 @@ CONFIG_SND_USB_AUDIO=m
# CONFIG_SND_USB_TONEPORT is not set
# CONFIG_SND_USB_VARIAX is not set
# CONFIG_SND_SOC is not set
+# CONFIG_SND_VIRTIO is not set
CONFIG_AC97_BUS=m
#
@@ -4244,7 +4622,9 @@ CONFIG_HID_CYPRESS=m
CONFIG_HID_EZKEY=m
# CONFIG_HID_GEMBIRD is not set
# CONFIG_HID_GFRM is not set
+# CONFIG_HID_GLORIOUS is not set
# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_VIVALDI is not set
# CONFIG_HID_GT683R is not set
# CONFIG_HID_KEYTOUCH is not set
# CONFIG_HID_KYE is not set
@@ -4282,11 +4662,13 @@ CONFIG_HID_PANTHERLORD=m
CONFIG_HID_PETALYNX=m
# CONFIG_HID_PICOLCD is not set
# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PLAYSTATION is not set
# CONFIG_HID_PRIMAX is not set
# CONFIG_HID_RETRODE is not set
# CONFIG_HID_ROCCAT is not set
# CONFIG_HID_SAITEK is not set
CONFIG_HID_SAMSUNG=m
+# CONFIG_HID_SEMITEK is not set
CONFIG_HID_SONY=m
CONFIG_SONY_FF=y
# CONFIG_HID_SPEEDLINK is not set
@@ -4322,7 +4704,8 @@ CONFIG_USB_HIDDEV=y
#
# I2C HID support
#
-# CONFIG_I2C_HID is not set
+# CONFIG_I2C_HID_OF is not set
+# CONFIG_I2C_HID_OF_GOODIX is not set
# end of I2C HID support
# end of HID support
@@ -4343,10 +4726,11 @@ CONFIG_USB_PCI=y
# Miscellaneous USB options
#
CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_FEW_INIT_RETRIES is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_PRODUCTLIST is not set
+# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
CONFIG_USB_AUTOSUSPEND_DELAY=2
CONFIG_USB_MON=y
@@ -4358,6 +4742,7 @@ CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
# CONFIG_USB_XHCI_DBGCAP is not set
CONFIG_USB_XHCI_PCI=y
+# CONFIG_USB_XHCI_PCI_RENESAS is not set
CONFIG_USB_XHCI_PLATFORM=m
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
@@ -4420,7 +4805,7 @@ CONFIG_USB_UAS=m
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USBIP_CORE is not set
-# CONFIG_USB_CDNS3 is not set
+# CONFIG_USB_CDNS_SUPPORT is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_DWC3 is not set
# CONFIG_USB_DWC2 is not set
@@ -4474,7 +4859,6 @@ CONFIG_USB_SERIAL_SIERRAWIRELESS=m
CONFIG_USB_SERIAL_SYMBOL=m
CONFIG_USB_SERIAL_TI=m
CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_WWAN=m
CONFIG_USB_SERIAL_OPTION=m
CONFIG_USB_SERIAL_OMNINET=m
@@ -4484,6 +4868,7 @@ CONFIG_USB_SERIAL_WISHBONE=m
CONFIG_USB_SERIAL_SSU100=m
CONFIG_USB_SERIAL_QT2=m
CONFIG_USB_SERIAL_UPD78F0730=m
+# CONFIG_USB_SERIAL_XR is not set
CONFIG_USB_SERIAL_DEBUG=m
#
@@ -4500,6 +4885,7 @@ CONFIG_USB_SERIAL_DEBUG=m
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
CONFIG_USB_APPLEDISPLAY=m
+# CONFIG_APPLE_MFI_FASTCHARGE is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
@@ -4533,6 +4919,7 @@ CONFIG_MMC_BLOCK=m
CONFIG_MMC_BLOCK_MINORS=8
# CONFIG_SDIO_UART is not set
# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_CRYPTO is not set
#
# MMC/SD/SDIO Host Controller Drivers
@@ -4544,11 +4931,11 @@ CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_PLTFM=m
# CONFIG_MMC_SDHCI_OF_ASPEED is not set
-# CONFIG_MMC_SDHCI_OF_AT91 is not set
# CONFIG_MMC_SDHCI_OF_ESDHC is not set
CONFIG_MMC_SDHCI_OF_HLWD=m
# CONFIG_MMC_SDHCI_CADENCE is not set
# CONFIG_MMC_SDHCI_F_SDH30 is not set
+# CONFIG_MMC_SDHCI_MILBEAUT is not set
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
# CONFIG_MMC_CB710 is not set
@@ -4557,8 +4944,8 @@ CONFIG_MMC_SDHCI_OF_HLWD=m
# CONFIG_MMC_USHC is not set
# CONFIG_MMC_USDHI6ROL0 is not set
# CONFIG_MMC_CQHCI is not set
+# CONFIG_MMC_HSQ is not set
# CONFIG_MMC_TOSHIBA_PCI is not set
-# CONFIG_MMC_MTK is not set
# CONFIG_MMC_SDHCI_XENON is not set
# CONFIG_MMC_SDHCI_OMAP is not set
CONFIG_MEMSTICK=m
@@ -4580,12 +4967,14 @@ CONFIG_MEMSTICK_R592=m
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_CLASS_FLASH is not set
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set
#
# LED drivers
#
# CONFIG_LEDS_AN30259A is not set
+# CONFIG_LEDS_AW2013 is not set
# CONFIG_LEDS_BCM6328 is not set
# CONFIG_LEDS_BCM6358 is not set
# CONFIG_LEDS_LM3530 is not set
@@ -4594,10 +4983,8 @@ CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_LM3692X is not set
# CONFIG_LEDS_PCA9532 is not set
# CONFIG_LEDS_LP3944 is not set
-# CONFIG_LEDS_LP5521 is not set
-# CONFIG_LEDS_LP5523 is not set
-# CONFIG_LEDS_LP5562 is not set
-# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP50XX is not set
+# CONFIG_LEDS_LP55XX_COMMON is not set
# CONFIG_LEDS_LP8860 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_PCA963X is not set
@@ -4618,6 +5005,10 @@ CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_TI_LMU_COMMON is not set
#
+# Flash and Torch LED drivers
+#
+
+#
# LED Triggers
#
CONFIG_LEDS_TRIGGERS=y
@@ -4639,7 +5030,8 @@ CONFIG_LEDS_TRIGGERS=y
# CONFIG_LEDS_TRIGGER_PANIC is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_PATTERN is not set
-# CONFIG_LEDS_TRIGGER_AUDIO is not set
+CONFIG_LEDS_TRIGGER_AUDIO=m
+# CONFIG_LEDS_TRIGGER_TTY is not set
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
CONFIG_EDAC_ATOMIC_SCRUB=y
@@ -4699,6 +5091,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_RX8025 is not set
# CONFIG_RTC_DRV_EM3027 is not set
# CONFIG_RTC_DRV_RV3028 is not set
+# CONFIG_RTC_DRV_RV3032 is not set
# CONFIG_RTC_DRV_RV8803 is not set
# CONFIG_RTC_DRV_SD3078 is not set
@@ -4713,6 +5106,7 @@ CONFIG_RTC_I2C_AND_SPI=y
# CONFIG_RTC_DRV_DS3232 is not set
# CONFIG_RTC_DRV_PCF2127 is not set
# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX6110 is not set
#
# Platform RTC drivers
@@ -4742,12 +5136,12 @@ CONFIG_RTC_DRV_GENERIC=y
# CONFIG_RTC_DRV_CADENCE is not set
# CONFIG_RTC_DRV_FTRTC010 is not set
# CONFIG_RTC_DRV_PS3 is not set
-# CONFIG_RTC_DRV_SNVS is not set
# CONFIG_RTC_DRV_R7301 is not set
#
# HID Sensor RTC drivers
#
+# CONFIG_RTC_DRV_GOLDFISH is not set
# CONFIG_DMADEVICES is not set
#
@@ -4756,25 +5150,29 @@ CONFIG_RTC_DRV_GENERIC=y
CONFIG_SYNC_FILE=y
# CONFIG_SW_SYNC is not set
# CONFIG_UDMABUF is not set
+# CONFIG_DMABUF_MOVE_NOTIFY is not set
+# CONFIG_DMABUF_DEBUG is not set
# CONFIG_DMABUF_SELFTESTS is not set
+# CONFIG_DMABUF_HEAPS is not set
+# CONFIG_DMABUF_SYSFS_STATS is not set
# end of DMABUF options
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+CONFIG_VFIO=m
CONFIG_VFIO_IOMMU_SPAPR_TCE=m
CONFIG_VFIO_SPAPR_EEH=m
CONFIG_VFIO_VIRQFD=m
-CONFIG_VFIO=m
# CONFIG_VFIO_NOIOMMU is not set
-CONFIG_VFIO_PCI=m
+CONFIG_VFIO_PCI_CORE=m
CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y
-CONFIG_VFIO_PCI_NVLINK2=y
+CONFIG_VFIO_PCI=m
CONFIG_VFIO_MDEV=m
-CONFIG_VFIO_MDEV_DEVICE=m
CONFIG_IRQ_BYPASS_MANAGER=y
CONFIG_VIRT_DRIVERS=y
CONFIG_VIRTIO=y
+CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=y
# CONFIG_VIRTIO_PCI_LEGACY is not set
@@ -4782,6 +5180,13 @@ CONFIG_VIRTIO_BALLOON=m
CONFIG_VIRTIO_INPUT=m
CONFIG_VIRTIO_MMIO=y
# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_DMA_SHARED_BUFFER=m
+# CONFIG_VDPA is not set
+CONFIG_VHOST_IOTLB=m
+CONFIG_VHOST=m
+CONFIG_VHOST_MENU=y
+CONFIG_VHOST_NET=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
#
# Microsoft Hyper-V guest support
@@ -4789,12 +5194,16 @@ CONFIG_VIRTIO_MMIO=y
# end of Microsoft Hyper-V guest support
# CONFIG_GREYBUS is not set
+# CONFIG_COMEDI is not set
# CONFIG_STAGING is not set
+# CONFIG_GOLDFISH is not set
+# CONFIG_COMMON_CLK is not set
# CONFIG_HWSPINLOCK is not set
#
# Clock Source drivers
#
+# CONFIG_MICROCHIP_PIT64B is not set
# end of Clock Source drivers
# CONFIG_MAILBOX is not set
@@ -4807,6 +5216,8 @@ CONFIG_IOMMU_SUPPORT=y
# end of Generic IOMMU Pagetable Support
# CONFIG_IOMMU_DEBUGFS is not set
+CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
+# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
CONFIG_SPAPR_TCE_IOMMU=y
@@ -4835,11 +5246,6 @@ CONFIG_SPAPR_TCE_IOMMU=y
# end of Amlogic SoC drivers
#
-# Aspeed SoC drivers
-#
-# end of Aspeed SoC drivers
-
-#
# Broadcom SoC drivers
#
# end of Broadcom SoC drivers
@@ -4847,6 +5253,7 @@ CONFIG_SPAPR_TCE_IOMMU=y
#
# NXP/Freescale QorIQ SoC drivers
#
+# CONFIG_QUICC_ENGINE is not set
# end of NXP/Freescale QorIQ SoC drivers
#
@@ -4855,8 +5262,15 @@ CONFIG_SPAPR_TCE_IOMMU=y
# end of i.MX SoC drivers
#
+# Enable LiteX SoC Builder specific drivers
+#
+# CONFIG_LITEX_SOC_CONTROLLER is not set
+# end of Enable LiteX SoC Builder specific drivers
+
+#
# Qualcomm SoC drivers
#
+CONFIG_QCOM_QMI_HELPERS=m
# end of Qualcomm SoC drivers
# CONFIG_SOC_TI is not set
@@ -4864,7 +5278,6 @@ CONFIG_SPAPR_TCE_IOMMU=y
#
# Xilinx SoC drivers
#
-# CONFIG_XILINX_VCU is not set
# end of Xilinx SoC drivers
# end of SOC (System On Chip) specific Drivers
@@ -4904,9 +5317,10 @@ CONFIG_IRQCHIP=y
# PHY Subsystem
#
# CONFIG_GENERIC_PHY is not set
+# CONFIG_PHY_CAN_TRANSCEIVER is not set
# CONFIG_BCM_KONA_USB2_PHY is not set
-# CONFIG_PHY_CADENCE_DP is not set
# CONFIG_PHY_CADENCE_DPHY is not set
+# CONFIG_PHY_CADENCE_SALVO is not set
# CONFIG_PHY_FSL_IMX8MQ_USB is not set
# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
# CONFIG_PHY_PXA_28NM_HSIC is not set
@@ -4922,6 +5336,7 @@ CONFIG_IRQCHIP=y
# end of Performance monitor support
CONFIG_RAS=y
+# CONFIG_USB4 is not set
#
# Android
@@ -4934,6 +5349,7 @@ CONFIG_DAX=y
# CONFIG_DEV_DAX is not set
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
+# CONFIG_NVMEM_RMEM is not set
#
# HW tracing support
@@ -4949,6 +5365,7 @@ CONFIG_PM_OPP=y
# CONFIG_SLIMBUS is not set
# CONFIG_INTERCONNECT is not set
# CONFIG_COUNTER is not set
+# CONFIG_MOST is not set
# end of Device Drivers
#
@@ -4978,6 +5395,7 @@ CONFIG_JFS_SECURITY=y
# CONFIG_JFS_DEBUG is not set
# CONFIG_JFS_STATISTICS is not set
CONFIG_XFS_FS=y
+CONFIG_XFS_SUPPORT_V4=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
@@ -5005,12 +5423,13 @@ CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_SECURITY=y
# CONFIG_F2FS_CHECK_FS is not set
# CONFIG_F2FS_FAULT_INJECTION is not set
+# CONFIG_F2FS_FS_COMPRESSION is not set
+CONFIG_F2FS_IOSTAT=y
# CONFIG_FS_DAX is not set
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
# CONFIG_EXPORTFS_BLOCK_OPS is not set
CONFIG_FILE_LOCKING=y
-# CONFIG_MANDATORY_FILE_LOCKING is not set
# CONFIG_FS_ENCRYPTION is not set
# CONFIG_FS_VERITY is not set
CONFIG_FSNOTIFY=y
@@ -5054,7 +5473,7 @@ CONFIG_UDF_FS=m
# end of CD-ROM/DVD Filesystems
#
-# DOS/FAT/NT Filesystems
+# DOS/FAT/EXFAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=m
@@ -5062,10 +5481,16 @@ CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_EXFAT_FS=m
+CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8"
CONFIG_NTFS_FS=m
# CONFIG_NTFS_DEBUG is not set
# CONFIG_NTFS_RW is not set
-# end of DOS/FAT/NT Filesystems
+CONFIG_NTFS3_FS=m
+# CONFIG_NTFS3_64BIT_CLUSTER is not set
+CONFIG_NTFS3_LZX_XPRESS=y
+# CONFIG_NTFS3_FS_POSIX_ACL is not set
+# end of DOS/FAT/EXFAT/NT Filesystems
#
# Pseudo filesystems
@@ -5080,6 +5505,8 @@ CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y
+# CONFIG_TMPFS_INODE64 is not set
+CONFIG_ARCH_SUPPORTS_HUGETLBFS=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_MEMFD_CREATE=y
@@ -5145,6 +5572,7 @@ CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
# CONFIG_NFS_V4_1_MIGRATION is not set
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
+CONFIG_NFS_DISABLE_UDP_SUPPORT=y
CONFIG_NFSD=m
CONFIG_NFSD_V2_ACL=y
CONFIG_NFSD_V3=y
@@ -5167,7 +5595,6 @@ CONFIG_SUNRPC_BACKCHANNEL=y
CONFIG_CIFS=m
# CONFIG_CIFS_STATS2 is not set
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
-# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_UPCALL is not set
CONFIG_CIFS_XATTR=y
# CONFIG_CIFS_POSIX is not set
@@ -5175,6 +5602,9 @@ CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set
# CONFIG_CIFS_DFS_UPCALL is not set
+# CONFIG_CIFS_SWN_UPCALL is not set
+# CONFIG_SMB_SERVER is not set
+CONFIG_SMBFS_COMMON=m
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
CONFIG_9P_FS=m
@@ -5233,16 +5663,15 @@ CONFIG_NLS_MAC_TURKISH=m
CONFIG_NLS_UTF8=y
# CONFIG_DLM is not set
# CONFIG_UNICODE is not set
+CONFIG_IO_WQ=y
# end of File systems
#
# Security options
#
CONFIG_KEYS=y
-CONFIG_KEYS_COMPAT=y
# CONFIG_KEYS_REQUEST_CACHE is not set
# CONFIG_PERSISTENT_KEYRINGS is not set
-# CONFIG_BIG_KEYS is not set
# CONFIG_ENCRYPTED_KEYS is not set
# CONFIG_KEY_DH_OPERATIONS is not set
# CONFIG_SECURITY_DMESG_RESTRICT is not set
@@ -5263,6 +5692,7 @@ CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_YAMA=y
# CONFIG_SECURITY_SAFESETID is not set
# CONFIG_SECURITY_LOCKDOWN_LSM is not set
+# CONFIG_SECURITY_LANDLOCK is not set
# CONFIG_INTEGRITY is not set
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
@@ -5275,6 +5705,9 @@ CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
# Memory initialization
#
CONFIG_INIT_STACK_NONE=y
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_USER is not set
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF is not set
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL is not set
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
# end of Memory initialization
@@ -5296,8 +5729,8 @@ CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_SKCIPHER=y
+CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=m
@@ -5327,7 +5760,10 @@ CONFIG_CRYPTO_RSA=y
# CONFIG_CRYPTO_DH is not set
CONFIG_CRYPTO_ECC=m
CONFIG_CRYPTO_ECDH=m
+# CONFIG_CRYPTO_ECDSA is not set
# CONFIG_CRYPTO_ECRDSA is not set
+# CONFIG_CRYPTO_SM2 is not set
+# CONFIG_CRYPTO_CURVE25519 is not set
#
# Authenticated Encryption with Associated Data
@@ -5369,7 +5805,9 @@ CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_CRC32C=y
# CONFIG_CRYPTO_CRC32C_VPMSUM is not set
CONFIG_CRYPTO_CRC32=m
-# CONFIG_CRYPTO_XXHASH is not set
+CONFIG_CRYPTO_XXHASH=m
+CONFIG_CRYPTO_BLAKE2B=m
+# CONFIG_CRYPTO_BLAKE2S is not set
CONFIG_CRYPTO_CRCT10DIF=y
# CONFIG_CRYPTO_CRCT10DIF_VPMSUM is not set
CONFIG_CRYPTO_GHASH=m
@@ -5378,39 +5816,30 @@ CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MD5_PPC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
-# CONFIG_CRYPTO_RMD128 is not set
# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA1_PPC=m
-CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
# CONFIG_CRYPTO_SHA3 is not set
# CONFIG_CRYPTO_SM3 is not set
# CONFIG_CRYPTO_STREEBOG is not set
-# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_WP512 is not set
#
# Ciphers
#
-CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_AES_TI is not set
# CONFIG_CRYPTO_ANUBIS is not set
-CONFIG_CRYPTO_LIB_ARC4=m
CONFIG_CRYPTO_ARC4=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
-CONFIG_CRYPTO_LIB_DES=m
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
CONFIG_CRYPTO_CHACHA20=m
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_SERPENT is not set
@@ -5442,8 +5871,28 @@ CONFIG_CRYPTO_USER_API=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_USER_API_RNG=m
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
CONFIG_CRYPTO_HASH_INFO=y
+
+#
+# Crypto library routines
+#
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_ARC4=m
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=m
+CONFIG_CRYPTO_LIB_BLAKE2S=m
+CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
+CONFIG_CRYPTO_LIB_CHACHA=m
+CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_DES=m
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
+CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m
+CONFIG_CRYPTO_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
+CONFIG_CRYPTO_LIB_SHA256=y
# CONFIG_CRYPTO_HW is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
@@ -5457,6 +5906,8 @@ CONFIG_PKCS7_MESSAGE_PARSER=y
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
+CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
+# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
@@ -5477,7 +5928,8 @@ CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
CONFIG_CORDIC=m
-CONFIG_RATIONAL=y
+# CONFIG_PRIME_NUMBERS is not set
+CONFIG_RATIONAL=m
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
@@ -5504,7 +5956,7 @@ CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
CONFIG_ZSTD_COMPRESS=m
-CONFIG_ZSTD_DECOMPRESS=m
+CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
@@ -5520,6 +5972,7 @@ CONFIG_DECOMPRESS_LZMA=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
+CONFIG_DECOMPRESS_ZSTD=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
@@ -5531,12 +5984,17 @@ CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
+CONFIG_DMA_OPS=y
+CONFIG_DMA_OPS_BYPASS=y
+CONFIG_ARCH_HAS_DMA_MAP_DIRECT=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_DMA_DECLARE_COHERENT=y
CONFIG_SWIOTLB=y
+# CONFIG_DMA_RESTRICTED_POOL is not set
# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_MAP_BENCHMARK is not set
CONFIG_SGL_ALLOC=y
CONFIG_IOMMU_HELPER=y
CONFIG_CHECK_SIGNATURE=y
@@ -5550,16 +6008,20 @@ CONFIG_IRQ_POLL=y
CONFIG_MPILIB=y
CONFIG_LIBFDT=y
CONFIG_OID_REGISTRY=y
+CONFIG_HAVE_GENERIC_VDSO=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_VDSO_TIME_NS=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_ARCH_HAS_MEMREMAP_COMPAT_ALIGN=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
-CONFIG_ARCH_HAS_UACCESS_MCSAFE=y
+CONFIG_ARCH_HAS_COPY_MC=y
+CONFIG_ARCH_STACKWALK=y
CONFIG_SBITMAP=y
-# CONFIG_STRING_SELFTEST is not set
# end of Library routines
#
@@ -5571,31 +6033,47 @@ CONFIG_SBITMAP=y
#
CONFIG_PRINTK_TIME=y
# CONFIG_PRINTK_CALLER is not set
+# CONFIG_STACKTRACE_BUILD_ID is not set
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG_CORE is not set
+CONFIG_SYMBOLIC_ERRNAME=y
+CONFIG_DEBUG_BUGVERBOSE=y
# end of printk and dmesg options
#
# Compile-time checks and compiler options
#
# CONFIG_DEBUG_INFO is not set
-CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=2048
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_READABLE_ASM is not set
-CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_INSTALL is not set
-CONFIG_OPTIMIZE_INLINING=y
# CONFIG_DEBUG_SECTION_MISMATCH is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
+# CONFIG_VMLINUX_MAP is not set
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# end of Compile-time checks and compiler options
+#
+# Generic Kernel Debugging Instruments
+#
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
# CONFIG_MAGIC_SYSRQ_SERIAL is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ALLOW_ALL=y
+# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
+# CONFIG_DEBUG_FS_ALLOW_NONE is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_UBSAN is not set
+# end of Generic Kernel Debugging Instruments
+
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MISC=y
@@ -5606,12 +6084,17 @@ CONFIG_DEBUG_MISC=y
# CONFIG_PAGE_OWNER is not set
# CONFIG_PAGE_POISONING is not set
# CONFIG_DEBUG_PAGE_REF is not set
+CONFIG_GENERIC_PTDUMP=y
+# CONFIG_PTDUMP_DEBUGFS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_STATS is not set
CONFIG_HAVE_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VM_PGTABLE is not set
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_VIRTUAL is not set
CONFIG_DEBUG_MEMORY_INIT=y
@@ -5619,29 +6102,31 @@ CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACKOVERFLOW is not set
CONFIG_CC_HAS_KASAN_GENERIC=y
-CONFIG_KASAN_STACK=1
+CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
# end of Memory Debugging
-CONFIG_ARCH_HAS_KCOV=y
-CONFIG_CC_HAS_SANCOV_TRACE_PC=y
-# CONFIG_KCOV is not set
# CONFIG_DEBUG_SHIRQ is not set
#
-# Debug Lockups and Hangs
+# Debug Oops, Lockups and Hangs
#
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
# CONFIG_SOFTLOCKUP_DETECTOR is not set
# CONFIG_HARDLOCKUP_DETECTOR is not set
# CONFIG_DETECT_HUNG_TASK is not set
# CONFIG_WQ_WATCHDOG is not set
-# end of Debug Lockups and Hangs
+# CONFIG_TEST_LOCKUP is not set
+# end of Debug Oops, Lockups and Hangs
-# CONFIG_PANIC_ON_OOPS is not set
-CONFIG_PANIC_ON_OOPS_VALUE=0
+#
+# Scheduler Debugging
+#
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHED_INFO=y
# CONFIG_SCHEDSTATS is not set
-CONFIG_SCHED_STACK_END_CHECK=y
+# end of Scheduler Debugging
+
# CONFIG_DEBUG_TIMEKEEPING is not set
#
@@ -5660,34 +6145,40 @@ CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_SCF_TORTURE_TEST is not set
+# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)
+# CONFIG_DEBUG_IRQFLAGS is not set
CONFIG_STACKTRACE=y
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+
+#
+# Debug kernel data structures
+#
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_PLIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
+# end of Debug kernel data structures
+
# CONFIG_DEBUG_CREDENTIALS is not set
#
# RCU Debugging
#
-# CONFIG_RCU_PERF_TEST is not set
+# CONFIG_RCU_SCALE_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_REF_SCALE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=21
CONFIG_RCU_TRACE=y
# CONFIG_RCU_EQS_DEBUG is not set
# end of RCU Debugging
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
-# CONFIG_NOTIFIER_ERROR_INJECTION is not set
-CONFIG_FUNCTION_ERROR_INJECTION=y
-# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
@@ -5700,21 +6191,22 @@ CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
CONFIG_EVENT_TRACING=y
CONFIG_CONTEXT_SWITCH_TRACER=y
-CONFIG_RING_BUFFER_ALLOW_SWAP=y
CONFIG_TRACING=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
+# CONFIG_BOOTTIME_TRACING is not set
# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_PREEMPTIRQ_EVENTS is not set
+# CONFIG_STACK_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
# CONFIG_HWLAT_TRACER is not set
+# CONFIG_OSNOISE_TRACER is not set
+# CONFIG_TIMERLAT_TRACER is not set
# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_FTRACE_SYSCALLS is not set
# CONFIG_TRACER_SNAPSHOT is not set
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_STACK_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
CONFIG_KPROBE_EVENTS=y
CONFIG_UPROBE_EVENTS=y
@@ -5722,16 +6214,56 @@ CONFIG_BPF_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
# CONFIG_BPF_KPROBE_OVERRIDE is not set
+# CONFIG_SYNTH_EVENTS is not set
# CONFIG_HIST_TRIGGERS is not set
+# CONFIG_TRACE_EVENT_INJECT is not set
# CONFIG_TRACEPOINT_BENCHMARK is not set
# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_TRACE_EVAL_MAP_FILE is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
-# CONFIG_TRACE_EVAL_MAP_FILE is not set
+# CONFIG_KPROBE_EVENT_GEN_TEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_IO_STRICT_DEVMEM=y
+
+#
+# powerpc Debugging
+#
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_HCALL_STATS is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+CONFIG_JUMP_LABEL_FEATURE_CHECKS=y
+# CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_PPC_IRQ_SOFT_MASK_DEBUG is not set
+# CONFIG_PPC_RFI_SRR_DEBUG is not set
+# CONFIG_XMON is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+# CONFIG_PPC_FAST_ENDIAN_SWITCH is not set
+# end of powerpc Debugging
+
+#
+# Kernel Testing and Coverage
+#
+# CONFIG_KUNIT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+CONFIG_FUNCTION_ERROR_INJECTION=y
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_ARCH_HAS_KCOV=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+# CONFIG_KCOV is not set
CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_LKDTM is not set
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_TEST_SORT is not set
+# CONFIG_TEST_MIN_HEAP is not set
+# CONFIG_TEST_DIV64 is not set
# CONFIG_KPROBES_SANITY_TEST is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_RBTREE_TEST is not set
@@ -5741,12 +6273,13 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_ASYNC_RAID6_TEST is not set
# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_SCANF is not set
# CONFIG_TEST_BITMAP is not set
-# CONFIG_TEST_BITFIELD is not set
# CONFIG_TEST_UUID is not set
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_OVERFLOW is not set
@@ -5754,6 +6287,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_BITOPS is not set
# CONFIG_TEST_VMALLOC is not set
# CONFIG_TEST_USER_COPY is not set
# CONFIG_TEST_BPF is not set
@@ -5767,31 +6301,8 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_MEMCAT_P is not set
# CONFIG_TEST_STACKINIT is not set
# CONFIG_TEST_MEMINIT is not set
+# CONFIG_TEST_FREE_PAGES is not set
+CONFIG_ARCH_USE_MEMTEST=y
# CONFIG_MEMTEST is not set
-# CONFIG_BUG_ON_DATA_CORRUPTION is not set
-# CONFIG_SAMPLES is not set
-CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
-CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
-# CONFIG_UBSAN is not set
-CONFIG_UBSAN_ALIGNMENT=y
-CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_IO_STRICT_DEVMEM=y
-# CONFIG_PPC_DISABLE_WERROR is not set
-CONFIG_PPC_WERROR=y
-CONFIG_PRINT_STACK_DEPTH=64
-# CONFIG_HCALL_STATS is not set
-# CONFIG_PPC_EMULATED_STATS is not set
-# CONFIG_CODE_PATCHING_SELFTEST is not set
-CONFIG_JUMP_LABEL_FEATURE_CHECKS=y
-# CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG is not set
-# CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
-# CONFIG_PPC_IRQ_SOFT_MASK_DEBUG is not set
-# CONFIG_XMON is not set
-# CONFIG_BOOTX_TEXT is not set
-# CONFIG_PPC_EARLY_DEBUG is not set
-# CONFIG_PPC_PTDUMP is not set
-# CONFIG_PPC_FAST_ENDIAN_SWITCH is not set
+# end of Kernel Testing and Coverage
# end of Kernel hacking
diff --git a/system/easy-kernel/config-x86_64 b/system/easy-kernel/config-x86_64
index 38e391c1c..391be0e27 100644
--- a/system/easy-kernel/config-x86_64
+++ b/system/easy-kernel/config-x86_64
@@ -1,19 +1,23 @@
#
# Automatically generated file; DO NOT EDIT.
-# Linux/x86 5.4.66-mc1 Kernel Configuration
-#
-
-#
-# Compiler: gcc (Adelie 8.3.0) 8.3.0
+# Linux/x86 5.15.11-mc1 Kernel Configuration
#
+CONFIG_CC_VERSION_TEXT="gcc (Adelie 8.3.0) 8.3.0"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=80300
CONFIG_CLANG_VERSION=0
+CONFIG_AS_IS_GNU=y
+CONFIG_AS_VERSION=23200
+CONFIG_LD_IS_BFD=y
+CONFIG_LD_VERSION=23200
+CONFIG_LLD_VERSION=0
CONFIG_CC_CAN_LINK=y
+CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO=y
CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
CONFIG_IRQ_WORK=y
-CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_BUILDTIME_TABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y
#
@@ -21,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
#
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
+# CONFIG_WERROR is not set
CONFIG_LOCALVERSION="-easy"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_BUILD_SALT=""
@@ -30,18 +35,22 @@ CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_ZSTD=y
# CONFIG_KERNEL_GZIP is not set
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_XZ is not set
CONFIG_KERNEL_LZO=y
# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="adelie"
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_WATCH_QUEUE is not set
CONFIG_CROSS_MEMORY_ATTACH=y
# CONFIG_USELIB is not set
# CONFIG_AUDIT is not set
@@ -55,10 +64,12 @@ CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_IRQ_MSI_IOMMU=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
CONFIG_IRQ_FORCED_THREADING=y
@@ -67,7 +78,6 @@ CONFIG_SPARSE_IRQ=y
# end of IRQ subsystem
CONFIG_CLOCKSOURCE_WATCHDOG=y
-CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_CLOCKSOURCE_INIT=y
CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
CONFIG_GENERIC_TIME_VSYSCALL=y
@@ -75,6 +85,8 @@ CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
#
# Timers subsystem
@@ -88,6 +100,21 @@ CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
# end of Timers subsystem
+CONFIG_BPF=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
+
+#
+# BPF subsystem
+#
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_JIT=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BPF_JIT_DEFAULT_ON=y
+# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
+# CONFIG_BPF_PRELOAD is not set
+# end of BPF subsystem
+
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
@@ -118,6 +145,8 @@ CONFIG_TREE_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
+CONFIG_TASKS_RCU_GENERIC=y
+CONFIG_TASKS_TRACE_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
# end of RCU Subsystem
@@ -125,35 +154,34 @@ CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_BUILD_BIN2C=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-# CONFIG_IKHEADERS is not set
-CONFIG_LOG_BUF_SHIFT=16
+CONFIG_IKHEADERS=m
+CONFIG_LOG_BUF_SHIFT=17
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+# CONFIG_PRINTK_INDEX is not set
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
#
# Scheduler features
#
-# CONFIG_UCLAMP_TASK is not set
+CONFIG_SCHED_ALT=y
+# CONFIG_SCHED_BMQ is not set
+CONFIG_SCHED_PDS=y
# end of Scheduler features
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+CONFIG_CC_HAS_INT128=y
CONFIG_ARCH_SUPPORTS_INT128=y
-CONFIG_NUMA_BALANCING=y
-CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
-CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_CFS_BANDWIDTH=y
-CONFIG_RT_GROUP_SCHED=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
@@ -164,16 +192,17 @@ CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
+# CONFIG_CGROUP_MISC is not set
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
+CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
-CONFIG_SCHED_AUTOGROUP=y
# CONFIG_SYSFS_DEPRECATED is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
@@ -184,26 +213,26 @@ CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
+CONFIG_RD_ZSTD=y
+CONFIG_BOOT_CONFIG=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_LD_ORPHAN_WARN=y
CONFIG_SYSCTL=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
-CONFIG_BPF=y
CONFIG_EXPERT=y
# CONFIG_UID16 is not set
CONFIG_MULTIUSER=y
# CONFIG_SGETMASK_SYSCALL is not set
# CONFIG_SYSFS_SYSCALL is not set
-# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
CONFIG_PRINTK=y
-CONFIG_PRINTK_NMI=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
-# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_PCSPKR_PLATFORM=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_FUTEX_PI=y
@@ -215,15 +244,16 @@ CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y
+CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
+CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
CONFIG_KALLSYMS_BASE_RELATIVE=y
-CONFIG_BPF_SYSCALL=y
-CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_USERFAULTFD=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
+CONFIG_KCMP=y
CONFIG_RSEQ=y
# CONFIG_DEBUG_RSEQ is not set
# CONFIG_EMBEDDED is not set
@@ -239,7 +269,6 @@ CONFIG_PERF_EVENTS=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_SLUB_DEBUG is not set
-# CONFIG_SLUB_MEMCG_SYSFS_ON is not set
# CONFIG_COMPAT_BRK is not set
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -247,7 +276,7 @@ CONFIG_SLUB=y
CONFIG_SLAB_MERGE_DEFAULT=y
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
-# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
+CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
CONFIG_SLUB_CPU_PARTIAL=y
CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_PROFILING=y
@@ -258,7 +287,6 @@ CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
-CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
@@ -272,36 +300,35 @@ CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
-CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_FILTER_PGPROT=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_NR_GPIO=1024
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
-CONFIG_ZONE_DMA32=y
CONFIG_AUDIT_ARCH=y
-CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_HAVE_INTEL_TXT=y
CONFIG_X86_64_SMP=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_PGTABLE_LEVELS=4
+CONFIG_CC_HAS_SANE_STACKPROTECTOR=y
#
# Processor type and features
#
-CONFIG_ZONE_DMA=y
CONFIG_SMP=y
CONFIG_X86_FEATURE_NAMES=y
-# CONFIG_X86_X2APIC is not set
+CONFIG_X86_X2APIC=y
CONFIG_X86_MPPARSE=y
# CONFIG_GOLDFISH is not set
CONFIG_RETPOLINE=y
# CONFIG_X86_CPU_RESCTRL is not set
CONFIG_X86_EXTENDED_PLATFORM=y
# CONFIG_X86_VSMP is not set
+# CONFIG_X86_UV is not set
# CONFIG_X86_GOLDFISH is not set
# CONFIG_X86_INTEL_MID is not set
CONFIG_X86_INTEL_LPSS=y
@@ -318,18 +345,19 @@ CONFIG_PARAVIRT_XXL=y
CONFIG_X86_HV_CALLBACK_VECTOR=y
CONFIG_XEN=y
CONFIG_XEN_PV=y
+CONFIG_XEN_512GB=y
CONFIG_XEN_PV_SMP=y
-CONFIG_XEN_DOM0=y
+CONFIG_XEN_PV_DOM0=y
CONFIG_XEN_PVHVM=y
CONFIG_XEN_PVHVM_SMP=y
-CONFIG_XEN_512GB=y
+CONFIG_XEN_PVHVM_GUEST=y
CONFIG_XEN_SAVE_RESTORE=y
# CONFIG_XEN_DEBUG_FS is not set
CONFIG_XEN_PVH=y
+CONFIG_XEN_DOM0=y
CONFIG_KVM_GUEST=y
CONFIG_ARCH_CPUIDLE_HALTPOLL=y
CONFIG_PVH=y
-# CONFIG_KVM_DEBUG_FS is not set
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
CONFIG_PARAVIRT_CLOCK=y
# CONFIG_JAILHOUSE_GUEST is not set
@@ -345,12 +373,15 @@ CONFIG_PARAVIRT_CLOCK=y
# CONFIG_MSTEAMROLLER is not set
# CONFIG_MEXCAVATOR is not set
# CONFIG_MZEN is not set
+# CONFIG_MZEN2 is not set
# CONFIG_MPSC is not set
-# CONFIG_MATOM is not set
# CONFIG_MCORE2 is not set
+# CONFIG_MATOM is not set
# CONFIG_MNEHALEM is not set
# CONFIG_MWESTMERE is not set
# CONFIG_MSILVERMONT is not set
+# CONFIG_MGOLDMONT is not set
+# CONFIG_MGOLDMONTPLUS is not set
# CONFIG_MSANDYBRIDGE is not set
# CONFIG_MIVYBRIDGE is not set
# CONFIG_MHASWELL is not set
@@ -359,8 +390,10 @@ CONFIG_PARAVIRT_CLOCK=y
# CONFIG_MSKYLAKEX is not set
# CONFIG_MCANNONLAKE is not set
# CONFIG_MICELAKE is not set
+# CONFIG_MCASCADELAKE is not set
CONFIG_GENERIC_CPU=y
-# CONFIG_MNATIVE is not set
+# CONFIG_MNATIVE_INTEL is not set
+# CONFIG_MNATIVE_AMD is not set
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_TSC=y
@@ -368,6 +401,8 @@ CONFIG_X86_CMPXCHG64=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_IA32_FEAT_CTL=y
+CONFIG_X86_VMX_FEATURE_NAMES=y
CONFIG_PROCESSOR_SELECT=y
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
@@ -377,9 +412,7 @@ CONFIG_CPU_SUP_ZHAOXIN=y
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
CONFIG_DMI=y
-# CONFIG_GART_IOMMU is not set
-CONFIG_CALGARY_IOMMU=y
-CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
+CONFIG_GART_IOMMU=y
# CONFIG_MAXSMP is not set
CONFIG_NR_CPUS_RANGE_BEGIN=2
CONFIG_NR_CPUS_RANGE_END=512
@@ -397,7 +430,6 @@ CONFIG_X86_MCE_INTEL=y
CONFIG_X86_MCE_AMD=y
CONFIG_X86_MCE_THRESHOLD=y
# CONFIG_X86_MCE_INJECT is not set
-CONFIG_X86_THERMAL_VECTOR=y
#
# Performance monitoring
@@ -405,12 +437,14 @@ CONFIG_X86_THERMAL_VECTOR=y
CONFIG_PERF_EVENTS_INTEL_UNCORE=y
CONFIG_PERF_EVENTS_INTEL_RAPL=y
CONFIG_PERF_EVENTS_INTEL_CSTATE=y
-# CONFIG_PERF_EVENTS_AMD_POWER is not set
+CONFIG_PERF_EVENTS_AMD_POWER=y
+CONFIG_PERF_EVENTS_AMD_UNCORE=y
# end of Performance monitoring
CONFIG_X86_16BIT=y
CONFIG_X86_ESPFIX64=y
CONFIG_X86_VSYSCALL_EMULATION=y
+CONFIG_X86_IOPL_IOPERM=y
CONFIG_I8K=m
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=y
@@ -425,7 +459,6 @@ CONFIG_X86_DIRECT_GBPAGES=y
CONFIG_NUMA=y
CONFIG_AMD_NUMA=y
CONFIG_X86_64_ACPI_NUMA=y
-CONFIG_NODES_SPAN_OTHER_NODES=y
# CONFIG_NUMA_EMU is not set
CONFIG_NODES_SHIFT=2
CONFIG_ARCH_SPARSEMEM_ENABLE=y
@@ -436,7 +469,6 @@ CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
# CONFIG_X86_PMEM_LEGACY is not set
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
-CONFIG_X86_RESERVE_LOW=64
CONFIG_MTRR=y
CONFIG_MTRR_SANITIZER=y
CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0
@@ -445,16 +477,15 @@ CONFIG_X86_PAT=y
CONFIG_ARCH_USES_PG_UNCACHED=y
CONFIG_ARCH_RANDOM=y
CONFIG_X86_SMAP=y
-CONFIG_X86_INTEL_UMIP=y
-# CONFIG_X86_INTEL_MPX is not set
+CONFIG_X86_UMIP=y
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
CONFIG_X86_INTEL_TSX_MODE_OFF=y
# CONFIG_X86_INTEL_TSX_MODE_ON is not set
# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
+# CONFIG_X86_SGX is not set
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_EFI_MIXED=y
-CONFIG_SECCOMP=y
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
@@ -488,12 +519,8 @@ CONFIG_HAVE_LIVEPATCH=y
# end of Processor type and features
CONFIG_ARCH_HAS_ADD_PAGES=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
-CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
-CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
-CONFIG_ARCH_ENABLE_THP_MIGRATION=y
#
# Power management and ACPI options
@@ -504,6 +531,7 @@ CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
+CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_PM_STD_PARTITION=""
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
@@ -529,28 +557,28 @@ CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y
+CONFIG_ACPI_FPDT=y
CONFIG_ACPI_LPIT=y
CONFIG_ACPI_SLEEP=y
-# CONFIG_ACPI_PROCFS_POWER is not set
CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
# CONFIG_ACPI_EC_DEBUGFS is not set
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_VIDEO=m
+CONFIG_ACPI_VIDEO=y
CONFIG_ACPI_FAN=y
-# CONFIG_ACPI_TAD is not set
+CONFIG_ACPI_TAD=m
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_CPU_FREQ_PSS=y
CONFIG_ACPI_PROCESSOR_CSTATE=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_CPPC_LIB=y
CONFIG_ACPI_PROCESSOR=y
-# CONFIG_ACPI_IPMI is not set
+CONFIG_ACPI_IPMI=m
CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
CONFIG_ACPI_THERMAL=y
-CONFIG_ACPI_NUMA=y
+CONFIG_ACPI_PLATFORM_PROFILE=m
CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
CONFIG_ACPI_TABLE_UPGRADE=y
# CONFIG_ACPI_DEBUG is not set
@@ -565,6 +593,7 @@ CONFIG_ACPI_BGRT=y
# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
CONFIG_ACPI_NFIT=m
# CONFIG_NFIT_SECURITY_DEBUG is not set
+CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_HMAT is not set
CONFIG_HAVE_ACPI_APEI=y
CONFIG_HAVE_ACPI_APEI_NMI=y
@@ -574,12 +603,14 @@ CONFIG_ACPI_APEI_GHES=y
# CONFIG_ACPI_APEI_MEMORY_FAILURE is not set
# CONFIG_ACPI_APEI_EINJ is not set
# CONFIG_ACPI_APEI_ERST_DEBUG is not set
+CONFIG_ACPI_DPTF=y
CONFIG_DPTF_POWER=m
+CONFIG_DPTF_PCH_FIVR=m
# CONFIG_ACPI_EXTLOG is not set
-# CONFIG_PMIC_OPREGION is not set
CONFIG_ACPI_CONFIGFS=m
+# CONFIG_PMIC_OPREGION is not set
CONFIG_X86_PM_TIMER=y
-# CONFIG_SFI is not set
+CONFIG_ACPI_PRMT=y
#
# CPU Frequency scaling
@@ -591,9 +622,7 @@ CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -641,10 +670,9 @@ CONFIG_PCI_DIRECT=y
# CONFIG_PCI_MMCONFIG is not set
CONFIG_PCI_XEN=y
# CONFIG_PCI_CNB20LE_QUIRK is not set
-# CONFIG_ISA_BUS is not set
+CONFIG_ISA_BUS=y
CONFIG_ISA_DMA_API=y
CONFIG_AMD_NB=y
-# CONFIG_X86_SYSFB is not set
# end of Bus options (PCI etc.)
#
@@ -658,47 +686,6 @@ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
CONFIG_SYSVIPC_COMPAT=y
# end of Binary Emulations
-CONFIG_X86_DEV_DMA_OPS=y
-
-#
-# Firmware Drivers
-#
-# CONFIG_EDD is not set
-CONFIG_FIRMWARE_MEMMAP=y
-CONFIG_DMIID=y
-CONFIG_DMI_SYSFS=y
-CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
-# CONFIG_ISCSI_IBFT is not set
-CONFIG_FW_CFG_SYSFS=m
-CONFIG_FW_CFG_SYSFS_CMDLINE=y
-# CONFIG_GOOGLE_FIRMWARE is not set
-
-#
-# EFI (Extensible Firmware Interface) Support
-#
-# CONFIG_EFI_VARS is not set
-CONFIG_EFI_ESRT=y
-CONFIG_EFI_RUNTIME_MAP=y
-# CONFIG_EFI_FAKE_MEMMAP is not set
-CONFIG_EFI_RUNTIME_WRAPPERS=y
-# CONFIG_EFI_CAPSULE_LOADER is not set
-# CONFIG_EFI_TEST is not set
-CONFIG_APPLE_PROPERTIES=y
-# CONFIG_RESET_ATTACK_MITIGATION is not set
-# CONFIG_EFI_RCI2_TABLE is not set
-# end of EFI (Extensible Firmware Interface) Support
-
-CONFIG_UEFI_CPER=y
-CONFIG_UEFI_CPER_X86=y
-CONFIG_EFI_DEV_PATH_PARSER=y
-CONFIG_EFI_EARLYCON=y
-
-#
-# Tegra firmware driver
-#
-# end of Tegra firmware driver
-# end of Firmware Drivers
-
CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y
@@ -713,13 +700,18 @@ CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_KVM_COMPAT=y
CONFIG_HAVE_KVM_IRQ_BYPASS=y
CONFIG_HAVE_KVM_NO_POLL=y
+CONFIG_KVM_XFER_TO_GUEST_WORK=y
+CONFIG_HAVE_KVM_PM_NOTIFIER=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
+# CONFIG_KVM_WERROR is not set
CONFIG_KVM_INTEL=m
CONFIG_KVM_AMD=m
-CONFIG_VHOST_NET=m
-CONFIG_VHOST=m
-# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+# CONFIG_KVM_XEN is not set
+CONFIG_AS_AVX512=y
+CONFIG_AS_SHA1_NI=y
+CONFIG_AS_SHA256_NI=y
+CONFIG_AS_TPAUSE=y
#
# General architecture-dependent options
@@ -727,13 +719,11 @@ CONFIG_VHOST=m
CONFIG_CRASH_CORE=y
CONFIG_KEXEC_CORE=y
CONFIG_HOTPLUG_SMT=y
-CONFIG_OPROFILE=m
-# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
-CONFIG_HAVE_OPROFILE=y
-CONFIG_OPROFILE_NMI_TIMER=y
+CONFIG_GENERIC_ENTRY=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_STATIC_KEYS_SELFTEST is not set
+# CONFIG_STATIC_CALL_SELFTEST is not set
CONFIG_OPTPROBES=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
@@ -746,6 +736,7 @@ CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
@@ -754,11 +745,11 @@ CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
+CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
-CONFIG_HAVE_CLK=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
@@ -768,21 +759,32 @@ CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
-CONFIG_HAVE_RCU_TABLE_FREE=y
+CONFIG_MMU_GATHER_TABLE_FREE=y
+CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
+CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
+# CONFIG_SECCOMP_CACHE_DEBUG is not set
CONFIG_HAVE_ARCH_STACKLEAK=y
-CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
+CONFIG_HAVE_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
+CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
+CONFIG_LTO_NONE=y
CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOVE_PUD=y
CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
@@ -792,6 +794,7 @@ CONFIG_HAVE_ARCH_SOFT_DIRTY=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_HAVE_EXIT_THREAD=y
@@ -799,7 +802,6 @@ CONFIG_ARCH_MMAP_RND_BITS=28
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
-CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_STACK_VALIDATION=y
CONFIG_HAVE_RELIABLE_STACKTRACE=y
CONFIG_OLD_SIGSUSPEND3=y
@@ -807,16 +809,23 @@ CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_HAVE_ARCH_VMAP_STACK=y
CONFIG_VMAP_STACK=y
+CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
+# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
CONFIG_STRICT_MODULE_RWX=y
-CONFIG_ARCH_HAS_REFCOUNT=y
-CONFIG_REFCOUNT_FULL=y
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
CONFIG_ARCH_USE_MEMREMAP_PROT=y
# CONFIG_LOCK_EVENT_COUNTS is not set
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
+CONFIG_HAVE_STATIC_CALL=y
+CONFIG_HAVE_STATIC_CALL_INLINE=y
+CONFIG_HAVE_PREEMPT_DYNAMIC=y
+CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
+CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
#
# GCOV-based kernel profiling
@@ -825,8 +834,11 @@ CONFIG_ARCH_HAS_MEM_ENCRYPT=y
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling
-CONFIG_PLUGIN_HOSTCC=""
CONFIG_HAVE_GCC_PLUGINS=y
+CONFIG_GCC_PLUGINS=y
+# CONFIG_GCC_PLUGIN_CYC_COMPLEXITY is not set
+# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set
+# CONFIG_GCC_PLUGIN_RANDSTRUCT is not set
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@@ -848,29 +860,33 @@ CONFIG_MODULE_SIG_ALL=y
# CONFIG_MODULE_SIG_SHA384 is not set
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH="sha512"
-CONFIG_MODULE_COMPRESS=y
+# CONFIG_MODULE_COMPRESS_NONE is not set
# CONFIG_MODULE_COMPRESS_GZIP is not set
CONFIG_MODULE_COMPRESS_XZ=y
+# CONFIG_MODULE_COMPRESS_ZSTD is not set
# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
-# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_MODPROBE_PATH="/sbin/modprobe"
# CONFIG_TRIM_UNUSED_KSYMS is not set
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_BLOCK=y
CONFIG_BLK_RQ_ALLOC_TIME=y
-CONFIG_BLK_SCSI_REQUEST=y
-CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_CGROUP_RWSTAT=y
+CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BLK_DEV_INTEGRITY_T10=y
# CONFIG_BLK_DEV_ZONED is not set
CONFIG_BLK_DEV_THROTTLING=y
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
-# CONFIG_BLK_CMDLINE_PARSER is not set
CONFIG_BLK_WBT=y
+CONFIG_BLK_WBT_MQ=y
# CONFIG_BLK_CGROUP_IOLATENCY is not set
+# CONFIG_BLK_CGROUP_FC_APPID is not set
CONFIG_BLK_CGROUP_IOCOST=y
-CONFIG_BLK_WBT_MQ=y
+# CONFIG_BLK_CGROUP_IOPRIO is not set
CONFIG_BLK_DEBUG_FS=y
CONFIG_BLK_SED_OPAL=y
+# CONFIG_BLK_INLINE_ENCRYPTION is not set
#
# Partition Types
@@ -878,7 +894,7 @@ CONFIG_BLK_SED_OPAL=y
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_AIX_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
+CONFIG_OSF_PARTITION=y
CONFIG_AMIGA_PARTITION=y
# CONFIG_ATARI_PARTITION is not set
CONFIG_MAC_PARTITION=y
@@ -902,6 +918,7 @@ CONFIG_BLOCK_COMPAT=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_BLK_PM=y
+CONFIG_BLOCK_HOLDER_DEPRECATED=y
#
# IO Schedulers
@@ -914,6 +931,7 @@ CONFIG_BFQ_CGROUP_DEBUG=y
# end of IO Schedulers
CONFIG_PREEMPT_NOTIFIERS=y
+CONFIG_PADATA=y
CONFIG_ASN1=y
CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
CONFIG_INLINE_READ_UNLOCK=y
@@ -928,6 +946,7 @@ CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_QUEUED_RWLOCKS=y
+CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
CONFIG_FREEZER=y
@@ -950,27 +969,31 @@ CONFIG_COREDUMP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_HAVE_MEMORY_PRESENT=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
-CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_FAST_GUP=y
+CONFIG_NUMA_KEEP_MEMINFO=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_SPARSE=y
# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_MHP_MEMMAP_ON_MEMORY=y
CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_COMPACTION=y
+CONFIG_PAGE_REPORTING=y
CONFIG_MIGRATION=y
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
+CONFIG_ARCH_ENABLE_THP_MIGRATION=y
CONFIG_CONTIG_ALLOC=y
CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_MMU_NOTIFIER=y
CONFIG_KSM=y
@@ -985,14 +1008,26 @@ CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
CONFIG_ARCH_WANTS_THP_SWAP=y
CONFIG_THP_SWAP=y
-CONFIG_TRANSPARENT_HUGE_PAGECACHE=y
# CONFIG_CLEANCACHE is not set
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
# CONFIG_CMA_DEBUG is not set
CONFIG_CMA_DEBUGFS=y
+# CONFIG_CMA_SYSFS is not set
CONFIG_CMA_AREAS=7
CONFIG_ZSWAP=y
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set
+# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT="lzo"
+CONFIG_ZSWAP_ZPOOL_DEFAULT_ZBUD=y
+# CONFIG_ZSWAP_ZPOOL_DEFAULT_Z3FOLD is not set
+# CONFIG_ZSWAP_ZPOOL_DEFAULT_ZSMALLOC is not set
+CONFIG_ZSWAP_ZPOOL_DEFAULT="zbud"
+# CONFIG_ZSWAP_DEFAULT_ON is not set
CONFIG_ZPOOL=y
CONFIG_ZBUD=y
CONFIG_Z3FOLD=m
@@ -1000,16 +1035,28 @@ CONFIG_Z3FOLD=m
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
# CONFIG_IDLE_PAGE_TRACKING is not set
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_PTE_DEVMAP=y
+CONFIG_ARCH_HAS_ZONE_DMA_SET=y
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA32=y
# CONFIG_ZONE_DEVICE is not set
CONFIG_HMM_MIRROR=y
-CONFIG_FRAME_VECTOR=y
+CONFIG_VMAP_PFN=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
# CONFIG_PERCPU_STATS is not set
-# CONFIG_GUP_BENCHMARK is not set
+# CONFIG_GUP_TEST is not set
# CONFIG_READ_ONLY_THP_FOR_FS is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
+CONFIG_MAPPING_DIRTY_HELPERS=y
+CONFIG_SECRETMEM=y
+
+#
+# Data Access Monitoring
+#
+# CONFIG_DAMON is not set
+# end of Data Access Monitoring
# end of Memory Management options
CONFIG_NET=y
@@ -1025,16 +1072,20 @@ CONFIG_PACKET=y
CONFIG_PACKET_DIAG=m
CONFIG_UNIX=y
CONFIG_UNIX_SCM=y
+CONFIG_AF_UNIX_OOB=y
CONFIG_UNIX_DIAG=m
# CONFIG_TLS is not set
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_XFRM_ALGO=m
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_USER_COMPAT is not set
# CONFIG_XFRM_INTERFACE is not set
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_AH=m
+CONFIG_XFRM_ESP=m
CONFIG_XFRM_IPCOMP=m
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
@@ -1050,7 +1101,7 @@ CONFIG_IP_ROUTE_CLASSID=y
# CONFIG_IP_PNP is not set
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE_DEMUX=m
-CONFIG_NET_IP_TUNNEL=m
+CONFIG_NET_IP_TUNNEL=y
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE_COMMON=y
@@ -1060,12 +1111,13 @@ CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
-CONFIG_NET_UDP_TUNNEL=m
+CONFIG_NET_UDP_TUNNEL=y
CONFIG_NET_FOU=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_ESP_OFFLOAD=m
+# CONFIG_INET_ESPINTCP is not set
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
@@ -1102,6 +1154,7 @@ CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_ESP_OFFLOAD=m
+# CONFIG_INET6_ESPINTCP is not set
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_MIP6=m
# CONFIG_IPV6_ILA is not set
@@ -1122,7 +1175,10 @@ CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
+# CONFIG_IPV6_RPL_LWTUNNEL is not set
+# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
# CONFIG_NETLABEL is not set
+# CONFIG_MPTCP is not set
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NET_PTP_CLASSIFY=y
# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
@@ -1137,13 +1193,13 @@ CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_FAMILY_BRIDGE=y
CONFIG_NETFILTER_FAMILY_ARP=y
+# CONFIG_NETFILTER_NETLINK_HOOK is not set
CONFIG_NETFILTER_NETLINK_ACCT=m
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_NETLINK_OSF=m
CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_COMMON=m
-CONFIG_NF_LOG_NETDEV=m
+CONFIG_NF_LOG_SYSLOG=m
CONFIG_NETFILTER_CONNCOUNT=m
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_ZONES=y
@@ -1181,7 +1237,6 @@ CONFIG_NF_NAT_REDIRECT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NETFILTER_SYNPROXY=m
CONFIG_NF_TABLES=m
-CONFIG_NF_TABLES_SET=m
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=m
@@ -1213,9 +1268,11 @@ CONFIG_NF_DUP_NETDEV=m
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
# CONFIG_NFT_FIB_NETDEV is not set
+# CONFIG_NFT_REJECT_NETDEV is not set
CONFIG_NF_FLOW_TABLE_INET=m
CONFIG_NF_FLOW_TABLE=m
CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XTABLES_COMPAT=y
#
# Xtables combined modules
@@ -1404,7 +1461,6 @@ CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
-CONFIG_NF_LOG_BRIDGE=m
CONFIG_NF_CONNTRACK_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
@@ -1451,7 +1507,8 @@ CONFIG_MRP=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_BRIDGE_VLAN_FILTERING=y
-CONFIG_HAVE_NET_DSA=y
+# CONFIG_BRIDGE_MRP is not set
+# CONFIG_BRIDGE_CFM is not set
# CONFIG_NET_DSA is not set
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
@@ -1459,7 +1516,10 @@ CONFIG_VLAN_8021Q_MVRP=y
# CONFIG_DECNET is not set
CONFIG_LLC=m
# CONFIG_LLC2 is not set
-# CONFIG_ATALK is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+# CONFIG_LTPC is not set
+# CONFIG_IPDDP is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_PHONET is not set
@@ -1497,8 +1557,10 @@ CONFIG_NET_SCH_CAKE=m
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_HHF=m
CONFIG_NET_SCH_PIE=m
+# CONFIG_NET_SCH_FQ_PIE is not set
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_SCH_PLUG=m
+# CONFIG_NET_SCH_ETS is not set
CONFIG_NET_SCH_DEFAULT=y
# CONFIG_DEFAULT_FQ is not set
# CONFIG_DEFAULT_CODEL is not set
@@ -1547,6 +1609,7 @@ CONFIG_NET_ACT_SKBMOD=m
# CONFIG_NET_ACT_IFE is not set
CONFIG_NET_ACT_TUNNEL_KEY=m
CONFIG_NET_ACT_CT=m
+# CONFIG_NET_ACT_GATE is not set
# CONFIG_NET_TC_SKB_EXT is not set
CONFIG_NET_SCH_FIFO=y
# CONFIG_DCB is not set
@@ -1565,15 +1628,17 @@ CONFIG_NET_NSH=m
# CONFIG_HSR is not set
# CONFIG_NET_SWITCHDEV is not set
CONFIG_NET_L3_MASTER_DEV=y
+# CONFIG_QRTR is not set
# CONFIG_NET_NCSI is not set
+CONFIG_PCPU_DEV_REFCNT=y
CONFIG_RPS=y
CONFIG_RFS_ACCEL=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_XPS=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_NET_RX_BUSY_POLL=y
CONFIG_BQL=y
-CONFIG_BPF_JIT=y
# CONFIG_BPF_STREAM_PARSER is not set
CONFIG_NET_FLOW_LIMIT=y
@@ -1597,8 +1662,11 @@ CONFIG_BT_HIDP=m
CONFIG_BT_HS=y
CONFIG_BT_LE=y
CONFIG_BT_LEDS=y
-# CONFIG_BT_SELFTEST is not set
+# CONFIG_BT_MSFTEXT is not set
+CONFIG_BT_AOSPEXT=y
# CONFIG_BT_DEBUGFS is not set
+# CONFIG_BT_SELFTEST is not set
+# CONFIG_BT_FEATURE_DEBUG is not set
#
# Bluetooth device drivers
@@ -1612,7 +1680,7 @@ CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y
CONFIG_BT_HCIBTUSB_BCM=y
CONFIG_BT_HCIBTUSB_MTK=y
CONFIG_BT_HCIBTUSB_RTL=y
-# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIBTSDIO=m
CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_SERDEV=y
CONFIG_BT_HCIUART_H4=y
@@ -1634,15 +1702,17 @@ CONFIG_BT_HCIBT3C=m
CONFIG_BT_HCIBLUECARD=m
# CONFIG_BT_HCIVHCI is not set
CONFIG_BT_MRVL=m
-# CONFIG_BT_MRVL_SDIO is not set
+CONFIG_BT_MRVL_SDIO=m
CONFIG_BT_ATH3K=m
-# CONFIG_BT_MTKSDIO is not set
+CONFIG_BT_MTKSDIO=m
CONFIG_BT_MTKUART=m
CONFIG_BT_HCIRSI=m
+# CONFIG_BT_VIRTIO is not set
# end of Bluetooth device drivers
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
+# CONFIG_MCTP is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_WIRELESS_EXT=y
@@ -1658,7 +1728,7 @@ CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_CFG80211_DEFAULT_PS=y
# CONFIG_CFG80211_DEBUGFS is not set
-# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_CFG80211_CRDA_SUPPORT=y
CONFIG_CFG80211_WEXT=y
CONFIG_CFG80211_WEXT_EXPORT=y
CONFIG_LIB80211=m
@@ -1677,7 +1747,6 @@ CONFIG_MAC80211_LEDS=y
# CONFIG_MAC80211_MESSAGE_TRACING is not set
# CONFIG_MAC80211_DEBUG_MENU is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
-# CONFIG_WIMAX is not set
CONFIG_RFKILL=m
CONFIG_RFKILL_LEDS=y
CONFIG_RFKILL_INPUT=y
@@ -1695,16 +1764,22 @@ CONFIG_LWTUNNEL=y
# CONFIG_LWTUNNEL_BPF is not set
CONFIG_DST_CACHE=y
CONFIG_GRO_CELLS=y
+CONFIG_NET_SELFTESTS=m
+CONFIG_NET_SOCK_MSG=y
CONFIG_NET_DEVLINK=y
CONFIG_PAGE_POOL=y
CONFIG_FAILOVER=m
-CONFIG_HAVE_EBPF_JIT=y
+CONFIG_ETHTOOL_NETLINK=y
#
# Device Drivers
#
CONFIG_HAVE_EISA=y
-# CONFIG_EISA is not set
+CONFIG_EISA=y
+# CONFIG_EISA_VLB_PRIMING is not set
+CONFIG_EISA_PCI_EISA=y
+CONFIG_EISA_VIRTUAL_ROOT=y
+CONFIG_EISA_NAMES=y
CONFIG_HAVE_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
@@ -1714,7 +1789,6 @@ CONFIG_PCIEAER=y
# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIE_ECRC is not set
CONFIG_PCIEASPM=y
-CONFIG_PCIEASPM_DEBUG=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
@@ -1722,7 +1796,6 @@ CONFIG_PCIEASPM_DEFAULT=y
CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set
-# CONFIG_PCIE_BW is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
@@ -1732,12 +1805,18 @@ CONFIG_PCI_STUB=m
CONFIG_PCI_PF_STUB=m
CONFIG_XEN_PCIDEV_FRONTEND=m
CONFIG_PCI_ATS=y
+CONFIG_PCI_ECAM=y
CONFIG_PCI_LOCKLESS_CONFIG=y
CONFIG_PCI_IOV=y
CONFIG_PCI_PRI=y
CONFIG_PCI_PASID=y
CONFIG_PCI_LABEL=y
# CONFIG_PCI_HYPERV is not set
+# CONFIG_PCIE_BUS_TUNE_OFF is not set
+CONFIG_PCIE_BUS_DEFAULT=y
+# CONFIG_PCIE_BUS_SAFE is not set
+# CONFIG_PCIE_BUS_PERFORMANCE is not set
+# CONFIG_PCIE_BUS_PEER2PEER is not set
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_HOTPLUG_PCI_ACPI_IBM=m
@@ -1747,25 +1826,33 @@ CONFIG_HOTPLUG_PCI_SHPC=y
#
# PCI controller drivers
#
-
-#
-# Cadence PCIe controllers support
-#
-# CONFIG_PCIE_CADENCE_HOST is not set
-# end of Cadence PCIe controllers support
-
# CONFIG_PCI_FTPCI100 is not set
-# CONFIG_PCI_HOST_GENERIC is not set
+CONFIG_PCI_HOST_COMMON=m
+CONFIG_PCI_HOST_GENERIC=m
# CONFIG_PCIE_XILINX is not set
CONFIG_VMD=m
CONFIG_PCI_HYPERV_INTERFACE=m
+# CONFIG_PCIE_MICROCHIP_HOST is not set
#
# DesignWare PCI Core Support
#
# CONFIG_PCIE_DW_PLAT_HOST is not set
+# CONFIG_PCIE_INTEL_GW is not set
# CONFIG_PCI_MESON is not set
# end of DesignWare PCI Core Support
+
+#
+# Mobiveil PCIe Core Support
+#
+# end of Mobiveil PCIe Core Support
+
+#
+# Cadence PCIe controllers support
+#
+# CONFIG_PCIE_CADENCE_PLAT_HOST is not set
+# CONFIG_PCI_J721E_HOST is not set
+# end of Cadence PCIe controllers support
# end of PCI controller drivers
#
@@ -1780,6 +1867,7 @@ CONFIG_PCI_HYPERV_INTERFACE=m
# CONFIG_PCI_SW_SWITCHTEC is not set
# end of PCI switch controller drivers
+# CONFIG_CXL_BUS is not set
CONFIG_PCCARD=m
CONFIG_PCMCIA=m
CONFIG_PCMCIA_LOAD_CIS=y
@@ -1802,6 +1890,7 @@ CONFIG_PCCARD_NONSTATIC=y
#
# Generic Driver Options
#
+CONFIG_AUXILIARY_BUS=y
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -1816,6 +1905,7 @@ CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_EXTRA_FIRMWARE=""
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_FW_CACHE=y
# end of Firmware loader
CONFIG_WANT_DEV_COREDUMP=y
@@ -1830,6 +1920,7 @@ CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=m
CONFIG_REGMAP_SPI=m
+CONFIG_REGMAP_SPMI=m
CONFIG_REGMAP_MMIO=y
CONFIG_DMA_SHARED_BUFFER=y
# CONFIG_DMA_FENCE_TRACE is not set
@@ -1839,11 +1930,69 @@ CONFIG_DMA_SHARED_BUFFER=y
# Bus devices
#
# CONFIG_MOXTET is not set
-# CONFIG_SIMPLE_PM_BUS is not set
+# CONFIG_MHI_BUS is not set
# end of Bus devices
CONFIG_CONNECTOR=m
-# CONFIG_GNSS is not set
+
+#
+# Firmware Drivers
+#
+
+#
+# ARM System Control and Management Interface Protocol
+#
+# end of ARM System Control and Management Interface Protocol
+
+# CONFIG_EDD is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_DMIID=y
+CONFIG_DMI_SYSFS=y
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
+# CONFIG_ISCSI_IBFT is not set
+CONFIG_FW_CFG_SYSFS=m
+CONFIG_FW_CFG_SYSFS_CMDLINE=y
+CONFIG_SYSFB=y
+CONFIG_SYSFB_SIMPLEFB=y
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# EFI (Extensible Firmware Interface) Support
+#
+# CONFIG_EFI_VARS is not set
+CONFIG_EFI_ESRT=y
+CONFIG_EFI_VARS_PSTORE=y
+# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set
+CONFIG_EFI_RUNTIME_MAP=y
+# CONFIG_EFI_FAKE_MEMMAP is not set
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
+# CONFIG_EFI_BOOTLOADER_CONTROL is not set
+# CONFIG_EFI_CAPSULE_LOADER is not set
+# CONFIG_EFI_TEST is not set
+CONFIG_APPLE_PROPERTIES=y
+# CONFIG_RESET_ATTACK_MITIGATION is not set
+# CONFIG_EFI_RCI2_TABLE is not set
+# CONFIG_EFI_DISABLE_PCI_DMA is not set
+# end of EFI (Extensible Firmware Interface) Support
+
+CONFIG_UEFI_CPER=y
+CONFIG_UEFI_CPER_X86=y
+CONFIG_EFI_DEV_PATH_PARSER=y
+CONFIG_EFI_EARLYCON=y
+CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
+
+#
+# Tegra firmware driver
+#
+# end of Tegra firmware driver
+# end of Firmware Drivers
+
+CONFIG_GNSS=m
+CONFIG_GNSS_SERIAL=m
+CONFIG_GNSS_MTK_SERIAL=m
+CONFIG_GNSS_SIRF_SERIAL=m
+CONFIG_GNSS_UBX_SERIAL=m
CONFIG_MTD=m
# CONFIG_MTD_TESTS is not set
@@ -1862,6 +2011,10 @@ CONFIG_MTD_OF_PARTS=m
CONFIG_MTD_BLKDEVS=m
CONFIG_MTD_BLOCK=m
# CONFIG_MTD_BLOCK_RO is not set
+
+#
+# Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK.
+#
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
@@ -1918,6 +2071,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_DATAFLASH is not set
# CONFIG_MTD_MCHP23K256 is not set
+# CONFIG_MTD_MCHP48L640 is not set
# CONFIG_MTD_SST25L is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
@@ -1930,11 +2084,22 @@ CONFIG_MTD_BLOCK2MTD=m
# CONFIG_MTD_DOCG3 is not set
# end of Self-contained MTD device drivers
+#
+# NAND
+#
# CONFIG_MTD_ONENAND is not set
# CONFIG_MTD_RAW_NAND is not set
# CONFIG_MTD_SPI_NAND is not set
#
+# ECC engine support
+#
+# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set
+# CONFIG_MTD_NAND_ECC_SW_BCH is not set
+# end of ECC engine support
+# end of NAND
+
+#
# LPDDR & LPDDR2 PCM memory drivers
#
# CONFIG_MTD_LPDDR is not set
@@ -1942,7 +2107,9 @@ CONFIG_MTD_BLOCK2MTD=m
CONFIG_MTD_SPI_NOR=m
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
-# CONFIG_SPI_MTK_QUADSPI is not set
+# CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set
+CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y
+# CONFIG_MTD_SPI_NOR_SWP_KEEP is not set
# CONFIG_SPI_INTEL_SPI_PCI is not set
# CONFIG_SPI_INTEL_SPI_PLATFORM is not set
CONFIG_MTD_UBI=m
@@ -1952,18 +2119,21 @@ CONFIG_MTD_UBI_BEB_LIMIT=20
# CONFIG_MTD_UBI_GLUEBI is not set
CONFIG_MTD_UBI_BLOCK=y
# CONFIG_MTD_HYPERBUS is not set
+CONFIG_DTC=y
CONFIG_OF=y
# CONFIG_OF_UNITTEST is not set
+CONFIG_OF_FLATTREE=y
CONFIG_OF_KOBJ=y
+CONFIG_OF_DYNAMIC=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_IRQ=y
CONFIG_OF_NET=y
-CONFIG_OF_MDIO=m
-# CONFIG_OF_OVERLAY is not set
+CONFIG_OF_RESOLVE=y
+CONFIG_OF_OVERLAY=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
-# CONFIG_PARPORT_SERIAL is not set
+CONFIG_PARPORT_SERIAL=m
CONFIG_PARPORT_PC_FIFO=y
CONFIG_PARPORT_PC_SUPERIO=y
CONFIG_PARPORT_PC_PCMCIA=m
@@ -2011,13 +2181,11 @@ CONFIG_PARIDE_KTTI=m
CONFIG_PARIDE_ON20=m
CONFIG_PARIDE_ON26=m
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=y
-CONFIG_BLK_DEV_UMEM=m
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_DRBD is not set
CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_SKD=y
CONFIG_BLK_DEV_SX8=y
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
@@ -2027,7 +2195,6 @@ CONFIG_ATA_OVER_ETH=m
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_BLKDEV_BACKEND=m
CONFIG_VIRTIO_BLK=y
-# CONFIG_VIRTIO_BLK_SCSI is not set
# CONFIG_BLK_DEV_RBD is not set
CONFIG_BLK_DEV_RSXX=m
@@ -2037,10 +2204,12 @@ CONFIG_BLK_DEV_RSXX=m
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
# CONFIG_NVME_MULTIPATH is not set
+# CONFIG_NVME_HWMON is not set
CONFIG_NVME_FABRICS=y
CONFIG_NVME_FC=y
# CONFIG_NVME_TCP is not set
CONFIG_NVME_TARGET=m
+# CONFIG_NVME_TARGET_PASSTHRU is not set
# CONFIG_NVME_TARGET_LOOP is not set
# CONFIG_NVME_TARGET_FC is not set
# CONFIG_NVME_TARGET_TCP is not set
@@ -2058,22 +2227,25 @@ CONFIG_TIFM_CORE=m
CONFIG_TIFM_7XX1=m
# CONFIG_ICS932S401 is not set
CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_HI6421V600_IRQ=m
CONFIG_HP_ILO=m
-# CONFIG_APDS9802ALS is not set
+CONFIG_APDS9802ALS=m
CONFIG_ISL29003=m
CONFIG_ISL29020=m
CONFIG_SENSORS_TSL2550=m
-# CONFIG_SENSORS_BH1770 is not set
-# CONFIG_SENSORS_APDS990X is not set
-# CONFIG_HMC6352 is not set
-# CONFIG_DS1682 is not set
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_HMC6352=m
+CONFIG_DS1682=m
CONFIG_VMWARE_BALLOON=m
-# CONFIG_LATTICE_ECP3_CONFIG is not set
+CONFIG_LATTICE_ECP3_CONFIG=m
# CONFIG_SRAM is not set
-# CONFIG_PCI_ENDPOINT_TEST is not set
-# CONFIG_XILINX_SDFEC is not set
-CONFIG_PVPANIC=m
-# CONFIG_C2PORT is not set
+CONFIG_DW_XDATA_PCIE=m
+CONFIG_PCI_ENDPOINT_TEST=m
+CONFIG_XILINX_SDFEC=m
+CONFIG_MISC_RTSX=m
+CONFIG_C2PORT=m
+CONFIG_C2PORT_DURAMAR_2150=m
#
# EEPROM support
@@ -2081,9 +2253,9 @@ CONFIG_PVPANIC=m
CONFIG_EEPROM_AT24=m
CONFIG_EEPROM_AT25=m
CONFIG_EEPROM_LEGACY=m
-# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_MAX6875=m
CONFIG_EEPROM_93CX6=m
-# CONFIG_EEPROM_93XX46 is not set
+CONFIG_EEPROM_93XX46=m
CONFIG_EEPROM_IDT_89HPESX=m
CONFIG_EEPROM_EE1004=m
# end of EEPROM support
@@ -2098,80 +2270,35 @@ CONFIG_CB710_DEBUG_ASSUMPTIONS=y
# CONFIG_TI_ST is not set
# end of Texas Instruments shared transport line discipline
-# CONFIG_SENSORS_LIS3_I2C is not set
+CONFIG_SENSORS_LIS3_I2C=m
#
# Altera FPGA firmware download module (requires I2C)
#
-# CONFIG_ALTERA_STAPL is not set
+CONFIG_ALTERA_STAPL=m
CONFIG_INTEL_MEI=m
CONFIG_INTEL_MEI_ME=m
CONFIG_INTEL_MEI_TXE=m
-# CONFIG_INTEL_MEI_HDCP is not set
+CONFIG_INTEL_MEI_HDCP=m
CONFIG_VMWARE_VMCI=m
-
-#
-# Intel MIC & related support
-#
-
-#
-# Intel MIC Bus Driver
-#
-CONFIG_INTEL_MIC_BUS=m
-
-#
-# SCIF Bus Driver
-#
-CONFIG_SCIF_BUS=m
-
-#
-# VOP Bus Driver
-#
-CONFIG_VOP_BUS=m
-
-#
-# Intel MIC Host Driver
-#
-CONFIG_INTEL_MIC_HOST=m
-
-#
-# Intel MIC Card Driver
-#
-CONFIG_INTEL_MIC_CARD=m
-
-#
-# SCIF Driver
-#
-CONFIG_SCIF=m
-
-#
-# Intel MIC Coprocessor State Management (COSM) Drivers
-#
-CONFIG_MIC_COSM=m
-
-#
-# VOP Driver
-#
-CONFIG_VOP=m
-CONFIG_VHOST_RING=m
-# end of Intel MIC & related support
-
# CONFIG_GENWQE is not set
# CONFIG_ECHO is not set
-# CONFIG_MISC_ALCOR_PCI is not set
-# CONFIG_MISC_RTSX_PCI is not set
-# CONFIG_MISC_RTSX_USB is not set
-# CONFIG_HABANA_AI is not set
+CONFIG_BCM_VK=m
+# CONFIG_BCM_VK_TTY is not set
+CONFIG_MISC_ALCOR_PCI=m
+CONFIG_MISC_RTSX_PCI=m
+CONFIG_MISC_RTSX_USB=m
+CONFIG_HABANA_AI=m
+CONFIG_UACCE=m
+# CONFIG_PVPANIC is not set
# end of Misc devices
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
-
#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=y
+CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_PROC_FS=y
@@ -2183,6 +2310,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=y
CONFIG_CHR_DEV_SG=y
+CONFIG_BLK_DEV_BSG=y
CONFIG_CHR_DEV_SCH=m
# CONFIG_SCSI_ENCLOSURE is not set
CONFIG_SCSI_CONSTANTS=y
@@ -2214,6 +2342,7 @@ CONFIG_SCSI_HPSA=m
CONFIG_SCSI_3W_9XXX=m
CONFIG_SCSI_3W_SAS=m
CONFIG_SCSI_ACARD=m
+# CONFIG_SCSI_AHA1740 is not set
CONFIG_SCSI_AACRAID=m
CONFIG_SCSI_AIC7XXX=m
CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
@@ -2245,11 +2374,13 @@ CONFIG_SCSI_MPT3SAS=m
CONFIG_SCSI_MPT2SAS_MAX_SGE=128
CONFIG_SCSI_MPT3SAS_MAX_SGE=128
# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPI3MR is not set
CONFIG_SCSI_SMARTPQI=m
CONFIG_SCSI_UFSHCD=m
# CONFIG_SCSI_UFSHCD_PCI is not set
# CONFIG_SCSI_UFSHCD_PLATFORM is not set
# CONFIG_SCSI_UFS_BSG is not set
+# CONFIG_SCSI_UFS_HPB is not set
CONFIG_SCSI_HPTIOP=m
CONFIG_SCSI_BUSLOGIC=y
# CONFIG_SCSI_FLASHPOINT is not set
@@ -2263,7 +2394,6 @@ CONFIG_SCSI_SNIC=m
CONFIG_SCSI_DMX3191D=m
CONFIG_SCSI_FDOMAIN=m
# CONFIG_SCSI_FDOMAIN_PCI is not set
-CONFIG_SCSI_GDTH=m
CONFIG_SCSI_ISCI=m
CONFIG_SCSI_IPS=m
CONFIG_SCSI_INITIO=m
@@ -2282,6 +2412,7 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
CONFIG_SCSI_QLOGIC_1280=m
CONFIG_SCSI_QLA_ISCSI=m
CONFIG_QEDI=m
+# CONFIG_SCSI_SIM710 is not set
CONFIG_SCSI_DC395x=m
CONFIG_SCSI_AM53C974=m
CONFIG_SCSI_WD719X=m
@@ -2302,7 +2433,10 @@ CONFIG_SCSI_DH_ALUA=m
# end of SCSI device support
CONFIG_ATA=y
+CONFIG_SATA_HOST=y
+CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATA_FORCE=y
CONFIG_ATA_ACPI=y
# CONFIG_SATA_ZPODD is not set
CONFIG_SATA_PMP=y
@@ -2410,6 +2544,7 @@ CONFIG_MD_RAID456=m
CONFIG_BCACHE=m
# CONFIG_BCACHE_DEBUG is not set
# CONFIG_BCACHE_CLOSURES_DEBUG is not set
+# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=m
# CONFIG_DM_DEBUG is not set
@@ -2424,6 +2559,7 @@ CONFIG_DM_THIN_PROVISIONING=m
CONFIG_DM_CACHE=m
CONFIG_DM_CACHE_SMQ=m
CONFIG_DM_WRITECACHE=m
+# CONFIG_DM_EBS is not set
CONFIG_DM_ERA=m
CONFIG_DM_CLONE=m
CONFIG_DM_MIRROR=m
@@ -2466,6 +2602,7 @@ CONFIG_MII=m
CONFIG_NET_CORE=y
CONFIG_BONDING=m
CONFIG_DUMMY=m
+# CONFIG_WIREGUARD is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_FC is not set
# CONFIG_IFB is not set
@@ -2482,6 +2619,7 @@ CONFIG_IPVLAN=m
CONFIG_IPVTAP=m
CONFIG_VXLAN=m
# CONFIG_GENEVE is not set
+# CONFIG_BAREUDP is not set
# CONFIG_GTP is not set
CONFIG_MACSEC=m
CONFIG_NETCONSOLE=m
@@ -2497,19 +2635,10 @@ CONFIG_VIRTIO_NET=m
# CONFIG_NET_VRF is not set
CONFIG_SUNGEM_PHY=m
# CONFIG_ARCNET is not set
-
-#
-# CAIF transport drivers
-#
-
-#
-# Distributed Switch Architecture drivers
-#
-# end of Distributed Switch Architecture drivers
-
CONFIG_ETHERNET=y
CONFIG_MDIO=y
CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL3 is not set
CONFIG_PCMCIA_3C574=m
CONFIG_PCMCIA_3C589=m
CONFIG_VORTEX=m
@@ -2541,7 +2670,6 @@ CONFIG_ATL1=m
CONFIG_ATL1E=m
CONFIG_ATL1C=m
CONFIG_ALX=m
-# CONFIG_NET_VENDOR_AURORA is not set
CONFIG_NET_VENDOR_BROADCOM=y
CONFIG_B44=m
CONFIG_B44_PCI_AUTOSELECT=y
@@ -2577,9 +2705,12 @@ CONFIG_NET_VENDOR_CHELSIO=y
CONFIG_CHELSIO_T1=m
CONFIG_CHELSIO_T1_1G=y
CONFIG_CHELSIO_T3=y
-CONFIG_CHELSIO_T4=y
+CONFIG_CHELSIO_T4=m
CONFIG_CHELSIO_T4VF=m
CONFIG_CHELSIO_LIB=m
+CONFIG_CHELSIO_INLINE_CRYPTO=y
+# CONFIG_CHELSIO_IPSEC_INLINE is not set
+CONFIG_NET_VENDOR_CIRRUS=y
CONFIG_NET_VENDOR_CISCO=y
CONFIG_ENIC=m
CONFIG_NET_VENDOR_CORTINA=y
@@ -2616,8 +2747,6 @@ CONFIG_NET_VENDOR_FUJITSU=y
CONFIG_PCMCIA_FMVJ18X=m
CONFIG_NET_VENDOR_GOOGLE=y
# CONFIG_GVE is not set
-CONFIG_NET_VENDOR_HP=y
-CONFIG_HP100=m
CONFIG_NET_VENDOR_HUAWEI=y
CONFIG_HINIC=m
CONFIG_NET_VENDOR_I825XX=y
@@ -2643,7 +2772,10 @@ CONFIG_I40EVF=m
# CONFIG_ICE is not set
CONFIG_FM10K=m
# CONFIG_IGC is not set
+CONFIG_NET_VENDOR_MICROSOFT=y
CONFIG_JME=m
+CONFIG_NET_VENDOR_LITEX=y
+# CONFIG_LITEX_LITEETH is not set
CONFIG_NET_VENDOR_MARVELL=y
CONFIG_MVMDIO=m
CONFIG_SKGE=m
@@ -2763,6 +2895,9 @@ CONFIG_STMMAC_ETH=m
CONFIG_STMMAC_PLATFORM=m
# CONFIG_DWMAC_DWC_QOS_ETH is not set
CONFIG_DWMAC_GENERIC=m
+# CONFIG_DWMAC_INTEL_PLAT is not set
+CONFIG_DWMAC_INTEL=m
+# CONFIG_DWMAC_LOONGSON is not set
CONFIG_STMMAC_PCI=m
CONFIG_NET_VENDOR_SUN=y
CONFIG_HAPPYMEAL=m
@@ -2789,6 +2924,7 @@ CONFIG_WIZNET_W5300=m
CONFIG_WIZNET_BUS_ANY=y
# CONFIG_WIZNET_W5100_SPI is not set
CONFIG_NET_VENDOR_XILINX=y
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_XILINX_AXI_EMAC is not set
# CONFIG_XILINX_LL_TEMAC is not set
CONFIG_NET_VENDOR_XIRCOM=y
@@ -2796,56 +2932,47 @@ CONFIG_PCMCIA_XIRC2PS=m
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_NET_SB1000 is not set
-CONFIG_MDIO_DEVICE=m
-CONFIG_MDIO_BUS=m
-CONFIG_MDIO_BCM_UNIMAC=m
-# CONFIG_MDIO_BITBANG is not set
-# CONFIG_MDIO_BUS_MUX_GPIO is not set
-# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
-# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
-CONFIG_MDIO_CAVIUM=m
-# CONFIG_MDIO_HISI_FEMAC is not set
-# CONFIG_MDIO_MSCC_MIIM is not set
-# CONFIG_MDIO_OCTEON is not set
-CONFIG_MDIO_THUNDER=m
CONFIG_PHYLINK=m
CONFIG_PHYLIB=m
CONFIG_SWPHY=y
CONFIG_LED_TRIGGER_PHY=y
+CONFIG_FIXED_PHY=m
+# CONFIG_SFP is not set
#
# MII PHY device drivers
#
-# CONFIG_SFP is not set
-# CONFIG_ADIN_PHY is not set
CONFIG_AMD_PHY=m
+# CONFIG_ADIN_PHY is not set
CONFIG_AQUANTIA_PHY=m
-# CONFIG_AX88796B_PHY is not set
-CONFIG_AT803X_PHY=m
+CONFIG_AX88796B_PHY=m
+CONFIG_BROADCOM_PHY=m
+# CONFIG_BCM54140_PHY is not set
CONFIG_BCM7XXX_PHY=m
+# CONFIG_BCM84881_PHY is not set
CONFIG_BCM87XX_PHY=m
CONFIG_BCM_NET_PHYLIB=m
-CONFIG_BROADCOM_PHY=m
CONFIG_CICADA_PHY=m
CONFIG_CORTINA_PHY=m
CONFIG_DAVICOM_PHY=m
-# CONFIG_DP83822_PHY is not set
-# CONFIG_DP83TC811_PHY is not set
-CONFIG_DP83848_PHY=m
-CONFIG_DP83867_PHY=m
-CONFIG_FIXED_PHY=m
CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
CONFIG_INTEL_XWAY_PHY=m
CONFIG_LSI_ET1011C_PHY=m
-CONFIG_LXT_PHY=m
CONFIG_MARVELL_PHY=m
CONFIG_MARVELL_10G_PHY=m
+# CONFIG_MARVELL_88X2222_PHY is not set
+# CONFIG_MAXLINEAR_GPHY is not set
+# CONFIG_MEDIATEK_GE_PHY is not set
CONFIG_MICREL_PHY=m
CONFIG_MICROCHIP_PHY=m
# CONFIG_MICROCHIP_T1_PHY is not set
CONFIG_MICROSEMI_PHY=m
+# CONFIG_MOTORCOMM_PHY is not set
CONFIG_NATIONAL_PHY=m
+# CONFIG_NXP_C45_TJA11XX_PHY is not set
# CONFIG_NXP_TJA11XX_PHY is not set
+CONFIG_AT803X_PHY=m
CONFIG_QSEMI_PHY=m
CONFIG_REALTEK_PHY=m
# CONFIG_RENESAS_PHY is not set
@@ -2853,9 +2980,44 @@ CONFIG_ROCKCHIP_PHY=m
CONFIG_SMSC_PHY=m
CONFIG_STE10XP=m
CONFIG_TERANETICS_PHY=m
+# CONFIG_DP83822_PHY is not set
+# CONFIG_DP83TC811_PHY is not set
+CONFIG_DP83848_PHY=m
+CONFIG_DP83867_PHY=m
+# CONFIG_DP83869_PHY is not set
CONFIG_VITESSE_PHY=m
CONFIG_XILINX_GMII2RGMII=m
# CONFIG_MICREL_KS8995MA is not set
+CONFIG_MDIO_DEVICE=m
+CONFIG_MDIO_BUS=m
+CONFIG_FWNODE_MDIO=m
+CONFIG_OF_MDIO=m
+CONFIG_ACPI_MDIO=m
+CONFIG_MDIO_DEVRES=m
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_MDIO_BCM_UNIMAC=m
+CONFIG_MDIO_CAVIUM=m
+# CONFIG_MDIO_HISI_FEMAC is not set
+# CONFIG_MDIO_MVUSB is not set
+# CONFIG_MDIO_MSCC_MIIM is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MDIO_IPQ4019 is not set
+# CONFIG_MDIO_IPQ8064 is not set
+CONFIG_MDIO_THUNDER=m
+
+#
+# MDIO Multiplexers
+#
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+
+#
+# PCS device drivers
+#
+CONFIG_PCS_XPCS=m
+# end of PCS device drivers
+
CONFIG_PLIP=m
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
@@ -2868,8 +3030,11 @@ CONFIG_PPPOE=m
CONFIG_PPPOL2TP=m
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
-# CONFIG_SLIP is not set
+CONFIG_SLIP=m
CONFIG_SLHC=m
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
CONFIG_USB_NET_DRIVERS=m
CONFIG_USB_CATC=m
CONFIG_USB_KAWETH=m
@@ -2913,9 +3078,9 @@ CONFIG_USB_IPHETH=m
CONFIG_USB_SIERRA_NET=m
CONFIG_USB_VL600=m
CONFIG_USB_NET_CH9200=m
-# CONFIG_USB_NET_AQC111 is not set
+CONFIG_USB_NET_AQC111=m
+CONFIG_USB_RTL8153_ECM=m
CONFIG_WLAN=y
-# CONFIG_WIRELESS_WDS is not set
CONFIG_WLAN_VENDOR_ADMTEK=y
CONFIG_ADM8211=m
CONFIG_ATH_COMMON=m
@@ -2962,6 +3127,7 @@ CONFIG_ATH10K_USB=m
# CONFIG_ATH10K_DEBUGFS is not set
CONFIG_WCN36XX=m
# CONFIG_WCN36XX_DEBUGFS is not set
+# CONFIG_ATH11K is not set
CONFIG_WLAN_VENDOR_ATMEL=y
CONFIG_ATMEL=m
CONFIG_PCI_ATMEL=m
@@ -3067,7 +3233,6 @@ CONFIG_P54_PCI=m
CONFIG_P54_SPI=m
# CONFIG_P54_SPI_DEFAULT_EEPROM is not set
CONFIG_P54_LEDS=y
-CONFIG_PRISM54=m
CONFIG_WLAN_VENDOR_MARVELL=y
CONFIG_LIBERTAS=m
CONFIG_LIBERTAS_USB=m
@@ -3086,12 +3251,32 @@ CONFIG_MWIFIEX_USB=m
CONFIG_MWL8K=m
CONFIG_WLAN_VENDOR_MEDIATEK=y
CONFIG_MT7601U=m
-# CONFIG_MT76x0U is not set
-# CONFIG_MT76x0E is not set
-# CONFIG_MT76x2E is not set
-# CONFIG_MT76x2U is not set
-# CONFIG_MT7603E is not set
-# CONFIG_MT7615E is not set
+CONFIG_MT76_CORE=m
+CONFIG_MT76_LEDS=y
+CONFIG_MT76_USB=m
+CONFIG_MT76_SDIO=m
+CONFIG_MT76x02_LIB=m
+CONFIG_MT76x02_USB=m
+CONFIG_MT76_CONNAC_LIB=m
+CONFIG_MT76x0_COMMON=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x0E=m
+CONFIG_MT76x2_COMMON=m
+CONFIG_MT76x2E=m
+CONFIG_MT76x2U=m
+CONFIG_MT7603E=m
+CONFIG_MT7615_COMMON=m
+CONFIG_MT7615E=m
+CONFIG_MT7663_USB_SDIO_COMMON=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+CONFIG_MT7921E=m
+CONFIG_WLAN_VENDOR_MICROCHIP=y
+CONFIG_WILC1000=m
+CONFIG_WILC1000_SDIO=m
+CONFIG_WILC1000_SPI=m
+# CONFIG_WILC1000_HW_OOB_INTR is not set
CONFIG_WLAN_VENDOR_RALINK=y
CONFIG_RT2X00=m
CONFIG_RT2400PCI=m
@@ -3170,27 +3355,30 @@ CONFIG_USB_ZD1201=m
CONFIG_ZD1211RW=m
# CONFIG_ZD1211RW_DEBUG is not set
CONFIG_WLAN_VENDOR_QUANTENNA=y
-# CONFIG_QTNFMAC_PCIE is not set
+CONFIG_QTNFMAC=m
+CONFIG_QTNFMAC_PCIE=m
CONFIG_PCMCIA_RAYCS=m
CONFIG_PCMCIA_WL3501=m
# CONFIG_MAC80211_HWSIM is not set
CONFIG_USB_NET_RNDIS_WLAN=m
# CONFIG_VIRT_WIFI is not set
+# CONFIG_WAN is not set
#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
+# Wireless WAN
#
-# CONFIG_WAN is not set
+# CONFIG_WWAN is not set
+# end of Wireless WAN
+
CONFIG_XEN_NETDEV_FRONTEND=m
CONFIG_XEN_NETDEV_BACKEND=m
CONFIG_VMXNET3=m
# CONFIG_FUJITSU_ES is not set
-# CONFIG_THUNDERBOLT_NET is not set
+# CONFIG_USB4_NET is not set
CONFIG_HYPERV_NET=m
# CONFIG_NETDEVSIM is not set
CONFIG_NET_FAILOVER=m
# CONFIG_ISDN is not set
-# CONFIG_NVM is not set
#
# Input device support
@@ -3198,7 +3386,6 @@ CONFIG_NET_FAILOVER=m
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=m
CONFIG_INPUT_FF_MEMLESS=y
-CONFIG_INPUT_POLLDEV=m
CONFIG_INPUT_SPARSEKMAP=m
CONFIG_INPUT_MATRIXKMAP=m
@@ -3206,7 +3393,7 @@ CONFIG_INPUT_MATRIXKMAP=m
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=m
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_JOYDEV=m
@@ -3219,18 +3406,18 @@ CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ADP5588=m
CONFIG_KEYBOARD_ADP5589=m
-# CONFIG_KEYBOARD_APPLESPI is not set
+CONFIG_KEYBOARD_APPLESPI=m
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_QT1050 is not set
+CONFIG_KEYBOARD_QT1050=m
CONFIG_KEYBOARD_QT1070=m
CONFIG_KEYBOARD_QT2160=m
CONFIG_KEYBOARD_DLINK_DIR685=m
CONFIG_KEYBOARD_LKKBD=m
-# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO=m
# CONFIG_KEYBOARD_GPIO_POLLED is not set
CONFIG_KEYBOARD_TCA6416=m
CONFIG_KEYBOARD_TCA8418=m
-# CONFIG_KEYBOARD_MATRIX is not set
+CONFIG_KEYBOARD_MATRIX=m
CONFIG_KEYBOARD_LM8323=m
CONFIG_KEYBOARD_LM8333=m
CONFIG_KEYBOARD_MAX7359=m
@@ -3255,9 +3442,9 @@ CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_CYPRESS=y
CONFIG_MOUSE_PS2_LIFEBOOK=y
CONFIG_MOUSE_PS2_TRACKPOINT=y
-# CONFIG_MOUSE_PS2_ELANTECH is not set
-# CONFIG_MOUSE_PS2_SENTELIC is not set
-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_PS2_TOUCHKIT=y
CONFIG_MOUSE_PS2_FOCALTECH=y
CONFIG_MOUSE_PS2_VMMOUSE=y
CONFIG_MOUSE_SERIAL=y
@@ -3268,7 +3455,7 @@ CONFIG_MOUSE_ELAN_I2C=m
CONFIG_MOUSE_ELAN_I2C_I2C=y
CONFIG_MOUSE_ELAN_I2C_SMBUS=y
CONFIG_MOUSE_VSXXXAA=m
-# CONFIG_MOUSE_GPIO is not set
+CONFIG_MOUSE_GPIO=m
CONFIG_MOUSE_SYNAPTICS_I2C=m
CONFIG_MOUSE_SYNAPTICS_USB=m
CONFIG_INPUT_JOYSTICK=y
@@ -3302,19 +3489,19 @@ CONFIG_JOYSTICK_XPAD=m
CONFIG_JOYSTICK_XPAD_FF=y
CONFIG_JOYSTICK_XPAD_LEDS=y
CONFIG_JOYSTICK_WALKERA0701=m
-# CONFIG_JOYSTICK_PSXPAD_SPI is not set
-# CONFIG_JOYSTICK_PXRC is not set
-# CONFIG_JOYSTICK_FSIA6B is not set
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_PXRC=m
+CONFIG_JOYSTICK_QWIIC=m
+CONFIG_JOYSTICK_FSIA6B=m
CONFIG_INPUT_TABLET=y
CONFIG_TABLET_USB_ACECAD=m
CONFIG_TABLET_USB_AIPTEK=m
-CONFIG_TABLET_USB_GTCO=m
CONFIG_TABLET_USB_HANWANG=m
CONFIG_TABLET_USB_KBTAB=m
CONFIG_TABLET_USB_PEGASUS=m
CONFIG_TABLET_SERIAL_WACOM4=m
CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_PROPERTIES=y
# CONFIG_TOUCHSCREEN_ADS7846 is not set
# CONFIG_TOUCHSCREEN_AD7877 is not set
CONFIG_TOUCHSCREEN_AD7879=m
@@ -3328,6 +3515,7 @@ CONFIG_TOUCHSCREEN_BU21013=m
# CONFIG_TOUCHSCREEN_BU21029 is not set
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set
# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
CONFIG_TOUCHSCREEN_CYTTSP_CORE=m
# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set
@@ -3344,7 +3532,9 @@ CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m
CONFIG_TOUCHSCREEN_FUJITSU=m
# CONFIG_TOUCHSCREEN_GOODIX is not set
# CONFIG_TOUCHSCREEN_HIDEEP is not set
+# CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set
CONFIG_TOUCHSCREEN_ILI210X=m
+# CONFIG_TOUCHSCREEN_ILITEK is not set
# CONFIG_TOUCHSCREEN_S6SY761 is not set
CONFIG_TOUCHSCREEN_GUNZE=m
CONFIG_TOUCHSCREEN_EKTF2127=m
@@ -3356,6 +3546,7 @@ CONFIG_TOUCHSCREEN_MAX11801=m
CONFIG_TOUCHSCREEN_MCS5000=m
CONFIG_TOUCHSCREEN_MMS114=m
CONFIG_TOUCHSCREEN_MELFAS_MIP4=m
+# CONFIG_TOUCHSCREEN_MSG2638 is not set
CONFIG_TOUCHSCREEN_MTOUCH=m
# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
CONFIG_TOUCHSCREEN_INEXIO=m
@@ -3408,6 +3599,7 @@ CONFIG_TOUCHSCREEN_ZET6223=m
# CONFIG_TOUCHSCREEN_ZFORCE is not set
CONFIG_TOUCHSCREEN_ROHM_BU21023=m
# CONFIG_TOUCHSCREEN_IQS5XX is not set
+# CONFIG_TOUCHSCREEN_ZINITIX is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_AD714X=m
CONFIG_INPUT_AD714X_I2C=m
@@ -3415,10 +3607,9 @@ CONFIG_INPUT_AD714X_SPI=m
CONFIG_INPUT_ATMEL_CAPTOUCH=m
CONFIG_INPUT_BMA150=m
CONFIG_INPUT_E3X0_BUTTON=m
-# CONFIG_INPUT_MSM_VIBRATOR is not set
+# CONFIG_INPUT_PCSPKR is not set
CONFIG_INPUT_MMA8450=m
CONFIG_INPUT_APANEL=m
-# CONFIG_INPUT_GP2A is not set
# CONFIG_INPUT_GPIO_BEEPER is not set
# CONFIG_INPUT_GPIO_DECODER is not set
# CONFIG_INPUT_GPIO_VIBRA is not set
@@ -3426,22 +3617,27 @@ CONFIG_INPUT_ATLAS_BTNS=m
CONFIG_INPUT_ATI_REMOTE2=m
CONFIG_INPUT_KEYSPAN_REMOTE=m
CONFIG_INPUT_KXTJ9=m
-# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set
CONFIG_INPUT_POWERMATE=m
CONFIG_INPUT_YEALINK=m
CONFIG_INPUT_CM109=m
# CONFIG_INPUT_REGULATOR_HAPTIC is not set
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_PCF8574=m
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_PWM_VIBRA is not set
# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_DA7280_HAPTICS is not set
CONFIG_INPUT_ADXL34X=m
CONFIG_INPUT_ADXL34X_I2C=m
CONFIG_INPUT_ADXL34X_SPI=m
CONFIG_INPUT_IMS_PCU=m
+# CONFIG_INPUT_IQS269A is not set
+# CONFIG_INPUT_IQS626A is not set
CONFIG_INPUT_CMA3000=m
# CONFIG_INPUT_CMA3000_I2C is not set
CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y
CONFIG_INPUT_IDEAPAD_SLIDEBAR=m
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
# CONFIG_INPUT_DRV260X_HAPTICS is not set
CONFIG_INPUT_DRV2665_HAPTICS=m
CONFIG_INPUT_DRV2667_HAPTICS=m
@@ -3456,6 +3652,7 @@ CONFIG_RMI4_F11=y
CONFIG_RMI4_F12=y
CONFIG_RMI4_F30=y
# CONFIG_RMI4_F34 is not set
+# CONFIG_RMI4_F3A is not set
# CONFIG_RMI4_F54 is not set
# CONFIG_RMI4_F55 is not set
@@ -3499,14 +3696,7 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-# CONFIG_TRACE_SINK is not set
-# CONFIG_NULL_TTY is not set
CONFIG_LDISC_AUTOLOAD=y
-CONFIG_DEVMEM=y
-# CONFIG_DEVKMEM is not set
#
# Serial drivers
@@ -3515,6 +3705,7 @@ CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
CONFIG_SERIAL_8250_PNP=y
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
# CONFIG_SERIAL_8250_FINTEK is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DMA=y
@@ -3543,16 +3734,17 @@ CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_JSM=m
# CONFIG_SERIAL_SIFIVE is not set
+# CONFIG_SERIAL_LANTIQ is not set
CONFIG_SERIAL_SCCNXP=m
CONFIG_SERIAL_SC16IS7XX_CORE=m
CONFIG_SERIAL_SC16IS7XX=m
CONFIG_SERIAL_SC16IS7XX_I2C=y
# CONFIG_SERIAL_SC16IS7XX_SPI is not set
+# CONFIG_SERIAL_BCM63XX is not set
CONFIG_SERIAL_ALTERA_JTAGUART=m
CONFIG_SERIAL_ALTERA_UART=m
CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4
CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200
-# CONFIG_SERIAL_IFX6X60 is not set
CONFIG_SERIAL_XILINX_PS_UART=m
CONFIG_SERIAL_ARC=m
CONFIG_SERIAL_ARC_NR_PORTS=1
@@ -3561,18 +3753,23 @@ CONFIG_SERIAL_RP2_NR_UARTS=32
CONFIG_SERIAL_FSL_LPUART=m
# CONFIG_SERIAL_FSL_LINFLEXUART is not set
CONFIG_SERIAL_CONEXANT_DIGICOLOR=m
+# CONFIG_SERIAL_SPRD is not set
# end of Serial drivers
CONFIG_SERIAL_MCTRL_GPIO=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NULL_TTY is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_XEN=y
+CONFIG_HVC_XEN_FRONTEND=y
CONFIG_SERIAL_DEV_BUS=m
# CONFIG_TTY_PRINTK is not set
CONFIG_PRINTER=m
# CONFIG_LP_CONSOLE is not set
CONFIG_PPDEV=m
-CONFIG_HVC_DRIVER=y
-CONFIG_HVC_IRQ=y
-CONFIG_HVC_XEN=y
-CONFIG_HVC_XEN_FRONTEND=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DMI_DECODE=y
@@ -3587,9 +3784,11 @@ CONFIG_HW_RANDOM=m
CONFIG_HW_RANDOM_TIMERIOMEM=m
CONFIG_HW_RANDOM_INTEL=m
CONFIG_HW_RANDOM_AMD=m
+# CONFIG_HW_RANDOM_BA431 is not set
CONFIG_HW_RANDOM_VIA=m
# CONFIG_HW_RANDOM_VIRTIO is not set
-CONFIG_NVRAM=m
+# CONFIG_HW_RANDOM_CCTRNG is not set
+# CONFIG_HW_RANDOM_XIPHERA is not set
# CONFIG_APPLICOM is not set
#
@@ -3603,7 +3802,9 @@ CONFIG_IPWIRELESS=m
# end of PCMCIA character devices
CONFIG_MWAVE=m
-# CONFIG_RAW_DRIVER is not set
+CONFIG_DEVMEM=y
+CONFIG_NVRAM=m
+CONFIG_DEVPORT=y
CONFIG_HPET=y
CONFIG_HPET_MMAP=y
CONFIG_HPET_MMAP_DEFAULT=y
@@ -3613,6 +3814,7 @@ CONFIG_HW_RANDOM_TPM=y
CONFIG_TCG_TIS_CORE=m
CONFIG_TCG_TIS=m
# CONFIG_TCG_TIS_SPI is not set
+# CONFIG_TCG_TIS_I2C_CR50 is not set
CONFIG_TCG_TIS_I2C_ATMEL=m
CONFIG_TCG_TIS_I2C_INFINEON=m
CONFIG_TCG_TIS_I2C_NUVOTON=m
@@ -3626,12 +3828,65 @@ CONFIG_TCG_TIS_ST33ZP24=m
CONFIG_TCG_TIS_ST33ZP24_I2C=m
# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
# CONFIG_TELCLOCK is not set
-CONFIG_DEVPORT=y
# CONFIG_XILLYBUS is not set
-# end of Character devices
-
+# CONFIG_XILLYUSB is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
+CONFIG_LRNG=y
+
+#
+# Specific DRNG seeding strategies
+#
+CONFIG_LRNG_OVERSAMPLE_ENTROPY_SOURCES=y
+CONFIG_LRNG_OVERSAMPLE_ES_BITS=64
+CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS=128
+# end of Specific DRNG seeding strategies
+
+#
+# Entropy Source Configuration
+#
+
+#
+# Interrupt Entropy Source
+#
+CONFIG_LRNG_IRQ=y
+CONFIG_LRNG_CONTINUOUS_COMPRESSION_ENABLED=y
+# CONFIG_LRNG_CONTINUOUS_COMPRESSION_DISABLED is not set
+CONFIG_LRNG_ENABLE_CONTINUOUS_COMPRESSION=y
+# CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION is not set
+CONFIG_LRNG_COLLECTION_SIZE_512=y
+# CONFIG_LRNG_COLLECTION_SIZE_1024 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_2048 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_4096 is not set
+# CONFIG_LRNG_COLLECTION_SIZE_8192 is not set
+CONFIG_LRNG_COLLECTION_SIZE=512
+# CONFIG_LRNG_HEALTH_TESTS is not set
+CONFIG_LRNG_RCT_CUTOFF=31
+CONFIG_LRNG_APT_CUTOFF=325
+CONFIG_LRNG_IRQ_ENTROPY_RATE=256
+
+#
+# Jitter RNG Entropy Source
+#
+CONFIG_LRNG_JENT=y
+CONFIG_LRNG_JENT_ENTROPY_RATE=16
+
+#
+# CPU Entropy Source
+#
+CONFIG_LRNG_CPU=y
+CONFIG_LRNG_CPU_FULL_ENT_MULTIPLIER=1
+CONFIG_LRNG_CPU_ENTROPY_RATE=8
+# end of Entropy Source Configuration
+
+CONFIG_LRNG_DRNG_SWITCH=y
+CONFIG_LRNG_KCAPI_HASH=y
+CONFIG_LRNG_DRBG=m
+# CONFIG_LRNG_KCAPI is not set
+# CONFIG_LRNG_TESTING_MENU is not set
+CONFIG_LRNG_SELFTEST=y
+# CONFIG_LRNG_SELFTEST_PANIC is not set
+# end of Character devices
#
# I2C support
@@ -3645,16 +3900,16 @@ CONFIG_I2C_MUX=m
#
# Multiplexer I2C Chip support
#
-# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
-# CONFIG_I2C_MUX_GPIO is not set
-# CONFIG_I2C_MUX_GPMUX is not set
-# CONFIG_I2C_MUX_LTC4306 is not set
-# CONFIG_I2C_MUX_PCA9541 is not set
-# CONFIG_I2C_MUX_PCA954x is not set
-# CONFIG_I2C_MUX_PINCTRL is not set
-# CONFIG_I2C_MUX_REG is not set
-# CONFIG_I2C_DEMUX_PINCTRL is not set
-# CONFIG_I2C_MUX_MLXCPLD is not set
+CONFIG_I2C_ARB_GPIO_CHALLENGE=m
+CONFIG_I2C_MUX_GPIO=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_LTC4306=m
+CONFIG_I2C_MUX_PCA9541=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_MUX_REG=m
+CONFIG_I2C_DEMUX_PINCTRL=m
+CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support
CONFIG_I2C_HELPER_AUTO=y
@@ -3681,7 +3936,7 @@ CONFIG_I2C_ISMT=m
CONFIG_I2C_PIIX4=m
CONFIG_I2C_NFORCE2=m
# CONFIG_I2C_NFORCE2_S4985 is not set
-# CONFIG_I2C_NVIDIA_GPU is not set
+CONFIG_I2C_NVIDIA_GPU=m
CONFIG_I2C_SIS5595=m
CONFIG_I2C_SIS630=m
CONFIG_I2C_SIS96X=m
@@ -3698,12 +3953,13 @@ CONFIG_I2C_SCMI=m
#
# CONFIG_I2C_CBUS_GPIO is not set
CONFIG_I2C_DESIGNWARE_CORE=m
-CONFIG_I2C_DESIGNWARE_PLATFORM=m
# CONFIG_I2C_DESIGNWARE_SLAVE is not set
-CONFIG_I2C_DESIGNWARE_PCI=m
+CONFIG_I2C_DESIGNWARE_PLATFORM=m
# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set
+CONFIG_I2C_DESIGNWARE_PCI=m
# CONFIG_I2C_EMEV2 is not set
-# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PCA_PLATFORM is not set
# CONFIG_I2C_RK3X is not set
@@ -3714,9 +3970,9 @@ CONFIG_I2C_DESIGNWARE_PCI=m
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_CP2615 is not set
CONFIG_I2C_PARPORT=m
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
# CONFIG_I2C_TAOS_EVM is not set
CONFIG_I2C_TINY_USB=m
@@ -3724,6 +3980,7 @@ CONFIG_I2C_TINY_USB=m
# Other I2C/SMBus bus drivers
#
# CONFIG_I2C_MLXCPLD is not set
+# CONFIG_I2C_VIRTIO is not set
# end of I2C Hardware Bus support
# CONFIG_I2C_STUB is not set
@@ -3733,7 +3990,11 @@ CONFIG_I2C_TINY_USB=m
# CONFIG_I2C_DEBUG_BUS is not set
# end of I2C support
-# CONFIG_I3C is not set
+CONFIG_I3C=m
+CONFIG_CDNS_I3C_MASTER=m
+CONFIG_DW_I3C_MASTER=m
+CONFIG_SVC_I3C_MASTER=m
+CONFIG_MIPI_I3C_HCI=m
CONFIG_SPI=y
# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
@@ -3743,29 +4004,38 @@ CONFIG_SPI_MEM=y
# SPI Master Controller Drivers
#
CONFIG_SPI_ALTERA=m
+CONFIG_SPI_ALTERA_CORE=m
CONFIG_SPI_AXI_SPI_ENGINE=m
CONFIG_SPI_BITBANG=m
CONFIG_SPI_BUTTERFLY=m
CONFIG_SPI_CADENCE=m
+CONFIG_SPI_CADENCE_QUADSPI=m
CONFIG_SPI_DESIGNWARE=m
+# CONFIG_SPI_DW_DMA is not set
CONFIG_SPI_DW_PCI=m
-# CONFIG_SPI_DW_MID_DMA is not set
CONFIG_SPI_DW_MMIO=m
# CONFIG_SPI_NXP_FLEXSPI is not set
# CONFIG_SPI_GPIO is not set
# CONFIG_SPI_LM70_LLP is not set
CONFIG_SPI_FSL_LIB=m
CONFIG_SPI_FSL_SPI=m
+# CONFIG_SPI_LANTIQ_SSC is not set
# CONFIG_SPI_OC_TINY is not set
CONFIG_SPI_PXA2XX=m
CONFIG_SPI_PXA2XX_PCI=m
CONFIG_SPI_ROCKCHIP=m
CONFIG_SPI_SC18IS602=m
-# CONFIG_SPI_SIFIVE is not set
-# CONFIG_SPI_MXIC is not set
+CONFIG_SPI_SIFIVE=m
+CONFIG_SPI_MXIC=m
CONFIG_SPI_XCOMM=m
CONFIG_SPI_XILINX=m
CONFIG_SPI_ZYNQMP_GQSPI=m
+CONFIG_SPI_AMD=m
+
+#
+# SPI Multiplexer support
+#
+# CONFIG_SPI_MUX is not set
#
# SPI Protocol Masters
@@ -3776,6 +4046,7 @@ CONFIG_SPI_ZYNQMP_GQSPI=m
# CONFIG_SPI_SLAVE is not set
CONFIG_SPI_DYNAMIC=y
CONFIG_SPMI=m
+# CONFIG_SPMI_HISI3670 is not set
CONFIG_HSI=m
CONFIG_HSI_BOARDINFO=y
@@ -3806,11 +4077,16 @@ CONFIG_PPS_CLIENT_GPIO=m
# PTP clock support
#
CONFIG_PTP_1588_CLOCK=m
+CONFIG_PTP_1588_CLOCK_OPTIONAL=m
#
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
#
CONFIG_PTP_1588_CLOCK_KVM=m
+# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
+# CONFIG_PTP_1588_CLOCK_IDTCM is not set
+# CONFIG_PTP_1588_CLOCK_VMW is not set
+# CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support
CONFIG_PINCTRL=y
@@ -3823,17 +4099,32 @@ CONFIG_GENERIC_PINCONF=y
# CONFIG_PINCTRL_SINGLE is not set
# CONFIG_PINCTRL_STMFX is not set
# CONFIG_PINCTRL_OCELOT is not set
+# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set
# CONFIG_PINCTRL_BAYTRAIL is not set
# CONFIG_PINCTRL_CHERRYVIEW is not set
+# CONFIG_PINCTRL_LYNXPOINT is not set
CONFIG_PINCTRL_INTEL=m
+# CONFIG_PINCTRL_ALDERLAKE is not set
# CONFIG_PINCTRL_BROXTON is not set
CONFIG_PINCTRL_CANNONLAKE=m
# CONFIG_PINCTRL_CEDARFORK is not set
# CONFIG_PINCTRL_DENVERTON is not set
+# CONFIG_PINCTRL_ELKHARTLAKE is not set
+# CONFIG_PINCTRL_EMMITSBURG is not set
# CONFIG_PINCTRL_GEMINILAKE is not set
# CONFIG_PINCTRL_ICELAKE is not set
+# CONFIG_PINCTRL_JASPERLAKE is not set
+# CONFIG_PINCTRL_LAKEFIELD is not set
# CONFIG_PINCTRL_LEWISBURG is not set
# CONFIG_PINCTRL_SUNRISEPOINT is not set
+# CONFIG_PINCTRL_TIGERLAKE is not set
+
+#
+# Renesas pinctrl drivers
+#
+# end of Renesas pinctrl drivers
+
+# CONFIG_PINCTRL_EQUILIBRIUM is not set
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_OF_GPIO=y
@@ -3841,6 +4132,8 @@ CONFIG_GPIO_ACPI=y
CONFIG_GPIOLIB_IRQCHIP=y
# CONFIG_DEBUG_GPIO is not set
# CONFIG_GPIO_SYSFS is not set
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_CDEV_V1=y
#
# Memory mapped GPIO drivers
@@ -3856,9 +4149,10 @@ CONFIG_GPIOLIB_IRQCHIP=y
# CONFIG_GPIO_GRGPIO is not set
# CONFIG_GPIO_HLWD is not set
# CONFIG_GPIO_ICH is not set
-# CONFIG_GPIO_LYNXPOINT is not set
+# CONFIG_GPIO_LOGICVC is not set
# CONFIG_GPIO_MB86S7X is not set
# CONFIG_GPIO_SAMA5D2_PIOBU is not set
+# CONFIG_GPIO_SIFIVE is not set
# CONFIG_GPIO_SYSCON is not set
# CONFIG_GPIO_VX855 is not set
# CONFIG_GPIO_XILINX is not set
@@ -3885,6 +4179,7 @@ CONFIG_GPIOLIB_IRQCHIP=y
# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCA9570 is not set
# CONFIG_GPIO_PCF857X is not set
# CONFIG_GPIO_TPIC2810 is not set
# end of I2C GPIO expanders
@@ -3921,13 +4216,20 @@ CONFIG_GPIOLIB_IRQCHIP=y
#
# end of USB GPIO expanders
+#
+# Virtual GPIO drivers
+#
+# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_MOCKUP is not set
+# CONFIG_GPIO_VIRTIO is not set
+# end of Virtual GPIO drivers
+
# CONFIG_W1 is not set
-# CONFIG_POWER_AVS is not set
CONFIG_POWER_RESET=y
# CONFIG_POWER_RESET_GPIO is not set
# CONFIG_POWER_RESET_GPIO_RESTART is not set
# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_REGULATOR is not set
# CONFIG_POWER_RESET_RESTART is not set
CONFIG_POWER_RESET_SYSCON=y
CONFIG_POWER_RESET_SYSCON_POWEROFF=y
@@ -3940,6 +4242,7 @@ CONFIG_POWER_SUPPLY_HWMON=y
CONFIG_PDA_POWER=m
# CONFIG_TEST_POWER is not set
# CONFIG_CHARGER_ADP5061 is not set
+# CONFIG_BATTERY_CW2015 is not set
# CONFIG_BATTERY_DS2780 is not set
# CONFIG_BATTERY_DS2781 is not set
# CONFIG_BATTERY_DS2782 is not set
@@ -3954,15 +4257,23 @@ CONFIG_CHARGER_SBS=m
# CONFIG_CHARGER_GPIO is not set
# CONFIG_CHARGER_MANAGER is not set
# CONFIG_CHARGER_LT3651 is not set
+# CONFIG_CHARGER_LTC4162L is not set
# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
# CONFIG_CHARGER_BQ24257 is not set
# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ2515X is not set
# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_BQ25980 is not set
+# CONFIG_CHARGER_BQ256XX is not set
# CONFIG_CHARGER_SMB347 is not set
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_RT5033 is not set
# CONFIG_CHARGER_RT9455 is not set
# CONFIG_CHARGER_UCS1002 is not set
+# CONFIG_CHARGER_BD99954 is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=m
# CONFIG_HWMON_DEBUG_CHIP is not set
@@ -3980,6 +4291,7 @@ CONFIG_SENSORS_ADM1025=m
CONFIG_SENSORS_ADM1026=m
CONFIG_SENSORS_ADM1029=m
CONFIG_SENSORS_ADM1031=m
+# CONFIG_SENSORS_ADM1177 is not set
CONFIG_SENSORS_ADM9240=m
CONFIG_SENSORS_ADT7X10=m
# CONFIG_SENSORS_ADT7310 is not set
@@ -3988,8 +4300,11 @@ CONFIG_SENSORS_ADT7411=m
CONFIG_SENSORS_ADT7462=m
CONFIG_SENSORS_ADT7470=m
CONFIG_SENSORS_ADT7475=m
+# CONFIG_SENSORS_AHT10 is not set
+# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
# CONFIG_SENSORS_AS370 is not set
CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
CONFIG_SENSORS_K8TEMP=m
CONFIG_SENSORS_K10TEMP=m
CONFIG_SENSORS_FAM15H_POWER=m
@@ -3997,6 +4312,9 @@ CONFIG_SENSORS_APPLESMC=m
CONFIG_SENSORS_ASB100=m
CONFIG_SENSORS_ASPEED=m
CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_CORSAIR_CPRO is not set
+# CONFIG_SENSORS_CORSAIR_PSU is not set
+# CONFIG_SENSORS_DRIVETEMP is not set
CONFIG_SENSORS_DS620=m
CONFIG_SENSORS_DS1621=m
CONFIG_SENSORS_DELL_SMM=m
@@ -4020,7 +4338,10 @@ CONFIG_SENSORS_JC42=m
CONFIG_SENSORS_POWR1220=m
CONFIG_SENSORS_LINEAGE=m
CONFIG_SENSORS_LTC2945=m
+# CONFIG_SENSORS_LTC2947_I2C is not set
+# CONFIG_SENSORS_LTC2947_SPI is not set
CONFIG_SENSORS_LTC2990=m
+# CONFIG_SENSORS_LTC2992 is not set
CONFIG_SENSORS_LTC4151=m
CONFIG_SENSORS_LTC4215=m
CONFIG_SENSORS_LTC4222=m
@@ -4028,11 +4349,13 @@ CONFIG_SENSORS_LTC4245=m
CONFIG_SENSORS_LTC4260=m
CONFIG_SENSORS_LTC4261=m
# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX127 is not set
CONFIG_SENSORS_MAX16065=m
CONFIG_SENSORS_MAX1619=m
CONFIG_SENSORS_MAX1668=m
CONFIG_SENSORS_MAX197=m
# CONFIG_SENSORS_MAX31722 is not set
+# CONFIG_SENSORS_MAX31730 is not set
# CONFIG_SENSORS_MAX6621 is not set
CONFIG_SENSORS_MAX6639=m
CONFIG_SENSORS_MAX6642=m
@@ -4041,6 +4364,8 @@ CONFIG_SENSORS_MAX6697=m
CONFIG_SENSORS_MAX31790=m
CONFIG_SENSORS_MCP3021=m
CONFIG_SENSORS_TC654=m
+# CONFIG_SENSORS_TPS23861 is not set
+# CONFIG_SENSORS_MR75203 is not set
# CONFIG_SENSORS_ADCXX is not set
CONFIG_SENSORS_LM63=m
# CONFIG_SENSORS_LM70 is not set
@@ -4064,35 +4389,55 @@ CONFIG_SENSORS_NTC_THERMISTOR=m
CONFIG_SENSORS_NCT6683=m
CONFIG_SENSORS_NCT6775=m
CONFIG_SENSORS_NCT7802=m
-CONFIG_SENSORS_NCT7904=m
# CONFIG_SENSORS_NPCM7XX is not set
+# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
CONFIG_SENSORS_PCF8591=m
CONFIG_PMBUS=m
CONFIG_SENSORS_PMBUS=m
+# CONFIG_SENSORS_ADM1266 is not set
# CONFIG_SENSORS_ADM1275 is not set
+# CONFIG_SENSORS_BEL_PFE is not set
+# CONFIG_SENSORS_BPA_RS600 is not set
+# CONFIG_SENSORS_FSP_3Y is not set
# CONFIG_SENSORS_IBM_CFFPS is not set
+# CONFIG_SENSORS_DPS920AB is not set
# CONFIG_SENSORS_INSPUR_IPSPS is not set
# CONFIG_SENSORS_IR35221 is not set
+# CONFIG_SENSORS_IR36021 is not set
# CONFIG_SENSORS_IR38064 is not set
# CONFIG_SENSORS_IRPS5401 is not set
# CONFIG_SENSORS_ISL68137 is not set
# CONFIG_SENSORS_LM25066 is not set
# CONFIG_SENSORS_LTC2978 is not set
# CONFIG_SENSORS_LTC3815 is not set
+# CONFIG_SENSORS_MAX15301 is not set
# CONFIG_SENSORS_MAX16064 is not set
+# CONFIG_SENSORS_MAX16601 is not set
+# CONFIG_SENSORS_MAX20730 is not set
# CONFIG_SENSORS_MAX20751 is not set
# CONFIG_SENSORS_MAX31785 is not set
# CONFIG_SENSORS_MAX34440 is not set
# CONFIG_SENSORS_MAX8688 is not set
+# CONFIG_SENSORS_MP2888 is not set
+# CONFIG_SENSORS_MP2975 is not set
+# CONFIG_SENSORS_PIM4328 is not set
+# CONFIG_SENSORS_PM6764TR is not set
# CONFIG_SENSORS_PXE1610 is not set
+# CONFIG_SENSORS_Q54SJ108A2 is not set
+# CONFIG_SENSORS_STPDDC60 is not set
# CONFIG_SENSORS_TPS40422 is not set
# CONFIG_SENSORS_TPS53679 is not set
# CONFIG_SENSORS_UCD9000 is not set
# CONFIG_SENSORS_UCD9200 is not set
+# CONFIG_SENSORS_XDPE122 is not set
# CONFIG_SENSORS_ZL6100 is not set
+# CONFIG_SENSORS_PWM_FAN is not set
+# CONFIG_SENSORS_SBTSI is not set
+# CONFIG_SENSORS_SBRMI is not set
# CONFIG_SENSORS_SHT15 is not set
CONFIG_SENSORS_SHT21=m
CONFIG_SENSORS_SHT3x=m
+# CONFIG_SENSORS_SHT4x is not set
CONFIG_SENSORS_SHTC1=m
CONFIG_SENSORS_SIS5595=m
CONFIG_SENSORS_DME1737=m
@@ -4118,6 +4463,7 @@ CONFIG_SENSORS_TMP103=m
CONFIG_SENSORS_TMP108=m
CONFIG_SENSORS_TMP401=m
CONFIG_SENSORS_TMP421=m
+# CONFIG_SENSORS_TMP513 is not set
CONFIG_SENSORS_VIA_CPUTEMP=m
CONFIG_SENSORS_VIA686A=m
CONFIG_SENSORS_VT1211=m
@@ -4141,6 +4487,7 @@ CONFIG_SENSORS_XGENE=m
CONFIG_SENSORS_ACPI_POWER=m
CONFIG_SENSORS_ATK0110=m
CONFIG_THERMAL=y
+# CONFIG_THERMAL_NETLINK is not set
# CONFIG_THERMAL_STATISTICS is not set
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_HWMON=y
@@ -4149,23 +4496,21 @@ CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
-# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_USER_SPACE=y
# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
# CONFIG_CPU_THERMAL is not set
-# CONFIG_CLOCK_THERMAL is not set
# CONFIG_DEVFREQ_THERMAL is not set
# CONFIG_THERMAL_EMULATION is not set
# CONFIG_THERMAL_MMIO is not set
-# CONFIG_QORIQ_THERMAL is not set
#
# Intel thermal drivers
#
CONFIG_INTEL_POWERCLAMP=m
+CONFIG_X86_THERMAL_VECTOR=y
CONFIG_X86_PKG_TEMP_THERMAL=m
# CONFIG_INTEL_SOC_DTS_THERMAL is not set
@@ -4176,6 +4521,8 @@ CONFIG_X86_PKG_TEMP_THERMAL=m
# end of ACPI INT340X thermal drivers
CONFIG_INTEL_PCH_THERMAL=m
+# CONFIG_INTEL_TCC_COOLING is not set
+CONFIG_INTEL_MENLOW=m
# end of Intel thermal drivers
# CONFIG_WATCHDOG is not set
@@ -4220,18 +4567,24 @@ CONFIG_MFD_CORE=y
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_GATEWORKS_GSC is not set
# CONFIG_MFD_MC13XXX_SPI is not set
# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MP2629 is not set
# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_HI6421_SPMI is not set
# CONFIG_HTC_PASIC3 is not set
CONFIG_MFD_INTEL_QUARK_I2C_GPIO=m
CONFIG_LPC_ICH=y
CONFIG_LPC_SCH=m
-# CONFIG_INTEL_SOC_PMIC_BXTWC is not set
# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set
+# CONFIG_INTEL_SOC_PMIC_MRFLD is not set
CONFIG_MFD_INTEL_LPSS=m
CONFIG_MFD_INTEL_LPSS_ACPI=m
CONFIG_MFD_INTEL_LPSS_PCI=m
+# CONFIG_MFD_INTEL_PMC_BXT is not set
+# CONFIG_MFD_INTEL_PMT is not set
+# CONFIG_MFD_IQS62X is not set
# CONFIG_MFD_JANZ_CMODIO is not set
# CONFIG_MFD_KEMPLD is not set
# CONFIG_MFD_88PM800 is not set
@@ -4241,22 +4594,24 @@ CONFIG_MFD_INTEL_LPSS_PCI=m
# CONFIG_MFD_MAX77686 is not set
# CONFIG_MFD_MAX77693 is not set
# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MT6360 is not set
# CONFIG_MFD_MT6397 is not set
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_EZX_PCAP is not set
# CONFIG_MFD_CPCAP is not set
# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_NTXEC is not set
# CONFIG_MFD_RETU is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_UCB1400_CORE is not set
# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RT4831 is not set
# CONFIG_MFD_RT5033 is not set
# CONFIG_MFD_RK808 is not set
# CONFIG_MFD_RN5T618 is not set
# CONFIG_MFD_SI476X_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_SKY81452 is not set
-# CONFIG_ABX500_CORE is not set
# CONFIG_MFD_STMPE is not set
CONFIG_MFD_SYSCON=y
# CONFIG_MFD_TI_AM335X_TSCADC is not set
@@ -4281,7 +4636,12 @@ CONFIG_MFD_WL1273_CORE=m
# CONFIG_MFD_WM831X_SPI is not set
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_STMFX is not set
+# CONFIG_MFD_ATC260X_I2C is not set
+# CONFIG_MFD_QCOM_PM8008 is not set
# CONFIG_RAVE_SP_CORE is not set
+# CONFIG_MFD_INTEL_M10_BMC is not set
+# CONFIG_MFD_RSMU_I2C is not set
+# CONFIG_MFD_RSMU_SPI is not set
# end of Multifunction device drivers
CONFIG_REGULATOR=y
@@ -4292,10 +4652,11 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_88PG86X is not set
# CONFIG_REGULATOR_ACT8865 is not set
# CONFIG_REGULATOR_AD5398 is not set
-# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9121 is not set
# CONFIG_REGULATOR_DA9210 is not set
# CONFIG_REGULATOR_DA9211 is not set
# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_FAN53880 is not set
# CONFIG_REGULATOR_GPIO is not set
# CONFIG_REGULATOR_ISL9305 is not set
# CONFIG_REGULATOR_ISL6271A is not set
@@ -4308,18 +4669,37 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_MAX1586 is not set
# CONFIG_REGULATOR_MAX8649 is not set
# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8893 is not set
# CONFIG_REGULATOR_MAX8952 is not set
# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_MAX77826 is not set
# CONFIG_REGULATOR_MCP16502 is not set
+# CONFIG_REGULATOR_MP5416 is not set
+# CONFIG_REGULATOR_MP8859 is not set
+# CONFIG_REGULATOR_MP886X is not set
+# CONFIG_REGULATOR_MPQ7920 is not set
# CONFIG_REGULATOR_MT6311 is not set
+# CONFIG_REGULATOR_MT6315 is not set
+# CONFIG_REGULATOR_PCA9450 is not set
+# CONFIG_REGULATOR_PF8X00 is not set
# CONFIG_REGULATOR_PFUZE100 is not set
# CONFIG_REGULATOR_PV88060 is not set
# CONFIG_REGULATOR_PV88080 is not set
# CONFIG_REGULATOR_PV88090 is not set
+# CONFIG_REGULATOR_PWM is not set
# CONFIG_REGULATOR_QCOM_SPMI is not set
+# CONFIG_REGULATOR_QCOM_USB_VBUS is not set
+# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set
+# CONFIG_REGULATOR_RT4801 is not set
+# CONFIG_REGULATOR_RT6160 is not set
+# CONFIG_REGULATOR_RT6245 is not set
+# CONFIG_REGULATOR_RTQ2134 is not set
+# CONFIG_REGULATOR_RTMV20 is not set
+# CONFIG_REGULATOR_RTQ6752 is not set
# CONFIG_REGULATOR_SLG51000 is not set
# CONFIG_REGULATOR_SY8106A is not set
# CONFIG_REGULATOR_SY8824X is not set
+# CONFIG_REGULATOR_SY8827N is not set
# CONFIG_REGULATOR_TPS51632 is not set
# CONFIG_REGULATOR_TPS62360 is not set
# CONFIG_REGULATOR_TPS65023 is not set
@@ -4327,8 +4707,7 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_TPS65132 is not set
# CONFIG_REGULATOR_TPS6524X is not set
# CONFIG_REGULATOR_VCTRL is not set
-CONFIG_CEC_CORE=m
-CONFIG_CEC_NOTIFIER=y
+# CONFIG_REGULATOR_QCOM_LABIBB is not set
CONFIG_RC_CORE=y
CONFIG_RC_MAP=y
# CONFIG_LIRC is not set
@@ -4366,39 +4745,71 @@ CONFIG_IR_SERIAL=m
CONFIG_IR_SERIAL_TRANSMITTER=y
CONFIG_IR_SIR=m
# CONFIG_RC_XBOX_DVD is not set
+# CONFIG_IR_TOY is not set
+CONFIG_CEC_CORE=m
+CONFIG_CEC_NOTIFIER=y
+# CONFIG_MEDIA_CEC_RC is not set
+CONFIG_MEDIA_CEC_SUPPORT=y
+# CONFIG_CEC_CH7322 is not set
+# CONFIG_CEC_SECO is not set
+CONFIG_USB_PULSE8_CEC=m
+CONFIG_USB_RAINSHADOW_CEC=m
CONFIG_MEDIA_SUPPORT=m
+# CONFIG_MEDIA_SUPPORT_FILTER is not set
+CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
#
-# Multimedia core support
+# Media device types
#
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_RADIO_SUPPORT=y
CONFIG_MEDIA_SDR_SUPPORT=y
-CONFIG_MEDIA_CEC_SUPPORT=y
-# CONFIG_MEDIA_CEC_RC is not set
-CONFIG_MEDIA_CONTROLLER=y
-CONFIG_MEDIA_CONTROLLER_DVB=y
+CONFIG_MEDIA_PLATFORM_SUPPORT=y
+CONFIG_MEDIA_TEST_SUPPORT=y
+# end of Media device types
+
+#
+# Media core support
+#
CONFIG_VIDEO_DEV=m
-# CONFIG_VIDEO_V4L2_SUBDEV_API is not set
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_DVB_CORE=m
+# end of Media core support
+
+#
+# Video4Linux options
+#
CONFIG_VIDEO_V4L2=m
CONFIG_VIDEO_V4L2_I2C=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_VIDEO_ADV_DEBUG is not set
# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
CONFIG_VIDEO_TUNER=m
CONFIG_V4L2_FWNODE=m
+CONFIG_V4L2_ASYNC=m
CONFIG_VIDEOBUF_GEN=m
CONFIG_VIDEOBUF_DMA_SG=m
CONFIG_VIDEOBUF_VMALLOC=m
-CONFIG_DVB_CORE=m
+# end of Video4Linux options
+
+#
+# Media controller options
+#
+CONFIG_MEDIA_CONTROLLER_DVB=y
+# end of Media controller options
+
+#
+# Digital TV options
+#
# CONFIG_DVB_MMAP is not set
CONFIG_DVB_NET=y
-CONFIG_TTPCI_EEPROM=m
CONFIG_DVB_MAX_ADAPTERS=16
# CONFIG_DVB_DYNAMIC_MINORS is not set
# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set
# CONFIG_DVB_ULE_DEBUG is not set
+# end of Digital TV options
#
# Media drivers
@@ -4411,55 +4822,55 @@ CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
CONFIG_USB_GSPCA=m
-# CONFIG_USB_M5602 is not set
-# CONFIG_USB_STV06XX is not set
-# CONFIG_USB_GL860 is not set
-# CONFIG_USB_GSPCA_BENQ is not set
-# CONFIG_USB_GSPCA_CONEX is not set
-# CONFIG_USB_GSPCA_CPIA1 is not set
-# CONFIG_USB_GSPCA_DTCS033 is not set
-# CONFIG_USB_GSPCA_ETOMS is not set
-# CONFIG_USB_GSPCA_FINEPIX is not set
-# CONFIG_USB_GSPCA_JEILINJ is not set
-# CONFIG_USB_GSPCA_JL2005BCD is not set
-# CONFIG_USB_GSPCA_KINECT is not set
-# CONFIG_USB_GSPCA_KONICA is not set
-# CONFIG_USB_GSPCA_MARS is not set
-# CONFIG_USB_GSPCA_MR97310A is not set
-# CONFIG_USB_GSPCA_NW80X is not set
-# CONFIG_USB_GSPCA_OV519 is not set
-# CONFIG_USB_GSPCA_OV534 is not set
-# CONFIG_USB_GSPCA_OV534_9 is not set
-# CONFIG_USB_GSPCA_PAC207 is not set
-# CONFIG_USB_GSPCA_PAC7302 is not set
-# CONFIG_USB_GSPCA_PAC7311 is not set
-# CONFIG_USB_GSPCA_SE401 is not set
-# CONFIG_USB_GSPCA_SN9C2028 is not set
-# CONFIG_USB_GSPCA_SN9C20X is not set
-# CONFIG_USB_GSPCA_SONIXB is not set
-# CONFIG_USB_GSPCA_SONIXJ is not set
-# CONFIG_USB_GSPCA_SPCA500 is not set
-# CONFIG_USB_GSPCA_SPCA501 is not set
-# CONFIG_USB_GSPCA_SPCA505 is not set
-# CONFIG_USB_GSPCA_SPCA506 is not set
-# CONFIG_USB_GSPCA_SPCA508 is not set
-# CONFIG_USB_GSPCA_SPCA561 is not set
-# CONFIG_USB_GSPCA_SPCA1528 is not set
-# CONFIG_USB_GSPCA_SQ905 is not set
-# CONFIG_USB_GSPCA_SQ905C is not set
-# CONFIG_USB_GSPCA_SQ930X is not set
-# CONFIG_USB_GSPCA_STK014 is not set
-# CONFIG_USB_GSPCA_STK1135 is not set
-# CONFIG_USB_GSPCA_STV0680 is not set
-# CONFIG_USB_GSPCA_SUNPLUS is not set
-# CONFIG_USB_GSPCA_T613 is not set
-# CONFIG_USB_GSPCA_TOPRO is not set
-# CONFIG_USB_GSPCA_TOUPTEK is not set
-# CONFIG_USB_GSPCA_TV8532 is not set
-# CONFIG_USB_GSPCA_VC032X is not set
-# CONFIG_USB_GSPCA_VICAM is not set
-# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
-# CONFIG_USB_GSPCA_ZC3XX is not set
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
CONFIG_USB_PWC=m
# CONFIG_USB_PWC_DEBUG is not set
CONFIG_USB_PWC_INPUT_EVDEV=y
@@ -4467,7 +4878,7 @@ CONFIG_VIDEO_CPIA2=m
CONFIG_USB_ZR364XX=m
CONFIG_USB_STKWEBCAM=m
CONFIG_USB_S2255=m
-# CONFIG_VIDEO_USBTV is not set
+CONFIG_VIDEO_USBTV=m
#
# Analog TV USB devices
@@ -4477,10 +4888,12 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y
CONFIG_VIDEO_PVRUSB2_DVB=y
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
CONFIG_VIDEO_HDPVR=m
-CONFIG_VIDEO_USBVISION=m
CONFIG_VIDEO_STK1160_COMMON=m
CONFIG_VIDEO_STK1160=m
-# CONFIG_VIDEO_GO7007 is not set
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_LOADER=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
#
# Analog/digital TV USB devices
@@ -4490,10 +4903,10 @@ CONFIG_VIDEO_AU0828_V4L2=y
# CONFIG_VIDEO_AU0828_RC is not set
CONFIG_VIDEO_CX231XX=m
CONFIG_VIDEO_CX231XX_RC=y
-# CONFIG_VIDEO_CX231XX_ALSA is not set
+CONFIG_VIDEO_CX231XX_ALSA=m
CONFIG_VIDEO_CX231XX_DVB=m
CONFIG_VIDEO_TM6000=m
-# CONFIG_VIDEO_TM6000_ALSA is not set
+CONFIG_VIDEO_TM6000_ALSA=m
CONFIG_VIDEO_TM6000_DVB=m
#
@@ -4562,30 +4975,23 @@ CONFIG_VIDEO_EM28XX_RC=m
#
CONFIG_USB_AIRSPY=m
CONFIG_USB_HACKRF=m
-# CONFIG_USB_MSI2500 is not set
-
-#
-# USB HDMI CEC adapters
-#
-CONFIG_USB_PULSE8_CEC=m
-CONFIG_USB_RAINSHADOW_CEC=m
+CONFIG_USB_MSI2500=m
CONFIG_MEDIA_PCI_SUPPORT=y
#
# Media capture support
#
# CONFIG_VIDEO_MEYE is not set
-# CONFIG_VIDEO_SOLO6X10 is not set
+CONFIG_VIDEO_SOLO6X10=m
CONFIG_VIDEO_TW5864=m
CONFIG_VIDEO_TW68=m
-# CONFIG_VIDEO_TW686X is not set
+CONFIG_VIDEO_TW686X=m
#
# Media capture/analog TV support
#
CONFIG_VIDEO_IVTV=m
-# CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS is not set
-# CONFIG_VIDEO_IVTV_ALSA is not set
+CONFIG_VIDEO_IVTV_ALSA=m
# CONFIG_VIDEO_FB_IVTV is not set
CONFIG_VIDEO_HEXIUM_GEMINI=m
CONFIG_VIDEO_HEXIUM_ORION=m
@@ -4613,19 +5019,16 @@ CONFIG_VIDEO_SAA7134=m
# CONFIG_VIDEO_SAA7134_ALSA is not set
CONFIG_VIDEO_SAA7134_RC=y
CONFIG_VIDEO_SAA7134_DVB=m
+# CONFIG_VIDEO_SAA7134_GO7007 is not set
CONFIG_VIDEO_SAA7164=m
#
# Media digital TV PCI Adapters
#
-CONFIG_DVB_AV7110_IR=y
-CONFIG_DVB_AV7110=m
-CONFIG_DVB_AV7110_OSD=y
CONFIG_DVB_BUDGET_CORE=m
CONFIG_DVB_BUDGET=m
CONFIG_DVB_BUDGET_CI=m
CONFIG_DVB_BUDGET_AV=m
-CONFIG_DVB_BUDGET_PATCH=m
CONFIG_DVB_B2C2_FLEXCOP_PCI=m
# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set
CONFIG_DVB_PLUTO2=m
@@ -4639,25 +5042,14 @@ CONFIG_DVB_NGENE=m
CONFIG_DVB_DDBRIDGE=m
# CONFIG_DVB_DDBRIDGE_MSIENABLE is not set
CONFIG_DVB_SMIPCIE=m
-# CONFIG_DVB_NETUP_UNIDVB is not set
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_CAFE_CCIC=m
-# CONFIG_VIDEO_CADENCE is not set
-# CONFIG_VIDEO_ASPEED is not set
-# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-# CONFIG_V4L_TEST_DRIVERS is not set
-CONFIG_DVB_PLATFORM_DRIVERS=y
-CONFIG_CEC_PLATFORM_DRIVERS=y
-# CONFIG_VIDEO_SECO_CEC is not set
-CONFIG_SDR_PLATFORM_DRIVERS=y
-
-#
-# Supported MMC/SDIO adapters
-#
-# CONFIG_SMS_SDIO_DRV is not set
+CONFIG_DVB_NETUP_UNIDVB=m
+CONFIG_VIDEO_IPU3_CIO2=m
+# CONFIG_CIO2_BRIDGE is not set
CONFIG_RADIO_ADAPTERS=y
CONFIG_RADIO_TEA575X=m
-# CONFIG_RADIO_SI470X is not set
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
CONFIG_RADIO_SI4713=m
CONFIG_USB_SI4713=m
CONFIG_PLATFORM_SI4713=m
@@ -4674,17 +5066,6 @@ CONFIG_RADIO_TEA5764=m
CONFIG_RADIO_SAA7706H=m
CONFIG_RADIO_TEF6862=m
CONFIG_RADIO_WL1273=m
-
-#
-# Texas Instruments WL128x FM driver (ST based)
-#
-# end of Texas Instruments WL128x FM driver (ST based)
-
-#
-# Supported FireWire (IEEE 1394) Adapters
-#
-CONFIG_DVB_FIREDTV=m
-CONFIG_DVB_FIREDTV_INPUT=y
CONFIG_MEDIA_COMMON_OPTIONS=y
#
@@ -4692,6 +5073,7 @@ CONFIG_MEDIA_COMMON_OPTIONS=y
#
CONFIG_VIDEO_CX2341X=m
CONFIG_VIDEO_TVEEPROM=m
+CONFIG_TTPCI_EEPROM=m
CONFIG_CYPRESS_FIRMWARE=m
CONFIG_VIDEOBUF2_CORE=m
CONFIG_VIDEOBUF2_V4L2=m
@@ -4705,17 +5087,39 @@ CONFIG_VIDEO_SAA7146=m
CONFIG_VIDEO_SAA7146_VV=m
CONFIG_SMS_SIANO_MDTV=m
CONFIG_SMS_SIANO_RC=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_CAFE_CCIC=m
+# CONFIG_VIDEO_CADENCE is not set
+CONFIG_VIDEO_ASPEED=m
+CONFIG_VIDEO_MUX=m
+# CONFIG_VIDEO_XILINX is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+CONFIG_DVB_PLATFORM_DRIVERS=y
+CONFIG_SDR_PLATFORM_DRIVERS=y
#
-# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
+# MMC/SDIO DVB adapters
+#
+# CONFIG_SMS_SDIO_DRV is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_DVB_TEST_DRIVERS is not set
+
+#
+# FireWire (IEEE 1394) Adapters
+#
+CONFIG_DVB_FIREDTV=m
+CONFIG_DVB_FIREDTV_INPUT=y
+# end of Media drivers
+
+#
+# Media ancillary drivers
#
-CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
CONFIG_MEDIA_ATTACH=y
-CONFIG_VIDEO_IR_I2C=m
#
-# I2C Encoders, decoders, sensors and other helper chips
+# IR I2C driver auto-selected by 'Autoselect ancillary drivers'
#
+CONFIG_VIDEO_IR_I2C=m
#
# Audio decoders, processors and mixers
@@ -4726,46 +5130,58 @@ CONFIG_VIDEO_TDA9840=m
CONFIG_VIDEO_TEA6415C=m
CONFIG_VIDEO_TEA6420=m
CONFIG_VIDEO_MSP3400=m
-# CONFIG_VIDEO_CS3308 is not set
+CONFIG_VIDEO_CS3308=m
CONFIG_VIDEO_CS5345=m
CONFIG_VIDEO_CS53L32A=m
-# CONFIG_VIDEO_TLV320AIC23B is not set
-# CONFIG_VIDEO_UDA1342 is not set
+CONFIG_VIDEO_TLV320AIC23B=m
+CONFIG_VIDEO_UDA1342=m
CONFIG_VIDEO_WM8775=m
CONFIG_VIDEO_WM8739=m
CONFIG_VIDEO_VP27SMPX=m
-# CONFIG_VIDEO_SONY_BTF_MPX is not set
+CONFIG_VIDEO_SONY_BTF_MPX=m
+# end of Audio decoders, processors and mixers
#
# RDS decoders
#
CONFIG_VIDEO_SAA6588=m
+# end of RDS decoders
#
# Video decoders
#
-# CONFIG_VIDEO_ADV7183 is not set
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_ADV7183=m
+CONFIG_VIDEO_ADV748X=m
+CONFIG_VIDEO_ADV7604=m
+# CONFIG_VIDEO_ADV7604_CEC is not set
+CONFIG_VIDEO_ADV7842=m
+# CONFIG_VIDEO_ADV7842_CEC is not set
CONFIG_VIDEO_BT819=m
CONFIG_VIDEO_BT856=m
CONFIG_VIDEO_BT866=m
CONFIG_VIDEO_KS0127=m
-# CONFIG_VIDEO_ML86V7667 is not set
+CONFIG_VIDEO_ML86V7667=m
CONFIG_VIDEO_SAA7110=m
CONFIG_VIDEO_SAA711X=m
-# CONFIG_VIDEO_TVP514X is not set
+CONFIG_VIDEO_TC358743=m
+# CONFIG_VIDEO_TC358743_CEC is not set
+CONFIG_VIDEO_TVP514X=m
CONFIG_VIDEO_TVP5150=m
-# CONFIG_VIDEO_TVP7002 is not set
-# CONFIG_VIDEO_TW2804 is not set
-# CONFIG_VIDEO_TW9903 is not set
-# CONFIG_VIDEO_TW9906 is not set
-# CONFIG_VIDEO_TW9910 is not set
+CONFIG_VIDEO_TVP7002=m
+CONFIG_VIDEO_TW2804=m
+CONFIG_VIDEO_TW9903=m
+CONFIG_VIDEO_TW9906=m
+CONFIG_VIDEO_TW9910=m
CONFIG_VIDEO_VPX3220=m
+CONFIG_VIDEO_MAX9286=m
#
# Video and audio decoders
#
CONFIG_VIDEO_SAA717X=m
CONFIG_VIDEO_CX25840=m
+# end of Video decoders
#
# Video encoders
@@ -4774,37 +5190,116 @@ CONFIG_VIDEO_SAA7127=m
CONFIG_VIDEO_SAA7185=m
CONFIG_VIDEO_ADV7170=m
CONFIG_VIDEO_ADV7175=m
-# CONFIG_VIDEO_ADV7343 is not set
-# CONFIG_VIDEO_ADV7393 is not set
-# CONFIG_VIDEO_AK881X is not set
-# CONFIG_VIDEO_THS8200 is not set
+CONFIG_VIDEO_ADV7343=m
+CONFIG_VIDEO_ADV7393=m
+CONFIG_VIDEO_AD9389B=m
+CONFIG_VIDEO_AK881X=m
+CONFIG_VIDEO_THS8200=m
+# end of Video encoders
+
+#
+# Video improvement chips
+#
+CONFIG_VIDEO_UPD64031A=m
+CONFIG_VIDEO_UPD64083=m
+# end of Video improvement chips
+
+#
+# Audio/Video compression chips
+#
+CONFIG_VIDEO_SAA6752HS=m
+# end of Audio/Video compression chips
+
+#
+# SDR tuner chips
+#
+CONFIG_SDR_MAX2175=m
+# end of SDR tuner chips
+
+#
+# Miscellaneous helper chips
+#
+CONFIG_VIDEO_THS7303=m
+CONFIG_VIDEO_M52790=m
+CONFIG_VIDEO_I2C=m
+CONFIG_VIDEO_ST_MIPID02=m
+# end of Miscellaneous helper chips
#
# Camera sensor devices
#
+# CONFIG_VIDEO_HI556 is not set
+# CONFIG_VIDEO_IMX208 is not set
+# CONFIG_VIDEO_IMX214 is not set
+# CONFIG_VIDEO_IMX219 is not set
+# CONFIG_VIDEO_IMX258 is not set
+# CONFIG_VIDEO_IMX274 is not set
+# CONFIG_VIDEO_IMX290 is not set
+# CONFIG_VIDEO_IMX319 is not set
+# CONFIG_VIDEO_IMX334 is not set
+# CONFIG_VIDEO_IMX335 is not set
+# CONFIG_VIDEO_IMX355 is not set
+# CONFIG_VIDEO_IMX412 is not set
+# CONFIG_VIDEO_OV02A10 is not set
CONFIG_VIDEO_OV2640=m
# CONFIG_VIDEO_OV2659 is not set
# CONFIG_VIDEO_OV2680 is not set
# CONFIG_VIDEO_OV2685 is not set
+# CONFIG_VIDEO_OV2740 is not set
+# CONFIG_VIDEO_OV5640 is not set
+# CONFIG_VIDEO_OV5645 is not set
+# CONFIG_VIDEO_OV5647 is not set
+# CONFIG_VIDEO_OV5648 is not set
# CONFIG_VIDEO_OV6650 is not set
+# CONFIG_VIDEO_OV5670 is not set
+# CONFIG_VIDEO_OV5675 is not set
# CONFIG_VIDEO_OV5695 is not set
+# CONFIG_VIDEO_OV7251 is not set
# CONFIG_VIDEO_OV772X is not set
-# CONFIG_VIDEO_OV7640 is not set
+CONFIG_VIDEO_OV7640=m
CONFIG_VIDEO_OV7670=m
# CONFIG_VIDEO_OV7740 is not set
+# CONFIG_VIDEO_OV8856 is not set
+# CONFIG_VIDEO_OV8865 is not set
+# CONFIG_VIDEO_OV9282 is not set
# CONFIG_VIDEO_OV9640 is not set
+# CONFIG_VIDEO_OV9650 is not set
+# CONFIG_VIDEO_OV9734 is not set
+# CONFIG_VIDEO_OV13858 is not set
# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_MT9M001 is not set
+# CONFIG_VIDEO_MT9M032 is not set
# CONFIG_VIDEO_MT9M111 is not set
+# CONFIG_VIDEO_MT9P031 is not set
+# CONFIG_VIDEO_MT9T001 is not set
# CONFIG_VIDEO_MT9T112 is not set
CONFIG_VIDEO_MT9V011=m
+# CONFIG_VIDEO_MT9V032 is not set
# CONFIG_VIDEO_MT9V111 is not set
# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_M5MOLS is not set
+# CONFIG_VIDEO_RDACM20 is not set
+# CONFIG_VIDEO_RDACM21 is not set
# CONFIG_VIDEO_RJ54N1 is not set
+# CONFIG_VIDEO_S5K6AA is not set
+# CONFIG_VIDEO_S5K6A3 is not set
+# CONFIG_VIDEO_S5K4ECGX is not set
+# CONFIG_VIDEO_S5K5BAF is not set
+# CONFIG_VIDEO_CCS is not set
+# CONFIG_VIDEO_ET8EK8 is not set
+# CONFIG_VIDEO_S5C73M3 is not set
+# end of Camera sensor devices
#
# Lens drivers
#
# CONFIG_VIDEO_AD5820 is not set
+# CONFIG_VIDEO_AK7375 is not set
+# CONFIG_VIDEO_DW9714 is not set
+# CONFIG_VIDEO_DW9768 is not set
+# CONFIG_VIDEO_DW9807_VCM is not set
+# end of Lens drivers
#
# Flash devices
@@ -4812,34 +5307,12 @@ CONFIG_VIDEO_MT9V011=m
# CONFIG_VIDEO_ADP1653 is not set
# CONFIG_VIDEO_LM3560 is not set
# CONFIG_VIDEO_LM3646 is not set
-
-#
-# Video improvement chips
-#
-CONFIG_VIDEO_UPD64031A=m
-CONFIG_VIDEO_UPD64083=m
-
-#
-# Audio/Video compression chips
-#
-CONFIG_VIDEO_SAA6752HS=m
-
-#
-# SDR tuner chips
-#
-# CONFIG_SDR_MAX2175 is not set
-
-#
-# Miscellaneous helper chips
-#
-# CONFIG_VIDEO_THS7303 is not set
-CONFIG_VIDEO_M52790=m
-# CONFIG_VIDEO_I2C is not set
-# end of I2C Encoders, decoders, sensors and other helper chips
+# end of Flash devices
#
# SPI helper chips
#
+# CONFIG_VIDEO_GS1662 is not set
# end of SPI helper chips
#
@@ -4861,7 +5334,7 @@ CONFIG_MEDIA_TUNER_TDA18271=m
CONFIG_MEDIA_TUNER_TDA9887=m
CONFIG_MEDIA_TUNER_TEA5761=m
CONFIG_MEDIA_TUNER_TEA5767=m
-# CONFIG_MEDIA_TUNER_MSI001 is not set
+CONFIG_MEDIA_TUNER_MSI001=m
CONFIG_MEDIA_TUNER_MT20XX=m
CONFIG_MEDIA_TUNER_MT2060=m
CONFIG_MEDIA_TUNER_MT2063=m
@@ -4951,7 +5424,6 @@ CONFIG_DVB_TDA10071=m
#
# DVB-T (terrestrial) frontends
#
-CONFIG_DVB_SP8870=m
CONFIG_DVB_SP887X=m
CONFIG_DVB_CX22700=m
CONFIG_DVB_CX22702=m
@@ -5006,6 +5478,7 @@ CONFIG_DVB_AU8522=m
CONFIG_DVB_AU8522_DTV=m
CONFIG_DVB_AU8522_V4L=m
CONFIG_DVB_S5H1411=m
+CONFIG_DVB_MXL692=m
#
# ISDB-T (terrestrial) frontends
@@ -5046,21 +5519,22 @@ CONFIG_DVB_TDA665x=m
CONFIG_DVB_IX2505V=m
CONFIG_DVB_M88RS2000=m
CONFIG_DVB_AF9033=m
-# CONFIG_DVB_HORUS3A is not set
-# CONFIG_DVB_ASCOT2E is not set
-# CONFIG_DVB_HELENE is not set
+CONFIG_DVB_HORUS3A=m
+CONFIG_DVB_ASCOT2E=m
+CONFIG_DVB_HELENE=m
#
# Common Interface (EN50221) controller drivers
#
CONFIG_DVB_CXD2099=m
CONFIG_DVB_SP2=m
+# end of Customise DVB Frontends
#
# Tools to develop new frontends
#
CONFIG_DVB_DUMMY_FE=m
-# end of Customise DVB Frontends
+# end of Media ancillary drivers
#
# Graphics support
@@ -5076,10 +5550,11 @@ CONFIG_VGA_ARB_MAX_GPUS=16
CONFIG_VGA_SWITCHEROO=y
CONFIG_DRM=m
CONFIG_DRM_MIPI_DSI=y
+CONFIG_DRM_DP_AUX_BUS=m
# CONFIG_DRM_DP_AUX_CHARDEV is not set
# CONFIG_DRM_DEBUG_SELFTEST is not set
CONFIG_DRM_KMS_HELPER=m
-CONFIG_DRM_KMS_FB_HELPER=y
+# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
@@ -5087,6 +5562,7 @@ CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_DP_CEC is not set
CONFIG_DRM_TTM=m
CONFIG_DRM_VRAM_HELPER=m
+CONFIG_DRM_TTM_HELPER=m
CONFIG_DRM_GEM_CMA_HELPER=y
CONFIG_DRM_KMS_CMA_HELPER=y
CONFIG_DRM_GEM_SHMEM_HELPER=y
@@ -5113,7 +5589,6 @@ CONFIG_DRM_AMDGPU=m
CONFIG_DRM_AMDGPU_SI=y
CONFIG_DRM_AMDGPU_CIK=y
CONFIG_DRM_AMDGPU_USERPTR=y
-# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set
#
# ACP (Audio CoProcessor) Configuration
@@ -5125,11 +5600,10 @@ CONFIG_DRM_AMD_ACP=y
# Display Engine Configuration
#
CONFIG_DRM_AMD_DC=y
-CONFIG_DRM_AMD_DC_DCN1_0=y
-CONFIG_DRM_AMD_DC_DCN2_0=y
-# CONFIG_DRM_AMD_DC_DCN2_1 is not set
-CONFIG_DRM_AMD_DC_DSC_SUPPORT=y
-# CONFIG_DEBUG_KERNEL_DC is not set
+CONFIG_DRM_AMD_DC_DCN=y
+# CONFIG_DRM_AMD_DC_HDCP is not set
+# CONFIG_DRM_AMD_DC_SI is not set
+# CONFIG_DRM_AMD_SECURE_DISPLAY is not set
# end of Display Engine Configuration
# CONFIG_HSA_AMD is not set
@@ -5138,9 +5612,9 @@ CONFIG_DRM_NOUVEAU=m
CONFIG_NOUVEAU_DEBUG=5
CONFIG_NOUVEAU_DEBUG_DEFAULT=3
# CONFIG_NOUVEAU_DEBUG_MMU is not set
+# CONFIG_NOUVEAU_DEBUG_PUSH is not set
CONFIG_DRM_NOUVEAU_BACKLIGHT=y
CONFIG_DRM_I915=m
-# CONFIG_DRM_I915_ALPHA_SUPPORT is not set
CONFIG_DRM_I915_FORCE_PROBE=""
CONFIG_DRM_I915_CAPTURE_ERROR=y
CONFIG_DRM_I915_COMPRESS_ERROR=y
@@ -5165,45 +5639,63 @@ CONFIG_DRM_I915_USERPTR=y
#
# drm/i915 Profile Guided Optimisation
#
+CONFIG_DRM_I915_REQUEST_TIMEOUT=20000
+CONFIG_DRM_I915_FENCE_TIMEOUT=10000
CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250
-CONFIG_DRM_I915_SPIN_REQUEST=5
+CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500
+CONFIG_DRM_I915_PREEMPT_TIMEOUT=640
+CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000
+CONFIG_DRM_I915_STOP_TIMEOUT=100
+CONFIG_DRM_I915_TIMESLICE_DURATION=1
# end of drm/i915 Profile Guided Optimisation
CONFIG_DRM_VGEM=m
# CONFIG_DRM_VKMS is not set
CONFIG_DRM_VMWGFX=m
# CONFIG_DRM_VMWGFX_FBCON is not set
+# CONFIG_DRM_VMWGFX_MKSSTATS is not set
CONFIG_DRM_GMA500=m
-CONFIG_DRM_GMA600=y
-CONFIG_DRM_GMA3600=y
CONFIG_DRM_UDL=m
CONFIG_DRM_AST=m
CONFIG_DRM_MGAG200=m
-CONFIG_DRM_CIRRUS_QEMU=m
CONFIG_DRM_RCAR_DW_HDMI=m
-# CONFIG_DRM_RCAR_LVDS is not set
+CONFIG_DRM_RCAR_LVDS=m
CONFIG_DRM_QXL=m
-CONFIG_DRM_BOCHS=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_PANEL=y
#
# Display Panels
#
+# CONFIG_DRM_PANEL_ABT_Y030XX067A is not set
# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
+# CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596 is not set
+# CONFIG_DRM_PANEL_BOE_HIMAX8279D is not set
+# CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set
+# CONFIG_DRM_PANEL_DSI_CM is not set
CONFIG_DRM_PANEL_LVDS=m
CONFIG_DRM_PANEL_SIMPLE=m
+# CONFIG_DRM_PANEL_ELIDA_KD35T133 is not set
+# CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02 is not set
# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set
# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set
+# CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set
# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set
+# CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set
CONFIG_DRM_PANEL_INNOLUX_P079ZCA=m
CONFIG_DRM_PANEL_JDI_LT070ME05000=m
+# CONFIG_DRM_PANEL_KHADAS_TS050 is not set
# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set
+# CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W is not set
+# CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829 is not set
# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
# CONFIG_DRM_PANEL_LG_LB035Q02 is not set
# CONFIG_DRM_PANEL_LG_LG4573 is not set
# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set
+# CONFIG_DRM_PANEL_NOVATEK_NT35510 is not set
+# CONFIG_DRM_PANEL_NOVATEK_NT36672A is not set
# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set
+# CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set
# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set
# CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set
@@ -5211,24 +5703,33 @@ CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00=m
# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set
# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set
-# CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set
# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_DB7430 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set
CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2=m
# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
+# CONFIG_DRM_PANEL_SAMSUNG_SOFEF00 is not set
# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set
CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m
# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
CONFIG_DRM_PANEL_SHARP_LS043T1LE01=m
# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set
+# CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set
# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set
+# CONFIG_DRM_PANEL_SONY_ACX424AKP is not set
# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set
+# CONFIG_DRM_PANEL_TDO_TL070WSH30 is not set
# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set
# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set
# CONFIG_DRM_PANEL_TPO_TPG110 is not set
# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set
+# CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set
+# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set
+# CONFIG_DRM_PANEL_XINPENG_XPP055C272 is not set
# end of Display Panels
CONFIG_DRM_BRIDGE=y
@@ -5237,43 +5738,66 @@ CONFIG_DRM_PANEL_BRIDGE=y
#
# Display Interface Bridges
#
-CONFIG_DRM_ANALOGIX_ANX78XX=m
# CONFIG_DRM_CDNS_DSI is not set
-CONFIG_DRM_DUMB_VGA_DAC=m
-CONFIG_DRM_LVDS_ENCODER=m
+# CONFIG_DRM_CHIPONE_ICN6211 is not set
+# CONFIG_DRM_CHRONTEL_CH7033 is not set
+# CONFIG_DRM_DISPLAY_CONNECTOR is not set
+# CONFIG_DRM_LONTIUM_LT8912B is not set
+# CONFIG_DRM_LONTIUM_LT9611 is not set
+# CONFIG_DRM_LONTIUM_LT9611UXC is not set
+# CONFIG_DRM_ITE_IT66121 is not set
+# CONFIG_DRM_LVDS_CODEC is not set
CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW=m
+# CONFIG_DRM_NWL_MIPI_DSI is not set
CONFIG_DRM_NXP_PTN3460=m
CONFIG_DRM_PARADE_PS8622=m
+# CONFIG_DRM_PARADE_PS8640 is not set
CONFIG_DRM_SIL_SII8620=m
CONFIG_DRM_SII902X=m
# CONFIG_DRM_SII9234 is not set
+# CONFIG_DRM_SIMPLE_BRIDGE is not set
# CONFIG_DRM_THINE_THC63LVD1024 is not set
+# CONFIG_DRM_TOSHIBA_TC358762 is not set
# CONFIG_DRM_TOSHIBA_TC358764 is not set
CONFIG_DRM_TOSHIBA_TC358767=m
+# CONFIG_DRM_TOSHIBA_TC358768 is not set
+# CONFIG_DRM_TOSHIBA_TC358775 is not set
CONFIG_DRM_TI_TFP410=m
+# CONFIG_DRM_TI_SN65DSI83 is not set
# CONFIG_DRM_TI_SN65DSI86 is not set
+# CONFIG_DRM_TI_TPD12S015 is not set
+# CONFIG_DRM_ANALOGIX_ANX6345 is not set
+CONFIG_DRM_ANALOGIX_ANX78XX=m
+CONFIG_DRM_ANALOGIX_DP=m
+# CONFIG_DRM_ANALOGIX_ANX7625 is not set
CONFIG_DRM_I2C_ADV7511=m
-CONFIG_DRM_I2C_ADV7533=y
CONFIG_DRM_I2C_ADV7511_CEC=y
+# CONFIG_DRM_CDNS_MHDP8546 is not set
CONFIG_DRM_DW_HDMI=m
# CONFIG_DRM_DW_HDMI_AHB_AUDIO is not set
CONFIG_DRM_DW_HDMI_CEC=m
# end of Display Interface Bridges
# CONFIG_DRM_ETNAVIV is not set
-CONFIG_DRM_ARCPGU=m
CONFIG_DRM_MXS=y
CONFIG_DRM_MXSFB=m
-# CONFIG_DRM_GM12U320 is not set
+CONFIG_DRM_ARCPGU=m
+CONFIG_DRM_BOCHS=m
+CONFIG_DRM_CIRRUS_QEMU=m
+CONFIG_DRM_GM12U320=m
+CONFIG_DRM_SIMPLEDRM=m
# CONFIG_TINYDRM_HX8357D is not set
# CONFIG_TINYDRM_ILI9225 is not set
# CONFIG_TINYDRM_ILI9341 is not set
+# CONFIG_TINYDRM_ILI9486 is not set
# CONFIG_TINYDRM_MI0283QT is not set
# CONFIG_TINYDRM_REPAPER is not set
# CONFIG_TINYDRM_ST7586 is not set
# CONFIG_TINYDRM_ST7735R is not set
-# CONFIG_DRM_XEN is not set
-# CONFIG_DRM_VBOXVIDEO is not set
+# CONFIG_DRM_XEN_FRONTEND is not set
+CONFIG_DRM_VBOXVIDEO=m
+CONFIG_DRM_GUD=m
+# CONFIG_DRM_HYPERV is not set
# CONFIG_DRM_LEGACY is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
@@ -5334,7 +5858,8 @@ CONFIG_FB_MATROX=m
CONFIG_FB_MATROX_MILLENIUM=y
CONFIG_FB_MATROX_MYSTIQUE=y
CONFIG_FB_MATROX_G=y
-# CONFIG_FB_MATROX_I2C is not set
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
CONFIG_FB_RADEON=m
CONFIG_FB_RADEON_I2C=y
CONFIG_FB_RADEON_BACKLIGHT=y
@@ -5377,9 +5902,9 @@ CONFIG_FB_METRONOME=m
CONFIG_FB_MB862XX=m
CONFIG_FB_MB862XX_PCI_GDC=y
CONFIG_FB_MB862XX_I2C=y
-# CONFIG_FB_HYPERV is not set
-CONFIG_FB_SIMPLE=y
-# CONFIG_FB_SSD1307 is not set
+CONFIG_FB_HYPERV=m
+CONFIG_FB_SIMPLE=m
+CONFIG_FB_SSD1307=m
CONFIG_FB_SM712=m
# end of Frame buffer Devices
@@ -5387,31 +5912,35 @@ CONFIG_FB_SM712=m
# Backlight & LCD device support
#
CONFIG_LCD_CLASS_DEVICE=m
-# CONFIG_LCD_L4F00242T03 is not set
-# CONFIG_LCD_LMS283GF05 is not set
-# CONFIG_LCD_LTV350QV is not set
-# CONFIG_LCD_ILI922X is not set
-# CONFIG_LCD_ILI9320 is not set
-# CONFIG_LCD_TDO24M is not set
-# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_L4F00242T03=m
+CONFIG_LCD_LMS283GF05=m
+CONFIG_LCD_LTV350QV=m
+CONFIG_LCD_ILI922X=m
+CONFIG_LCD_ILI9320=m
+CONFIG_LCD_TDO24M=m
+CONFIG_LCD_VGG2432A4=m
CONFIG_LCD_PLATFORM=m
-# CONFIG_LCD_AMS369FG06 is not set
-# CONFIG_LCD_LMS501KF03 is not set
-# CONFIG_LCD_HX8357 is not set
-# CONFIG_LCD_OTM3225A is not set
+CONFIG_LCD_AMS369FG06=m
+CONFIG_LCD_LMS501KF03=m
+CONFIG_LCD_HX8357=m
+CONFIG_LCD_OTM3225A=m
CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_GENERIC=m
+CONFIG_BACKLIGHT_KTD253=m
CONFIG_BACKLIGHT_CARILLO_RANCH=m
+# CONFIG_BACKLIGHT_PWM is not set
CONFIG_BACKLIGHT_APPLE=m
-CONFIG_BACKLIGHT_PM8941_WLED=m
+CONFIG_BACKLIGHT_QCOM_WLED=m
CONFIG_BACKLIGHT_SAHARA=m
CONFIG_BACKLIGHT_ADP8860=m
CONFIG_BACKLIGHT_ADP8870=m
+# CONFIG_BACKLIGHT_LM3630A is not set
CONFIG_BACKLIGHT_LM3639=m
+# CONFIG_BACKLIGHT_LP855X is not set
# CONFIG_BACKLIGHT_GPIO is not set
CONFIG_BACKLIGHT_LV5207LP=m
CONFIG_BACKLIGHT_BD6107=m
CONFIG_BACKLIGHT_ARCXCNN=m
+# CONFIG_BACKLIGHT_LED is not set
# end of Backlight & LCD device support
CONFIG_VGASTATE=m
@@ -5463,6 +5992,7 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
CONFIG_SND_DMA_SGBUF=y
+CONFIG_SND_CTL_LED=m
CONFIG_SND_SEQUENCER=m
# CONFIG_SND_SEQ_DUMMY is not set
CONFIG_SND_SEQUENCER_OSS=m
@@ -5477,9 +6007,10 @@ CONFIG_SND_OPL3_LIB_SEQ=m
CONFIG_SND_VX_LIB=m
CONFIG_SND_AC97_CODEC=m
CONFIG_SND_DRIVERS=y
+# CONFIG_SND_PCSP is not set
# CONFIG_SND_DUMMY is not set
CONFIG_SND_ALOOP=m
-# CONFIG_SND_VIRMIDI is not set
+CONFIG_SND_VIRMIDI=m
CONFIG_SND_MTPAV=m
CONFIG_SND_MTS64=m
CONFIG_SND_SERIAL_U16550=m
@@ -5565,8 +6096,8 @@ CONFIG_SND_YMFPCI=m
# HD-Audio
#
CONFIG_SND_HDA=m
+CONFIG_SND_HDA_GENERIC_LEDS=y
CONFIG_SND_HDA_INTEL=m
-# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set
# CONFIG_SND_HDA_HWDEP is not set
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
@@ -5578,6 +6109,7 @@ CONFIG_SND_HDA_CODEC_SIGMATEL=m
CONFIG_SND_HDA_CODEC_VIA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_HDA_CODEC_CIRRUS=m
+# CONFIG_SND_HDA_CODEC_CS8409 is not set
CONFIG_SND_HDA_CODEC_CONEXANT=m
CONFIG_SND_HDA_CODEC_CA0110=m
CONFIG_SND_HDA_CODEC_CA0132=m
@@ -5586,13 +6118,16 @@ CONFIG_SND_HDA_CODEC_CMEDIA=m
CONFIG_SND_HDA_CODEC_SI3054=m
CONFIG_SND_HDA_GENERIC=m
CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set
# end of HD-Audio
CONFIG_SND_HDA_CORE=m
CONFIG_SND_HDA_COMPONENT=y
CONFIG_SND_HDA_I915=y
-CONFIG_SND_HDA_PREALLOC_SIZE=64
-CONFIG_SND_INTEL_NHLT=m
+CONFIG_SND_HDA_PREALLOC_SIZE=0
+CONFIG_SND_INTEL_NHLT=y
+CONFIG_SND_INTEL_DSP_CONFIG=m
+CONFIG_SND_INTEL_SOUNDWIRE_ACPI=m
CONFIG_SND_SPI=y
CONFIG_SND_USB=y
CONFIG_SND_USB_AUDIO=m
@@ -5629,6 +6164,7 @@ CONFIG_SND_X86=y
CONFIG_HDMI_LPE_AUDIO=m
CONFIG_SND_SYNTH_EMUX=m
# CONFIG_SND_XEN_FRONTEND is not set
+# CONFIG_SND_VIRTIO is not set
CONFIG_AC97_BUS=m
#
@@ -5653,16 +6189,16 @@ CONFIG_HID_ASUS=m
CONFIG_HID_AUREAL=m
CONFIG_HID_BELKIN=y
CONFIG_HID_BETOP_FF=m
-# CONFIG_HID_BIGBEN_FF is not set
+CONFIG_HID_BIGBEN_FF=m
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CORSAIR=m
-# CONFIG_HID_COUGAR is not set
-# CONFIG_HID_MACALLY is not set
+CONFIG_HID_COUGAR=m
+CONFIG_HID_MACALLY=m
CONFIG_HID_PRODIKEYS=m
CONFIG_HID_CMEDIA=m
# CONFIG_HID_CP2112 is not set
-# CONFIG_HID_CREATIVE_SB0540 is not set
+CONFIG_HID_CREATIVE_SB0540=m
CONFIG_HID_CYPRESS=y
CONFIG_HID_DRAGONRISE=m
CONFIG_DRAGONRISE_FF=y
@@ -5671,26 +6207,29 @@ CONFIG_HID_EMS_FF=m
CONFIG_HID_ELECOM=m
CONFIG_HID_ELO=m
CONFIG_HID_EZKEY=y
+CONFIG_HID_FT260=m
CONFIG_HID_GEMBIRD=m
CONFIG_HID_GFRM=m
+CONFIG_HID_GLORIOUS=m
CONFIG_HID_HOLTEK=m
CONFIG_HOLTEK_FF=y
+CONFIG_HID_VIVALDI=m
CONFIG_HID_GT683R=m
CONFIG_HID_KEYTOUCH=m
CONFIG_HID_KYE=m
CONFIG_HID_UCLOGIC=m
CONFIG_HID_WALTOP=m
-# CONFIG_HID_VIEWSONIC is not set
+CONFIG_HID_VIEWSONIC=m
CONFIG_HID_GYRATION=m
CONFIG_HID_ICADE=m
-CONFIG_HID_ITE=y
-# CONFIG_HID_JABRA is not set
+CONFIG_HID_ITE=m
+CONFIG_HID_JABRA=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_KENSINGTON=y
CONFIG_HID_LCPOWER=m
CONFIG_HID_LED=m
CONFIG_HID_LENOVO=m
-CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH=m
# CONFIG_HID_LOGITECH_DJ is not set
CONFIG_HID_LOGITECH_HIDPP=m
CONFIG_LOGITECH_FF=y
@@ -5698,9 +6237,9 @@ CONFIG_LOGIRUMBLEPAD2_FF=y
CONFIG_LOGIG940_FF=y
CONFIG_LOGIWHEELS_FF=y
CONFIG_HID_MAGICMOUSE=m
-# CONFIG_HID_MALTRON is not set
+CONFIG_HID_MALTRON=m
CONFIG_HID_MAYFLASH=m
-# CONFIG_HID_REDRAGON is not set
+CONFIG_HID_REDRAGON=m
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MONTEREY=y
CONFIG_HID_MULTITOUCH=m
@@ -5718,21 +6257,24 @@ CONFIG_HID_PICOLCD=m
# CONFIG_HID_PICOLCD_LEDS is not set
# CONFIG_HID_PICOLCD_CIR is not set
CONFIG_HID_PLANTRONICS=m
+CONFIG_HID_PLAYSTATION=m
+CONFIG_PLAYSTATION_FF=y
CONFIG_HID_PRIMAX=m
CONFIG_HID_RETRODE=m
CONFIG_HID_ROCCAT=m
CONFIG_HID_SAITEK=m
CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SEMITEK=m
CONFIG_HID_SONY=m
CONFIG_SONY_FF=y
CONFIG_HID_SPEEDLINK=m
-# CONFIG_HID_STEAM is not set
+CONFIG_HID_STEAM=m
CONFIG_HID_STEELSERIES=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_RMI=m
CONFIG_HID_GREENASIA=m
CONFIG_GREENASIA_FF=y
-# CONFIG_HID_HYPERV_MOUSE is not set
+CONFIG_HID_HYPERV_MOUSE=m
CONFIG_HID_SMARTJOYPLUS=m
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_HID_TIVO=m
@@ -5741,7 +6283,7 @@ CONFIG_HID_THINGM=m
CONFIG_HID_THRUSTMASTER=m
CONFIG_THRUSTMASTER_FF=y
CONFIG_HID_UDRAW_PS3=m
-# CONFIG_HID_U2FZERO is not set
+CONFIG_HID_U2FZERO=m
CONFIG_HID_WACOM=m
CONFIG_HID_WIIMOTE=m
CONFIG_HID_XINMO=m
@@ -5751,6 +6293,7 @@ CONFIG_HID_ZYDACRON=m
CONFIG_HID_SENSOR_HUB=m
CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
CONFIG_HID_ALPS=m
+CONFIG_HID_MCP2221=m
# end of Special HID drivers
#
@@ -5764,7 +6307,9 @@ CONFIG_USB_HIDDEV=y
#
# I2C HID support
#
-CONFIG_I2C_HID=m
+# CONFIG_I2C_HID_ACPI is not set
+# CONFIG_I2C_HID_OF is not set
+# CONFIG_I2C_HID_OF_GOODIX is not set
# end of I2C HID support
#
@@ -5773,6 +6318,12 @@ CONFIG_I2C_HID=m
CONFIG_INTEL_ISH_HID=m
# CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER is not set
# end of Intel ISH HID support
+
+#
+# AMD SFH HID Support
+#
+CONFIG_AMD_SFH_HID=m
+# end of AMD SFH HID Support
# end of HID support
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -5790,10 +6341,11 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
# Miscellaneous USB options
#
CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_FEW_INIT_RETRIES is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_PRODUCTLIST is not set
+# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
CONFIG_USB_AUTOSUSPEND_DELAY=2
CONFIG_USB_MON=y
@@ -5805,6 +6357,7 @@ CONFIG_USB_C67X00_HCD=y
CONFIG_USB_XHCI_HCD=y
# CONFIG_USB_XHCI_DBGCAP is not set
CONFIG_USB_XHCI_PCI=y
+# CONFIG_USB_XHCI_PCI_RENESAS is not set
CONFIG_USB_XHCI_PLATFORM=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
@@ -5874,7 +6427,7 @@ CONFIG_USBIP_VHCI_NR_HCS=1
CONFIG_USBIP_HOST=m
CONFIG_USBIP_VUDC=m
# CONFIG_USBIP_DEBUG is not set
-# CONFIG_USB_CDNS3 is not set
+# CONFIG_USB_CDNS_SUPPORT is not set
# CONFIG_USB_MUSB_HDRC is not set
# CONFIG_USB_DWC3 is not set
# CONFIG_USB_DWC2 is not set
@@ -5930,7 +6483,6 @@ CONFIG_USB_SERIAL_SIERRAWIRELESS=m
CONFIG_USB_SERIAL_SYMBOL=m
CONFIG_USB_SERIAL_TI=m
CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_WWAN=m
CONFIG_USB_SERIAL_OPTION=m
CONFIG_USB_SERIAL_OMNINET=m
@@ -5940,6 +6492,7 @@ CONFIG_USB_SERIAL_WISHBONE=m
CONFIG_USB_SERIAL_SSU100=m
CONFIG_USB_SERIAL_QT2=m
CONFIG_USB_SERIAL_UPD78F0730=m
+# CONFIG_USB_SERIAL_XR is not set
CONFIG_USB_SERIAL_DEBUG=m
#
@@ -5956,8 +6509,8 @@ CONFIG_USB_CYTHERM=m
CONFIG_USB_IDMOUSE=m
CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m
+# CONFIG_APPLE_MFI_FASTCHARGE is not set
CONFIG_USB_SISUSBVGA=m
-# CONFIG_USB_SISUSBVGA_CON is not set
CONFIG_USB_LD=m
CONFIG_USB_TRANCEVIBRATOR=m
CONFIG_USB_IOWARRIOR=m
@@ -6000,11 +6553,6 @@ CONFIG_USB_SNP_CORE=m
CONFIG_USB_SNP_UDC_PLAT=m
CONFIG_USB_M66592=m
CONFIG_USB_BDC_UDC=m
-
-#
-# Platform Support
-#
-CONFIG_USB_BDC_PCI=m
CONFIG_USB_AMD5536UDC=m
CONFIG_USB_NET2272=m
# CONFIG_USB_NET2272_DMA is not set
@@ -6012,21 +6560,47 @@ CONFIG_USB_NET2280=m
CONFIG_USB_GOKU=m
CONFIG_USB_EG20T=m
CONFIG_USB_GADGET_XILINX=m
+# CONFIG_USB_MAX3420_UDC is not set
# CONFIG_USB_DUMMY_HCD is not set
# end of USB Peripheral Controller
# CONFIG_USB_CONFIGFS is not set
+
+#
+# USB Gadget precomposed configurations
+#
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_USB_RAW_GADGET is not set
+# end of USB Gadget precomposed configurations
+
CONFIG_TYPEC=m
# CONFIG_TYPEC_TCPM is not set
CONFIG_TYPEC_UCSI=m
# CONFIG_UCSI_CCG is not set
CONFIG_UCSI_ACPI=m
# CONFIG_TYPEC_TPS6598X is not set
+# CONFIG_TYPEC_STUSB160X is not set
#
# USB Type-C Multiplexer/DeMultiplexer Switch support
#
# CONFIG_TYPEC_MUX_PI3USB30532 is not set
+# CONFIG_TYPEC_MUX_INTEL_PMC is not set
# end of USB Type-C Multiplexer/DeMultiplexer Switch support
#
@@ -6061,7 +6635,9 @@ CONFIG_MMC_SDHCI_OF_AT91=m
# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set
CONFIG_MMC_SDHCI_CADENCE=m
CONFIG_MMC_SDHCI_F_SDH30=m
+# CONFIG_MMC_SDHCI_MILBEAUT is not set
CONFIG_MMC_WBSD=m
+# CONFIG_MMC_ALCOR is not set
CONFIG_MMC_TIFM_SD=m
# CONFIG_MMC_SPI is not set
CONFIG_MMC_SDRICOH_CS=m
@@ -6070,7 +6646,10 @@ CONFIG_MMC_VIA_SDMMC=m
CONFIG_MMC_VUB300=m
CONFIG_MMC_USHC=m
CONFIG_MMC_USDHI6ROL0=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
CONFIG_MMC_CQHCI=m
+# CONFIG_MMC_HSQ is not set
CONFIG_MMC_TOSHIBA_PCI=m
CONFIG_MMC_MTK=m
CONFIG_MMC_SDHCI_XENON=m
@@ -6092,9 +6671,12 @@ CONFIG_MS_BLOCK=m
CONFIG_MEMSTICK_TIFM_MS=m
CONFIG_MEMSTICK_JMICRON_38X=m
CONFIG_MEMSTICK_R592=m
+CONFIG_MEMSTICK_REALTEK_PCI=m
+CONFIG_MEMSTICK_REALTEK_USB=m
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=m
# CONFIG_LEDS_CLASS_FLASH is not set
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set
#
@@ -6102,9 +6684,11 @@ CONFIG_LEDS_CLASS=m
#
# CONFIG_LEDS_AN30259A is not set
# CONFIG_LEDS_APU is not set
+# CONFIG_LEDS_AW2013 is not set
# CONFIG_LEDS_BCM6328 is not set
# CONFIG_LEDS_BCM6358 is not set
# CONFIG_LEDS_CR0014114 is not set
+# CONFIG_LEDS_EL15203000 is not set
# CONFIG_LEDS_LM3530 is not set
# CONFIG_LEDS_LM3532 is not set
# CONFIG_LEDS_LM3642 is not set
@@ -6113,15 +6697,14 @@ CONFIG_LEDS_CLASS=m
# CONFIG_LEDS_GPIO is not set
# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_LP3952 is not set
-# CONFIG_LEDS_LP5521 is not set
-# CONFIG_LEDS_LP5523 is not set
-# CONFIG_LEDS_LP5562 is not set
-# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP50XX is not set
+# CONFIG_LEDS_LP55XX_COMMON is not set
# CONFIG_LEDS_LP8860 is not set
# CONFIG_LEDS_CLEVO_MAIL is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_PCA963X is not set
# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
# CONFIG_LEDS_REGULATOR is not set
# CONFIG_LEDS_BD2802 is not set
# CONFIG_LEDS_INTEL_SS4200 is not set
@@ -6142,6 +6725,11 @@ CONFIG_LEDS_CLASS=m
# CONFIG_LEDS_NIC78BX is not set
# CONFIG_LEDS_SPI_BYTE is not set
# CONFIG_LEDS_TI_LMU_COMMON is not set
+# CONFIG_LEDS_LGM is not set
+
+#
+# Flash and Torch LED drivers
+#
#
# LED Triggers
@@ -6167,8 +6755,16 @@ CONFIG_LEDS_TRIGGERS=y
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_PATTERN is not set
CONFIG_LEDS_TRIGGER_AUDIO=m
+# CONFIG_LEDS_TRIGGER_TTY is not set
CONFIG_ACCESSIBILITY=y
# CONFIG_A11Y_BRAILLE_CONSOLE is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# end of Speakup console speech
+
# CONFIG_INFINIBAND is not set
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
@@ -6177,7 +6773,6 @@ CONFIG_EDAC_LEGACY_SYSFS=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_DECODE_MCE=m
CONFIG_EDAC_AMD64=m
-# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set
CONFIG_EDAC_E752X=m
CONFIG_EDAC_I82975X=m
CONFIG_EDAC_I3000=m
@@ -6218,18 +6813,17 @@ CONFIG_RTC_DRV_ABX80X=m
CONFIG_RTC_DRV_DS1307=m
CONFIG_RTC_DRV_DS1307_CENTURY=y
CONFIG_RTC_DRV_DS1374=m
-CONFIG_RTC_DRV_DS1374_WDT=y
CONFIG_RTC_DRV_DS1672=m
CONFIG_RTC_DRV_HYM8563=m
CONFIG_RTC_DRV_MAX6900=m
CONFIG_RTC_DRV_RS5C372=m
CONFIG_RTC_DRV_ISL1208=m
CONFIG_RTC_DRV_ISL12022=m
-# CONFIG_RTC_DRV_ISL12026 is not set
+CONFIG_RTC_DRV_ISL12026=m
CONFIG_RTC_DRV_X1205=m
CONFIG_RTC_DRV_PCF8523=m
CONFIG_RTC_DRV_PCF85063=m
-# CONFIG_RTC_DRV_PCF85363 is not set
+CONFIG_RTC_DRV_PCF85363=m
CONFIG_RTC_DRV_PCF8563=m
CONFIG_RTC_DRV_PCF8583=m
CONFIG_RTC_DRV_M41T80=m
@@ -6241,9 +6835,10 @@ CONFIG_RTC_DRV_RX8010=m
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_RX8025=m
CONFIG_RTC_DRV_EM3027=m
-# CONFIG_RTC_DRV_RV3028 is not set
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_RV3032=m
CONFIG_RTC_DRV_RV8803=m
-# CONFIG_RTC_DRV_SD3078 is not set
+CONFIG_RTC_DRV_SD3078=m
#
# SPI RTC drivers
@@ -6258,7 +6853,6 @@ CONFIG_RTC_DRV_RV8803=m
# CONFIG_RTC_DRV_MAX6916 is not set
# CONFIG_RTC_DRV_R9701 is not set
# CONFIG_RTC_DRV_RX4581 is not set
-# CONFIG_RTC_DRV_RX6110 is not set
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_MAX6902 is not set
# CONFIG_RTC_DRV_PCF2123 is not set
@@ -6273,6 +6867,7 @@ CONFIG_RTC_DRV_DS3232_HWMON=y
CONFIG_RTC_DRV_PCF2127=m
CONFIG_RTC_DRV_RV3029C2=m
CONFIG_RTC_DRV_RV3029_HWMON=y
+# CONFIG_RTC_DRV_RX6110 is not set
#
# Platform RTC drivers
@@ -6304,12 +6899,12 @@ CONFIG_RTC_DRV_ZYNQMP=m
#
# CONFIG_RTC_DRV_CADENCE is not set
CONFIG_RTC_DRV_FTRTC010=m
-CONFIG_RTC_DRV_SNVS=m
CONFIG_RTC_DRV_R7301=m
#
# HID Sensor RTC drivers
#
+# CONFIG_RTC_DRV_GOLDFISH is not set
CONFIG_DMADEVICES=y
# CONFIG_DMADEVICES_DEBUG is not set
@@ -6324,8 +6919,12 @@ CONFIG_DMA_OF=y
# CONFIG_DW_AXI_DMAC is not set
# CONFIG_FSL_EDMA is not set
CONFIG_INTEL_IDMA64=m
+# CONFIG_INTEL_IDXD is not set
+# CONFIG_INTEL_IDXD_COMPAT is not set
CONFIG_INTEL_IOATDMA=m
-CONFIG_INTEL_MIC_X100_DMA=m
+# CONFIG_PLX_DMA is not set
+# CONFIG_XILINX_ZYNQMP_DPDMA is not set
+# CONFIG_AMD_PTDMA is not set
# CONFIG_QCOM_HIDMA_MGMT is not set
# CONFIG_QCOM_HIDMA is not set
CONFIG_DW_DMAC_CORE=y
@@ -6334,6 +6933,8 @@ CONFIG_DW_DMAC_PCI=y
# CONFIG_DW_EDMA is not set
# CONFIG_DW_EDMA_PCIE is not set
CONFIG_HSU_DMA=y
+# CONFIG_SF_PDMA is not set
+# CONFIG_INTEL_LDMA is not set
#
# DMA Clients
@@ -6348,7 +6949,11 @@ CONFIG_DMA_ENGINE_RAID=y
CONFIG_SYNC_FILE=y
# CONFIG_SW_SYNC is not set
# CONFIG_UDMABUF is not set
+# CONFIG_DMABUF_MOVE_NOTIFY is not set
+# CONFIG_DMABUF_DEBUG is not set
# CONFIG_DMABUF_SELFTESTS is not set
+# CONFIG_DMABUF_HEAPS is not set
+# CONFIG_DMABUF_SYSFS_STATS is not set
# end of DMABUF options
CONFIG_DCA=m
@@ -6368,16 +6973,26 @@ CONFIG_UIO=y
# CONFIG_VFIO is not set
CONFIG_IRQ_BYPASS_MANAGER=y
CONFIG_VIRT_DRIVERS=y
-# CONFIG_VBOXGUEST is not set
+CONFIG_VBOXGUEST=m
+CONFIG_NITRO_ENCLAVES=m
CONFIG_VIRTIO=y
+CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
# CONFIG_VIRTIO_PMEM is not set
CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_MEM=m
CONFIG_VIRTIO_INPUT=m
CONFIG_VIRTIO_MMIO=y
# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_DMA_SHARED_BUFFER=m
+# CONFIG_VDPA is not set
+CONFIG_VHOST_IOTLB=m
+CONFIG_VHOST=m
+CONFIG_VHOST_MENU=y
+CONFIG_VHOST_NET=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
#
# Microsoft Hyper-V guest support
@@ -6393,6 +7008,7 @@ CONFIG_HYPERV_BALLOON=m
#
CONFIG_XEN_BALLOON=y
# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set
+CONFIG_XEN_MEMORY_HOTPLUG_LIMIT=512
CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
CONFIG_XEN_DEV_EVTCHN=y
CONFIG_XEN_BACKEND=y
@@ -6419,40 +7035,39 @@ CONFIG_XEN_HAVE_VPMU=y
# end of Xen driver support
# CONFIG_GREYBUS is not set
+# CONFIG_COMEDI is not set
# CONFIG_STAGING is not set
CONFIG_X86_PLATFORM_DEVICES=y
-CONFIG_ACER_WMI=m
-# CONFIG_ACER_WIRELESS is not set
+CONFIG_ACPI_WMI=m
+CONFIG_WMI_BMOF=m
+CONFIG_HUAWEI_WMI=m
+CONFIG_MXM_WMI=m
+CONFIG_PEAQ_WMI=m
+CONFIG_XIAOMI_WMI=m
+CONFIG_GIGABYTE_WMI=m
CONFIG_ACERHDF=m
-CONFIG_ALIENWARE_WMI=m
+CONFIG_ACER_WIRELESS=m
+CONFIG_ACER_WMI=m
+CONFIG_AMD_PMC=m
+CONFIG_ADV_SWBUTTON=m
+CONFIG_APPLE_GMUX=m
CONFIG_ASUS_LAPTOP=m
-CONFIG_DCDBAS=m
-CONFIG_DELL_SMBIOS=m
-CONFIG_DELL_SMBIOS_WMI=y
-CONFIG_DELL_SMBIOS_SMM=y
-CONFIG_DELL_LAPTOP=m
-CONFIG_DELL_WMI=m
-CONFIG_DELL_WMI_DESCRIPTOR=m
-CONFIG_DELL_WMI_AIO=m
-CONFIG_DELL_WMI_LED=m
-CONFIG_DELL_SMO8800=m
-CONFIG_DELL_RBTN=m
-# CONFIG_DELL_RBU is not set
+CONFIG_ASUS_WIRELESS=m
+CONFIG_ASUS_WMI=m
+CONFIG_ASUS_NB_WMI=m
+CONFIG_EEEPC_LAPTOP=m
+CONFIG_EEEPC_WMI=m
+# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set
+CONFIG_AMILO_RFKILL=m
CONFIG_FUJITSU_LAPTOP=m
CONFIG_FUJITSU_TABLET=m
-CONFIG_AMILO_RFKILL=m
# CONFIG_GPD_POCKET_FAN is not set
CONFIG_HP_ACCEL=m
-CONFIG_HP_WIRELESS=m
+# CONFIG_WIRELESS_HOTKEY is not set
CONFIG_HP_WMI=m
-# CONFIG_LG_LAPTOP is not set
-CONFIG_MSI_LAPTOP=m
-CONFIG_PANASONIC_LAPTOP=m
-CONFIG_COMPAL_LAPTOP=m
-CONFIG_SONY_LAPTOP=m
-# CONFIG_SONYPI_COMPAT is not set
+# CONFIG_IBM_RTL is not set
CONFIG_IDEAPAD_LAPTOP=m
-CONFIG_SURFACE3_WMI=m
+CONFIG_SENSORS_HDAPS=m
CONFIG_THINKPAD_ACPI=m
CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y
# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set
@@ -6460,47 +7075,12 @@ CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y
# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set
CONFIG_THINKPAD_ACPI_VIDEO=y
CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
-CONFIG_SENSORS_HDAPS=m
-CONFIG_INTEL_MENLOW=m
-CONFIG_EEEPC_LAPTOP=m
-CONFIG_ASUS_WMI=m
-CONFIG_ASUS_NB_WMI=m
-CONFIG_EEEPC_WMI=m
-CONFIG_ASUS_WIRELESS=m
-CONFIG_ACPI_WMI=m
-CONFIG_WMI_BMOF=m
-# CONFIG_INTEL_WMI_THUNDERBOLT is not set
-# CONFIG_XIAOMI_WMI is not set
-CONFIG_MSI_WMI=m
-CONFIG_PEAQ_WMI=m
-CONFIG_TOPSTAR_LAPTOP=m
-CONFIG_TOSHIBA_BT_RFKILL=m
-CONFIG_TOSHIBA_HAPS=m
-CONFIG_TOSHIBA_WMI=m
-CONFIG_ACPI_CMPC=m
-# CONFIG_INTEL_INT0002_VGPIO is not set
-CONFIG_INTEL_HID_EVENT=m
-CONFIG_INTEL_VBTN=m
-CONFIG_INTEL_IPS=m
-# CONFIG_INTEL_PMC_CORE is not set
-# CONFIG_IBM_RTL is not set
-CONFIG_SAMSUNG_LAPTOP=m
-CONFIG_MXM_WMI=m
-CONFIG_INTEL_OAKTRAIL=m
-CONFIG_SAMSUNG_Q10=m
-CONFIG_APPLE_GMUX=m
-CONFIG_INTEL_RST=m
-CONFIG_INTEL_SMARTCONNECT=m
-CONFIG_INTEL_PMC_IPC=m
-CONFIG_SURFACE_PRO3_BUTTON=m
-CONFIG_INTEL_PUNIT_IPC=m
-CONFIG_INTEL_TELEMETRY=m
-CONFIG_MLX_PLATFORM=m
-# CONFIG_INTEL_TURBO_MAX_3 is not set
-# CONFIG_I2C_MULTI_INSTANTIATE is not set
+# CONFIG_THINKPAD_LMI is not set
+CONFIG_X86_PLATFORM_DRIVERS_INTEL=y
# CONFIG_INTEL_ATOMISP2_PM is not set
-# CONFIG_HUAWEI_WMI is not set
-# CONFIG_PCENGINES_APU2 is not set
+# CONFIG_INTEL_SAR_INT1092 is not set
+# CONFIG_INTEL_SKL_INT3472 is not set
+# CONFIG_INTEL_PMC_CORE is not set
#
# Intel Speed Select Technology interface support
@@ -6508,18 +7088,64 @@ CONFIG_MLX_PLATFORM=m
# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set
# end of Intel Speed Select Technology interface support
+# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set
+# CONFIG_INTEL_WMI_THUNDERBOLT is not set
+CONFIG_INTEL_HID_EVENT=m
+CONFIG_INTEL_VBTN=m
+# CONFIG_INTEL_INT0002_VGPIO is not set
+CONFIG_INTEL_OAKTRAIL=m
+CONFIG_INTEL_PUNIT_IPC=m
+CONFIG_INTEL_RST=m
+CONFIG_INTEL_SMARTCONNECT=m
+# CONFIG_INTEL_TURBO_MAX_3 is not set
+# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set
+CONFIG_MSI_LAPTOP=m
+CONFIG_MSI_WMI=m
+# CONFIG_PCENGINES_APU2 is not set
+CONFIG_SAMSUNG_LAPTOP=m
+CONFIG_SAMSUNG_Q10=m
+CONFIG_TOSHIBA_BT_RFKILL=m
+CONFIG_TOSHIBA_HAPS=m
+CONFIG_TOSHIBA_WMI=m
+CONFIG_ACPI_CMPC=m
+CONFIG_COMPAL_LAPTOP=m
+CONFIG_LG_LAPTOP=m
+CONFIG_PANASONIC_LAPTOP=m
+CONFIG_SONY_LAPTOP=m
+# CONFIG_SONYPI_COMPAT is not set
+CONFIG_SYSTEM76_ACPI=m
+CONFIG_TOPSTAR_LAPTOP=m
+# CONFIG_I2C_MULTI_INSTANTIATE is not set
+CONFIG_MLX_PLATFORM=m
+CONFIG_INTEL_IPS=m
+CONFIG_INTEL_SCU_IPC=y
+CONFIG_INTEL_SCU=y
+# CONFIG_INTEL_SCU_PCI is not set
+CONFIG_INTEL_SCU_PLATFORM=m
+CONFIG_INTEL_SCU_IPC_UTIL=m
CONFIG_PMC_ATOM=y
-# CONFIG_MFD_CROS_EC is not set
# CONFIG_CHROME_PLATFORMS is not set
# CONFIG_MELLANOX_PLATFORM is not set
-CONFIG_CLKDEV_LOOKUP=y
+CONFIG_SURFACE_PLATFORMS=y
+CONFIG_SURFACE3_WMI=m
+CONFIG_SURFACE_3_BUTTON=m
+CONFIG_SURFACE_3_POWER_OPREGION=m
+CONFIG_SURFACE_GPE=m
+CONFIG_SURFACE_HOTPLUG=m
+CONFIG_SURFACE_PRO3_BUTTON=m
+# CONFIG_SURFACE_AGGREGATOR is not set
+CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
#
-# Common Clock Framework
+# Clock driver for ARM Reference designs
#
-# CONFIG_CLK_HSDK is not set
+# CONFIG_ICST is not set
+# CONFIG_CLK_SP810 is not set
+# end of Clock driver for ARM Reference designs
+
+# CONFIG_LMK04832 is not set
# CONFIG_COMMON_CLK_MAX9485 is not set
# CONFIG_COMMON_CLK_SI5341 is not set
# CONFIG_COMMON_CLK_SI5351 is not set
@@ -6529,17 +7155,21 @@ CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_CDCE706 is not set
# CONFIG_COMMON_CLK_CDCE925 is not set
# CONFIG_COMMON_CLK_CS2000_CP is not set
+# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
+# CONFIG_COMMON_CLK_PWM is not set
# CONFIG_COMMON_CLK_VC5 is not set
# CONFIG_COMMON_CLK_FIXED_MMIO is not set
-# end of Common Clock Framework
-
+# CONFIG_CLK_LGM_CGU is not set
+# CONFIG_XILINX_VCU is not set
# CONFIG_HWSPINLOCK is not set
#
# Clock Source drivers
#
CONFIG_CLKEVT_I8253=y
+CONFIG_I8253_LOCK=y
CONFIG_CLKBLD_I8253=y
+# CONFIG_MICROCHIP_PIT64B is not set
# end of Clock Source drivers
CONFIG_MAILBOX=y
@@ -6548,17 +7178,23 @@ CONFIG_PCC=y
# CONFIG_ALTERA_MBOX is not set
# CONFIG_MAILBOX_TEST is not set
CONFIG_IOMMU_IOVA=y
+CONFIG_IOASID=y
CONFIG_IOMMU_API=y
CONFIG_IOMMU_SUPPORT=y
#
# Generic IOMMU Pagetable Support
#
+CONFIG_IOMMU_IO_PGTABLE=y
# end of Generic IOMMU Pagetable Support
# CONFIG_IOMMU_DEBUGFS is not set
+# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
+CONFIG_IOMMU_DMA=y
+CONFIG_IOMMU_SVA_LIB=y
CONFIG_AMD_IOMMU=y
CONFIG_AMD_IOMMU_V2=m
CONFIG_DMAR_TABLE=y
@@ -6566,8 +7202,10 @@ CONFIG_INTEL_IOMMU=y
CONFIG_INTEL_IOMMU_SVM=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_INTEL_IOMMU_FLOPPY_WA=y
+CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y
CONFIG_IRQ_REMAP=y
CONFIG_HYPERV_IOMMU=y
+# CONFIG_VIRTIO_IOMMU is not set
#
# Remoteproc drivers
@@ -6594,11 +7232,6 @@ CONFIG_HYPERV_IOMMU=y
# end of Amlogic SoC drivers
#
-# Aspeed SoC drivers
-#
-# end of Aspeed SoC drivers
-
-#
# Broadcom SoC drivers
#
# end of Broadcom SoC drivers
@@ -6614,6 +7247,12 @@ CONFIG_HYPERV_IOMMU=y
# end of i.MX SoC drivers
#
+# Enable LiteX SoC Builder specific drivers
+#
+# CONFIG_LITEX_SOC_CONTROLLER is not set
+# end of Enable LiteX SoC Builder specific drivers
+
+#
# Qualcomm SoC drivers
#
# end of Qualcomm SoC drivers
@@ -6623,7 +7262,6 @@ CONFIG_HYPERV_IOMMU=y
#
# Xilinx SoC drivers
#
-# CONFIG_XILINX_VCU is not set
# end of Xilinx SoC drivers
# end of SOC (System On Chip) specific Drivers
@@ -6642,12 +7280,34 @@ CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
# DEVFREQ Drivers
#
# CONFIG_PM_DEVFREQ_EVENT is not set
-# CONFIG_EXTCON is not set
+CONFIG_EXTCON=m
+
+#
+# Extcon Device Drivers
+#
+# CONFIG_EXTCON_FSA9480 is not set
+# CONFIG_EXTCON_GPIO is not set
+# CONFIG_EXTCON_INTEL_INT3496 is not set
+# CONFIG_EXTCON_MAX3355 is not set
+# CONFIG_EXTCON_PTN5150 is not set
+# CONFIG_EXTCON_RT8973A is not set
+# CONFIG_EXTCON_SM5502 is not set
+# CONFIG_EXTCON_USB_GPIO is not set
+# CONFIG_EXTCON_USBC_TUSB320 is not set
# CONFIG_MEMORY is not set
# CONFIG_IIO is not set
# CONFIG_NTB is not set
# CONFIG_VME_BUS is not set
-# CONFIG_PWM is not set
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+# CONFIG_PWM_DEBUG is not set
+# CONFIG_PWM_ATMEL_TCB is not set
+# CONFIG_PWM_DWC is not set
+# CONFIG_PWM_FSL_FTM is not set
+# CONFIG_PWM_INTEL_LGM is not set
+# CONFIG_PWM_LPSS_PCI is not set
+# CONFIG_PWM_LPSS_PLATFORM is not set
+# CONFIG_PWM_PCA9685 is not set
#
# IRQ chip support
@@ -6658,16 +7318,20 @@ CONFIG_IRQCHIP=y
# CONFIG_IPACK_BUS is not set
CONFIG_RESET_CONTROLLER=y
+# CONFIG_RESET_INTEL_GW is not set
# CONFIG_RESET_TI_SYSCON is not set
#
# PHY Subsystem
#
CONFIG_GENERIC_PHY=y
+# CONFIG_USB_LGM_PHY is not set
+# CONFIG_PHY_CAN_TRANSCEIVER is not set
# CONFIG_BCM_KONA_USB2_PHY is not set
-# CONFIG_PHY_CADENCE_DP is not set
+# CONFIG_PHY_CADENCE_TORRENT is not set
# CONFIG_PHY_CADENCE_DPHY is not set
# CONFIG_PHY_CADENCE_SIERRA is not set
+# CONFIG_PHY_CADENCE_SALVO is not set
# CONFIG_PHY_FSL_IMX8MQ_USB is not set
# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
# CONFIG_PHY_PXA_28NM_HSIC is not set
@@ -6677,6 +7341,8 @@ CONFIG_GENERIC_PHY=y
# CONFIG_PHY_QCOM_USB_HS is not set
# CONFIG_PHY_QCOM_USB_HSIC is not set
# CONFIG_PHY_TUSB1210 is not set
+# CONFIG_PHY_INTEL_LGM_COMBO is not set
+# CONFIG_PHY_INTEL_LGM_EMMC is not set
# end of PHY Subsystem
# CONFIG_POWERCAP is not set
@@ -6689,7 +7355,9 @@ CONFIG_GENERIC_PHY=y
CONFIG_RAS=y
# CONFIG_RAS_CEC is not set
-CONFIG_THUNDERBOLT=m
+CONFIG_USB4=m
+# CONFIG_USB4_DEBUGFS_WRITE is not set
+# CONFIG_USB4_DMA_TEST is not set
#
# Android
@@ -6709,6 +7377,8 @@ CONFIG_DAX=y
# CONFIG_DEV_DAX is not set
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
+# CONFIG_NVMEM_SPMI_SDAM is not set
+# CONFIG_NVMEM_RMEM is not set
#
# HW tracing support
@@ -6719,12 +7389,25 @@ CONFIG_NVMEM_SYSFS=y
# CONFIG_FPGA is not set
# CONFIG_FSI is not set
+# CONFIG_TEE is not set
+CONFIG_MULTIPLEXER=m
+
+#
+# Multiplexer drivers
+#
+# CONFIG_MUX_ADG792A is not set
+# CONFIG_MUX_ADGS1408 is not set
+# CONFIG_MUX_GPIO is not set
+# CONFIG_MUX_MMIO is not set
+# end of Multiplexer drivers
+
CONFIG_PM_OPP=y
# CONFIG_UNISYS_VISORBUS is not set
# CONFIG_SIOX is not set
# CONFIG_SLIMBUS is not set
# CONFIG_INTERCONNECT is not set
# CONFIG_COUNTER is not set
+# CONFIG_MOST is not set
# end of Device Drivers
#
@@ -6755,6 +7438,7 @@ CONFIG_JFS_SECURITY=y
# CONFIG_JFS_DEBUG is not set
# CONFIG_JFS_STATISTICS is not set
CONFIG_XFS_FS=y
+CONFIG_XFS_SUPPORT_V4=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
@@ -6767,7 +7451,7 @@ CONFIG_OCFS2_FS_O2CB=m
CONFIG_OCFS2_FS_STATS=y
# CONFIG_OCFS2_DEBUG_MASKLOG is not set
# CONFIG_OCFS2_DEBUG_FS is not set
-CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
@@ -6782,12 +7466,13 @@ CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_SECURITY=y
# CONFIG_F2FS_CHECK_FS is not set
# CONFIG_F2FS_FAULT_INJECTION is not set
+# CONFIG_F2FS_FS_COMPRESSION is not set
+CONFIG_F2FS_IOSTAT=y
# CONFIG_FS_DAX is not set
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
# CONFIG_EXPORTFS_BLOCK_OPS is not set
CONFIG_FILE_LOCKING=y
-# CONFIG_MANDATORY_FILE_LOCKING is not set
# CONFIG_FS_ENCRYPTION is not set
# CONFIG_FS_VERITY is not set
CONFIG_FSNOTIFY=y
@@ -6803,7 +7488,6 @@ CONFIG_QUOTA_TREE=m
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
CONFIG_QUOTACTL=y
-CONFIG_QUOTACTL_COMPAT=y
# CONFIG_AUTOFS4_FS is not set
# CONFIG_AUTOFS_FS is not set
CONFIG_FUSE_FS=m
@@ -6832,7 +7516,7 @@ CONFIG_UDF_FS=m
# end of CD-ROM/DVD Filesystems
#
-# DOS/FAT/NT Filesystems
+# DOS/FAT/EXFAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=m
@@ -6840,10 +7524,14 @@ CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_FAT_DEFAULT_UTF8=y
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-# end of DOS/FAT/NT Filesystems
+CONFIG_EXFAT_FS=y
+CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8"
+# CONFIG_NTFS_FS is not set
+CONFIG_NTFS3_FS=y
+# CONFIG_NTFS3_64BIT_CLUSTER is not set
+CONFIG_NTFS3_LZX_XPRESS=y
+# CONFIG_NTFS3_FS_POSIX_ACL is not set
+# end of DOS/FAT/EXFAT/NT Filesystems
#
# Pseudo filesystems
@@ -6859,8 +7547,11 @@ CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y
+# CONFIG_TMPFS_INODE64 is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
+CONFIG_HUGETLB_PAGE_FREE_VMEMMAP=y
+# CONFIG_HUGETLB_PAGE_FREE_VMEMMAP_DEFAULT_ON is not set
CONFIG_MEMFD_CREATE=y
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
CONFIG_CONFIGFS_FS=m
@@ -6904,6 +7595,7 @@ CONFIG_HPFS_FS=m
# CONFIG_QNX6FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_PSTORE=y
+CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
CONFIG_PSTORE_DEFLATE_COMPRESS=y
# CONFIG_PSTORE_LZO_COMPRESS is not set
# CONFIG_PSTORE_LZ4_COMPRESS is not set
@@ -6916,11 +7608,13 @@ CONFIG_PSTORE_COMPRESS_DEFAULT="deflate"
# CONFIG_PSTORE_CONSOLE is not set
# CONFIG_PSTORE_PMSG is not set
# CONFIG_PSTORE_RAM is not set
+# CONFIG_PSTORE_BLK is not set
CONFIG_SYSV_FS=m
CONFIG_UFS_FS=m
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_UFS_DEBUG is not set
# CONFIG_EROFS_FS is not set
+# CONFIG_VBOXSF_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=m
CONFIG_NFS_V2=m
@@ -6937,6 +7631,7 @@ CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
# CONFIG_NFS_V4_1_MIGRATION is not set
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
+CONFIG_NFS_DISABLE_UDP_SUPPORT=y
CONFIG_NFSD=m
CONFIG_NFSD_V2_ACL=y
CONFIG_NFSD_V3=y
@@ -6959,7 +7654,6 @@ CONFIG_SUNRPC_BACKCHANNEL=y
CONFIG_CIFS=m
# CONFIG_CIFS_STATS2 is not set
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
-# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_UPCALL is not set
CONFIG_CIFS_XATTR=y
# CONFIG_CIFS_POSIX is not set
@@ -6967,6 +7661,9 @@ CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set
# CONFIG_CIFS_DFS_UPCALL is not set
+# CONFIG_CIFS_SWN_UPCALL is not set
+# CONFIG_SMB_SERVER is not set
+CONFIG_SMBFS_COMMON=m
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
CONFIG_9P_FS=m
@@ -7025,16 +7722,15 @@ CONFIG_NLS_MAC_TURKISH=m
CONFIG_NLS_UTF8=y
# CONFIG_DLM is not set
# CONFIG_UNICODE is not set
+CONFIG_IO_WQ=y
# end of File systems
#
# Security options
#
CONFIG_KEYS=y
-CONFIG_KEYS_COMPAT=y
# CONFIG_KEYS_REQUEST_CACHE is not set
# CONFIG_PERSISTENT_KEYRINGS is not set
-# CONFIG_BIG_KEYS is not set
# CONFIG_TRUSTED_KEYS is not set
# CONFIG_ENCRYPTED_KEYS is not set
# CONFIG_KEY_DH_OPERATIONS is not set
@@ -7058,7 +7754,9 @@ CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_YAMA=y
# CONFIG_SECURITY_SAFESETID is not set
# CONFIG_SECURITY_LOCKDOWN_LSM is not set
+# CONFIG_SECURITY_LANDLOCK is not set
# CONFIG_INTEGRITY is not set
+# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
@@ -7070,13 +7768,17 @@ CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
# Memory initialization
#
CONFIG_INIT_STACK_NONE=y
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_USER is not set
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF is not set
+# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL is not set
+# CONFIG_GCC_PLUGIN_STACKLEAK is not set
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
# end of Memory initialization
# end of Kernel hardening options
# end of Security options
-CONFIG_XOR_BLOCKS=m
+CONFIG_XOR_BLOCKS=y
CONFIG_ASYNC_CORE=m
CONFIG_ASYNC_MEMCPY=m
CONFIG_ASYNC_XOR=m
@@ -7091,11 +7793,11 @@ CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_SKCIPHER=y
+CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=m
CONFIG_CRYPTO_AKCIPHER2=y
@@ -7115,7 +7817,6 @@ CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=y
# CONFIG_CRYPTO_TEST is not set
CONFIG_CRYPTO_SIMD=m
-CONFIG_CRYPTO_GLUE_HELPER_X86=m
#
# Public-key cryptography
@@ -7124,7 +7825,11 @@ CONFIG_CRYPTO_RSA=y
# CONFIG_CRYPTO_DH is not set
CONFIG_CRYPTO_ECC=m
CONFIG_CRYPTO_ECDH=m
+# CONFIG_CRYPTO_ECDSA is not set
# CONFIG_CRYPTO_ECRDSA is not set
+# CONFIG_CRYPTO_SM2 is not set
+# CONFIG_CRYPTO_CURVE25519 is not set
+# CONFIG_CRYPTO_CURVE25519_X86 is not set
#
# Authenticated Encryption with Associated Data
@@ -7170,7 +7875,10 @@ CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRC32C_INTEL=m
CONFIG_CRYPTO_CRC32=m
# CONFIG_CRYPTO_CRC32_PCLMUL is not set
-# CONFIG_CRYPTO_XXHASH is not set
+CONFIG_CRYPTO_XXHASH=y
+CONFIG_CRYPTO_BLAKE2B=y
+# CONFIG_CRYPTO_BLAKE2S is not set
+# CONFIG_CRYPTO_BLAKE2S_X86 is not set
CONFIG_CRYPTO_CRCT10DIF=y
# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set
CONFIG_CRYPTO_GHASH=m
@@ -7179,33 +7887,26 @@ CONFIG_CRYPTO_POLY1305_X86_64=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
-# CONFIG_CRYPTO_RMD128 is not set
# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA1_SSSE3=m
CONFIG_CRYPTO_SHA256_SSSE3=m
CONFIG_CRYPTO_SHA512_SSSE3=m
-CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
# CONFIG_CRYPTO_SHA3 is not set
# CONFIG_CRYPTO_SM3 is not set
# CONFIG_CRYPTO_STREEBOG is not set
-# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_WP512 is not set
CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
#
# Ciphers
#
-CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_AES_TI is not set
CONFIG_CRYPTO_AES_NI_INTEL=m
# CONFIG_CRYPTO_ANUBIS is not set
-CONFIG_CRYPTO_LIB_ARC4=m
CONFIG_CRYPTO_ARC4=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set
@@ -7217,12 +7918,10 @@ CONFIG_CRYPTO_ARC4=m
# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set
-CONFIG_CRYPTO_LIB_DES=m
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
CONFIG_CRYPTO_CHACHA20=m
CONFIG_CRYPTO_CHACHA20_X86_64=m
# CONFIG_CRYPTO_SEED is not set
@@ -7231,6 +7930,8 @@ CONFIG_CRYPTO_CHACHA20_X86_64=m
# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set
# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set
# CONFIG_CRYPTO_SM4 is not set
+# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
+# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
@@ -7256,13 +7957,33 @@ CONFIG_CRYPTO_DRBG_HMAC=y
# CONFIG_CRYPTO_DRBG_HASH is not set
# CONFIG_CRYPTO_DRBG_CTR is not set
CONFIG_CRYPTO_DRBG=m
-CONFIG_CRYPTO_JITTERENTROPY=m
+CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_USER_API=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_USER_API_RNG=m
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
CONFIG_CRYPTO_HASH_INFO=y
+
+#
+# Crypto library routines
+#
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_ARC4=m
+# CONFIG_CRYPTO_LIB_BLAKE2S is not set
+CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m
+CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
+# CONFIG_CRYPTO_LIB_CHACHA is not set
+# CONFIG_CRYPTO_LIB_CURVE25519 is not set
+CONFIG_CRYPTO_LIB_DES=m
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11
+CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m
+# CONFIG_CRYPTO_LIB_POLY1305 is not set
+# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
+CONFIG_CRYPTO_LIB_SHA256=y
# CONFIG_CRYPTO_HW is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
@@ -7276,6 +7997,8 @@ CONFIG_PKCS7_MESSAGE_PARSER=y
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
+CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
+# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
@@ -7283,11 +8006,14 @@ CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
# end of Certificates for signature checking
+CONFIG_BINARY_PRINTF=y
+
#
# Library routines
#
-CONFIG_RAID6_PQ=m
+CONFIG_RAID6_PQ=y
CONFIG_RAID6_PQ_BENCHMARK=y
+CONFIG_LINEAR_RANGES=y
# CONFIG_PACKING is not set
CONFIG_BITREVERSE=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
@@ -7295,11 +8021,13 @@ CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_CORDIC=m
+# CONFIG_PRIME_NUMBERS is not set
CONFIG_RATIONAL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
CONFIG_CRC_CCITT=m
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
@@ -7321,9 +8049,10 @@ CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_COMPRESS=m
CONFIG_LZ4_DECOMPRESS=y
-CONFIG_ZSTD_COMPRESS=m
-CONFIG_ZSTD_DECOMPRESS=m
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
@@ -7339,6 +8068,7 @@ CONFIG_DECOMPRESS_LZMA=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
+CONFIG_DECOMPRESS_ZSTD=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
@@ -7350,12 +8080,25 @@ CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
+CONFIG_DMA_OPS=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_SWIOTLB=y
-# CONFIG_DMA_CMA is not set
+CONFIG_DMA_CMA=y
+# CONFIG_DMA_PERNUMA_CMA is not set
+
+#
+# Default contiguous memory area size:
+#
+CONFIG_CMA_SIZE_MBYTES=0
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
+# CONFIG_CMA_SIZE_SEL_MIN is not set
+# CONFIG_CMA_SIZE_SEL_MAX is not set
+CONFIG_CMA_ALIGNMENT=8
# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_MAP_BENCHMARK is not set
CONFIG_SGL_ALLOC=y
CONFIG_IOMMU_HELPER=y
CONFIG_CHECK_SIGNATURE=y
@@ -7368,21 +8111,23 @@ CONFIG_CLZ_TAB=y
CONFIG_IRQ_POLL=y
CONFIG_MPILIB=y
CONFIG_DIMLIB=y
+CONFIG_LIBFDT=y
CONFIG_OID_REGISTRY=y
CONFIG_UCS2_STRING=y
CONFIG_HAVE_GENERIC_VDSO=y
CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_VDSO_TIME_NS=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
-CONFIG_ARCH_HAS_UACCESS_MCSAFE=y
+CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y
CONFIG_SBITMAP=y
-# CONFIG_STRING_SELFTEST is not set
# end of Library routines
#
@@ -7394,34 +8139,51 @@ CONFIG_SBITMAP=y
#
CONFIG_PRINTK_TIME=y
# CONFIG_PRINTK_CALLER is not set
+# CONFIG_STACKTRACE_BUILD_ID is not set
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
CONFIG_BOOT_PRINTK_DELAY=y
# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG_CORE is not set
+CONFIG_SYMBOLIC_ERRNAME=y
+CONFIG_DEBUG_BUGVERBOSE=y
# end of printk and dmesg options
#
# Compile-time checks and compiler options
#
# CONFIG_DEBUG_INFO is not set
-CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=2048
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_READABLE_ASM is not set
-CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_INSTALL is not set
-CONFIG_OPTIMIZE_INLINING=y
# CONFIG_DEBUG_SECTION_MISMATCH is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
CONFIG_FRAME_POINTER=y
CONFIG_STACK_VALIDATION=y
+# CONFIG_VMLINUX_MAP is not set
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# end of Compile-time checks and compiler options
+#
+# Generic Kernel Debugging Instruments
+#
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
# CONFIG_MAGIC_SYSRQ_SERIAL is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ALLOW_ALL=y
+# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
+# CONFIG_DEBUG_FS_ALLOW_NONE is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_UBSAN is not set
+CONFIG_HAVE_ARCH_KCSAN=y
+# end of Generic Kernel Debugging Instruments
+
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MISC=y
@@ -7433,44 +8195,59 @@ CONFIG_DEBUG_MISC=y
# CONFIG_PAGE_OWNER is not set
# CONFIG_PAGE_POISONING is not set
# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_ARCH_HAS_DEBUG_WX=y
+CONFIG_DEBUG_WX=y
+CONFIG_GENERIC_PTDUMP=y
+CONFIG_PTDUMP_CORE=y
+# CONFIG_PTDUMP_DEBUGFS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_STATS is not set
CONFIG_HAVE_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VM_PGTABLE is not set
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_VIRTUAL is not set
CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_PER_CPU_MAPS is not set
+CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y
+# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set
CONFIG_HAVE_ARCH_KASAN=y
+CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
+CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
# CONFIG_KASAN is not set
-CONFIG_KASAN_STACK=1
+CONFIG_HAVE_ARCH_KFENCE=y
+# CONFIG_KFENCE is not set
# end of Memory Debugging
-CONFIG_ARCH_HAS_KCOV=y
-CONFIG_CC_HAS_SANCOV_TRACE_PC=y
-# CONFIG_KCOV is not set
# CONFIG_DEBUG_SHIRQ is not set
#
-# Debug Lockups and Hangs
+# Debug Oops, Lockups and Hangs
#
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=120
# CONFIG_SOFTLOCKUP_DETECTOR is not set
CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y
# CONFIG_HARDLOCKUP_DETECTOR is not set
# CONFIG_DETECT_HUNG_TASK is not set
# CONFIG_WQ_WATCHDOG is not set
-# end of Debug Lockups and Hangs
+# CONFIG_TEST_LOCKUP is not set
+# end of Debug Oops, Lockups and Hangs
-# CONFIG_PANIC_ON_OOPS is not set
-CONFIG_PANIC_ON_OOPS_VALUE=0
-CONFIG_PANIC_TIMEOUT=120
+#
+# Scheduler Debugging
+#
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHED_INFO=y
# CONFIG_SCHEDSTATS is not set
-CONFIG_SCHED_STACK_END_CHECK=y
+# end of Scheduler Debugging
+
# CONFIG_DEBUG_TIMEKEEPING is not set
#
@@ -7489,54 +8266,103 @@ CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_SCF_TORTURE_TEST is not set
+# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)
+# CONFIG_DEBUG_IRQFLAGS is not set
CONFIG_STACKTRACE=y
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+
+#
+# Debug kernel data structures
+#
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_PLIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
+# end of Debug kernel data structures
+
# CONFIG_DEBUG_CREDENTIALS is not set
#
# RCU Debugging
#
-# CONFIG_RCU_PERF_TEST is not set
+# CONFIG_RCU_SCALE_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_REF_SCALE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=21
# CONFIG_RCU_TRACE is not set
# CONFIG_RCU_EQS_DEBUG is not set
# end of RCU Debugging
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
-# CONFIG_NOTIFIER_ERROR_INJECTION is not set
-CONFIG_FUNCTION_ERROR_INJECTION=y
-# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y
+CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_TRACE_CLOCK=y
-CONFIG_RING_BUFFER=y
-CONFIG_RING_BUFFER_ALLOW_SWAP=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_SAMPLES is not set
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_IO_STRICT_DEVMEM=y
+
+#
+# x86 Debugging
+#
+CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
+# CONFIG_X86_VERBOSE_BOOTUP is not set
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK_DBGP is not set
+# CONFIG_EARLY_PRINTK_USB_XDBC is not set
+# CONFIG_EFI_PGT_DUMP is not set
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+# CONFIG_X86_DECODER_SELFTEST is not set
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+# CONFIG_DEBUG_BOOT_PARAMS is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_DEBUG_ENTRY is not set
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+CONFIG_X86_DEBUG_FPU=y
+# CONFIG_PUNIT_ATOM_DEBUG is not set
+# CONFIG_UNWINDER_ORC is not set
+CONFIG_UNWINDER_FRAME_POINTER=y
+# CONFIG_UNWINDER_GUESS is not set
+# end of x86 Debugging
+
+#
+# Kernel Testing and Coverage
+#
+# CONFIG_KUNIT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+CONFIG_FUNCTION_ERROR_INJECTION=y
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_ARCH_HAS_KCOV=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+# CONFIG_KCOV is not set
CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_LKDTM is not set
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_TEST_SORT is not set
+# CONFIG_TEST_MIN_HEAP is not set
+# CONFIG_TEST_DIV64 is not set
# CONFIG_KPROBES_SANITY_TEST is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_RBTREE_TEST is not set
@@ -7546,12 +8372,13 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_ASYNC_RAID6_TEST is not set
# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_SCANF is not set
# CONFIG_TEST_BITMAP is not set
-# CONFIG_TEST_BITFIELD is not set
# CONFIG_TEST_UUID is not set
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_OVERFLOW is not set
@@ -7559,6 +8386,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HASH is not set
# CONFIG_TEST_IDA is not set
# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_BITOPS is not set
# CONFIG_TEST_VMALLOC is not set
# CONFIG_TEST_USER_COPY is not set
# CONFIG_TEST_BPF is not set
@@ -7572,41 +8400,11 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_MEMCAT_P is not set
# CONFIG_TEST_STACKINIT is not set
# CONFIG_TEST_MEMINIT is not set
+# CONFIG_TEST_FREE_PAGES is not set
+# CONFIG_TEST_FPU is not set
+# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
+CONFIG_ARCH_USE_MEMTEST=y
# CONFIG_MEMTEST is not set
-# CONFIG_BUG_ON_DATA_CORRUPTION is not set
-# CONFIG_SAMPLES is not set
-CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
-CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
-# CONFIG_UBSAN is not set
-CONFIG_UBSAN_ALIGNMENT=y
-CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_IO_STRICT_DEVMEM=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# CONFIG_X86_VERBOSE_BOOTUP is not set
-CONFIG_EARLY_PRINTK=y
-# CONFIG_EARLY_PRINTK_DBGP is not set
-# CONFIG_EARLY_PRINTK_USB_XDBC is not set
-CONFIG_X86_PTDUMP_CORE=y
-# CONFIG_X86_PTDUMP is not set
-# CONFIG_EFI_PGT_DUMP is not set
-CONFIG_DEBUG_WX=y
-CONFIG_DOUBLEFAULT=y
-# CONFIG_DEBUG_TLBFLUSH is not set
-CONFIG_HAVE_MMIOTRACE_SUPPORT=y
-# CONFIG_X86_DECODER_SELFTEST is not set
-CONFIG_IO_DELAY_0X80=y
-# CONFIG_IO_DELAY_0XED is not set
-# CONFIG_IO_DELAY_UDELAY is not set
-# CONFIG_IO_DELAY_NONE is not set
-# CONFIG_DEBUG_BOOT_PARAMS is not set
-# CONFIG_CPA_DEBUG is not set
-# CONFIG_DEBUG_ENTRY is not set
-# CONFIG_DEBUG_NMI_SELFTEST is not set
-CONFIG_X86_DEBUG_FPU=y
-# CONFIG_PUNIT_ATOM_DEBUG is not set
-# CONFIG_UNWINDER_ORC is not set
-CONFIG_UNWINDER_FRAME_POINTER=y
-# CONFIG_UNWINDER_GUESS is not set
+# CONFIG_HYPERV_TESTING is not set
+# end of Kernel Testing and Coverage
# end of Kernel hacking
diff --git a/system/easy-kernel/kernel.h b/system/easy-kernel/kernel.h
deleted file mode 100644
index f9171158b..000000000
--- a/system/easy-kernel/kernel.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _LINUX_KERNEL_H
-#define _LINUX_KERNEL_H
-
-#ifdef __GLIBC__
-#include <linux/sysinfo.h>
-#endif
-
-/*
- * 'kernel.h' contains some often-used function prototypes etc
- */
-#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
-#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
-
-#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-
-#endif /* _LINUX_KERNEL_H */
diff --git a/system/easy-kernel/no-require-gnu-tar.patch b/system/easy-kernel/no-require-gnu-tar.patch
new file mode 100644
index 000000000..a111c3f1a
--- /dev/null
+++ b/system/easy-kernel/no-require-gnu-tar.patch
@@ -0,0 +1,10 @@
+--- a/kernel/gen_kheaders.sh 2021-10-31 20:53:10.000000000 +0000
++++ b/kernel/gen_kheaders.sh 2022-01-06 19:01:21.940000000 +0000
+@@ -85,7 +85,6 @@
+ # pre-sorted, as --sort=name might not be available.
+ find $cpio_dir -printf "./%P\n" | LC_ALL=C sort | \
+ tar "${KBUILD_BUILD_TIMESTAMP:+--mtime=$KBUILD_BUILD_TIMESTAMP}" \
+- --owner=0 --group=0 --numeric-owner --no-recursion \
+ -I $XZ -cf $tarfile -C $cpio_dir/ -T - > /dev/null
+
+ echo $headers_md5 > kernel/kheaders.md5
diff --git a/system/easy-kernel/no-require-lilo.patch b/system/easy-kernel/no-require-lilo.patch
new file mode 100644
index 000000000..6549b67c6
--- /dev/null
+++ b/system/easy-kernel/no-require-lilo.patch
@@ -0,0 +1,15 @@
+--- a/arch/x86/boot/install.sh 2021-10-31 20:53:10.000000000 +0000
++++ b/arch/x86/boot/install.sh 2022-01-06 19:35:31.180000000 +0000
+@@ -48,12 +48,3 @@
+
+ cat $2 > $4/vmlinuz
+ cp $3 $4/System.map
+-
+-if [ -x /sbin/lilo ]; then
+- /sbin/lilo
+-elif [ -x /etc/lilo/install ]; then
+- /etc/lilo/install
+-else
+- sync
+- echo "Cannot find LILO."
+-fi
diff --git a/system/easy-kernel/uapi-iphdr.patch b/system/easy-kernel/uapi-iphdr.patch
deleted file mode 100644
index 8436b035b..000000000
--- a/system/easy-kernel/uapi-iphdr.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 62689a5371ff8bbfc8c04625794c62d957b0863f Mon Sep 17 00:00:00 2001
-From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
-Date: Sat, 21 Dec 2019 23:36:33 -0600
-Subject: [PATCH] uapi: Prevent redefinition of struct iphdr
-
-As with struct ethhdr, the musl libc provides its own definition of the
-iphdr struct. This guard ensures software like net-tools builds correctly
-on the musl libc.
-
-The __UAPI_DEF_IPHDR definition is in ip.h itself to prevent the issue in
-commit da360299b673 ("uapi/if_ether.h: move __UAPI_DEF_ETHHDR libc define")
-from being seen here.
-
-Signed-off-by: A. Wilcox <AWilcox@Wilcox-Tech.com>
----
- include/uapi/linux/ip.h | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
-index e42d13b55cf3..d34a0d295672 100644
---- a/include/uapi/linux/ip.h
-+++ b/include/uapi/linux/ip.h
-@@ -83,6 +83,13 @@
-
- #define IPV4_BEET_PHMAXLEN 8
-
-+/* Allow libcs to deactivate this - musl has its own copy in <netinet/ip.h> */
-+
-+#ifndef __UAPI_DEF_IPHDR
-+#define __UAPI_DEF_IPHDR 1
-+#endif
-+
-+#if __UAPI_DEF_IPHDR
- struct iphdr {
- #if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 ihl:4,
-@@ -104,6 +111,7 @@ struct iphdr {
- __be32 daddr;
- /*The options start here. */
- };
-+#endif
-
-
- struct ip_auth_hdr {
---
-2.22.1
-