summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlice Ferrazzi <alicef@gentoo.org>2018-02-17 14:25:08 +0000
committerAlice Ferrazzi <alicef@gentoo.org>2018-02-17 14:25:08 +0000
commitd6237b6da0d6c278d18543a00c55cda4bbc53075 (patch)
tree0105f57348cda9f4cb84b3ac8a64df0d9e06e2fd
parentlinux kernel 4.14.19 (diff)
downloadlinux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.tar.gz
linux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.tar.bz2
linux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.zip
linux kernel 4.14.20
-rw-r--r--0000_README4
-rw-r--r--1018_linux-4.14.20.patch10698
2 files changed, 10702 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index b7c928d0..7fd6d67b 100644
--- a/0000_README
+++ b/0000_README
@@ -119,6 +119,10 @@ Patch: 1018_linux-4.14.19.patch
From: http://www.kernel.org
Desc: Linux 4.14.19
+Patch: 1019_linux-4.14.20.patch
+From: http://www.kernel.org
+Desc: Linux 4.14.20
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1018_linux-4.14.20.patch b/1018_linux-4.14.20.patch
new file mode 100644
index 00000000..0cea7cc2
--- /dev/null
+++ b/1018_linux-4.14.20.patch
@@ -0,0 +1,10698 @@
+diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
+index 66e8ce14d23d..f3d0d316d5f1 100644
+--- a/Documentation/arm64/silicon-errata.txt
++++ b/Documentation/arm64/silicon-errata.txt
+@@ -71,6 +71,7 @@ stable kernels.
+ | Hisilicon | Hip0{5,6,7} | #161010101 | HISILICON_ERRATUM_161010101 |
+ | Hisilicon | Hip0{6,7} | #161010701 | N/A |
+ | | | | |
+-| Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
++| Qualcomm Tech. | Kryo/Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
+ | Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
+ | Qualcomm Tech. | QDF2400 ITS | E0065 | QCOM_QDF2400_ERRATUM_0065 |
++| Qualcomm Tech. | Falkor v{1,2} | E1041 | QCOM_FALKOR_ERRATUM_1041 |
+diff --git a/Makefile b/Makefile
+index 76a0b13623f4..33176140f133 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 4
+ PATCHLEVEL = 14
+-SUBLEVEL = 19
++SUBLEVEL = 20
+ EXTRAVERSION =
+ NAME = Petit Gorille
+
+@@ -416,7 +416,8 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
+ export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
+
+ export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
+-export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_KASAN CFLAGS_UBSAN
++export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
++export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN
+ export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+ export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
+ export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
+index d2e4da93e68c..ca3322536f72 100644
+--- a/arch/alpha/include/asm/futex.h
++++ b/arch/alpha/include/asm/futex.h
+@@ -20,8 +20,8 @@
+ "3: .subsection 2\n" \
+ "4: br 1b\n" \
+ " .previous\n" \
+- EXC(1b,3b,%1,$31) \
+- EXC(2b,3b,%1,$31) \
++ EXC(1b,3b,$31,%1) \
++ EXC(2b,3b,$31,%1) \
+ : "=&r" (oldval), "=&r"(ret) \
+ : "r" (uaddr), "r"(oparg) \
+ : "memory")
+@@ -82,8 +82,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ "3: .subsection 2\n"
+ "4: br 1b\n"
+ " .previous\n"
+- EXC(1b,3b,%0,$31)
+- EXC(2b,3b,%0,$31)
++ EXC(1b,3b,$31,%0)
++ EXC(2b,3b,$31,%0)
+ : "+r"(ret), "=&r"(prev), "=&r"(cmp)
+ : "r"(uaddr), "r"((long)(int)oldval), "r"(newval)
+ : "memory");
+diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
+index ce3a675c0c4b..75a5c35a2067 100644
+--- a/arch/alpha/kernel/osf_sys.c
++++ b/arch/alpha/kernel/osf_sys.c
+@@ -964,8 +964,8 @@ static inline long
+ put_tv32(struct timeval32 __user *o, struct timeval *i)
+ {
+ return copy_to_user(o, &(struct timeval32){
+- .tv_sec = o->tv_sec,
+- .tv_usec = o->tv_usec},
++ .tv_sec = i->tv_sec,
++ .tv_usec = i->tv_usec},
+ sizeof(struct timeval32));
+ }
+
+diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
+index 26231601630e..f332d88ffaff 100644
+--- a/arch/alpha/kernel/pci_impl.h
++++ b/arch/alpha/kernel/pci_impl.h
+@@ -144,7 +144,8 @@ struct pci_iommu_arena
+ };
+
+ #if defined(CONFIG_ALPHA_SRM) && \
+- (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
++ (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
++ defined(CONFIG_ALPHA_AVANTI))
+ # define NEED_SRM_SAVE_RESTORE
+ #else
+ # undef NEED_SRM_SAVE_RESTORE
+diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
+index 74bfb1f2d68e..3a885253f486 100644
+--- a/arch/alpha/kernel/process.c
++++ b/arch/alpha/kernel/process.c
+@@ -269,12 +269,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
+ application calling fork. */
+ if (clone_flags & CLONE_SETTLS)
+ childti->pcb.unique = regs->r20;
++ else
++ regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
+ childti->pcb.usp = usp ?: rdusp();
+ *childregs = *regs;
+ childregs->r0 = 0;
+ childregs->r19 = 0;
+ childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
+- regs->r20 = 0;
+ stack = ((struct switch_stack *) regs) - 1;
+ *childstack = *stack;
+ childstack->r26 = (unsigned long) ret_from_fork;
+diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
+index 4bd99a7b1c41..f43bd05dede2 100644
+--- a/arch/alpha/kernel/traps.c
++++ b/arch/alpha/kernel/traps.c
+@@ -160,11 +160,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
+ for(i=0; i < kstack_depth_to_print; i++) {
+ if (((long) stack & (THREAD_SIZE-1)) == 0)
+ break;
+- if (i && ((i % 4) == 0))
+- printk("\n ");
+- printk("%016lx ", *stack++);
++ if ((i % 4) == 0) {
++ if (i)
++ pr_cont("\n");
++ printk(" ");
++ } else {
++ pr_cont(" ");
++ }
++ pr_cont("%016lx", *stack++);
+ }
+- printk("\n");
++ pr_cont("\n");
+ dik_show_trace(sp);
+ }
+
+diff --git a/arch/arm/crypto/crc32-ce-glue.c b/arch/arm/crypto/crc32-ce-glue.c
+index 1b0e0e86ee9c..96e62ec105d0 100644
+--- a/arch/arm/crypto/crc32-ce-glue.c
++++ b/arch/arm/crypto/crc32-ce-glue.c
+@@ -188,6 +188,7 @@ static struct shash_alg crc32_pmull_algs[] = { {
+ .base.cra_name = "crc32",
+ .base.cra_driver_name = "crc32-arm-ce",
+ .base.cra_priority = 200,
++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+ }, {
+@@ -203,6 +204,7 @@ static struct shash_alg crc32_pmull_algs[] = { {
+ .base.cra_name = "crc32c",
+ .base.cra_driver_name = "crc32c-arm-ce",
+ .base.cra_priority = 200,
++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+ } };
+diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
+index 4a879f6ff13b..31fbb9285f62 100644
+--- a/arch/arm/include/asm/kvm_host.h
++++ b/arch/arm/include/asm/kvm_host.h
+@@ -293,4 +293,10 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
+ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr);
+
++static inline bool kvm_arm_harden_branch_predictor(void)
++{
++ /* No way to detect it yet, pretend it is not there. */
++ return false;
++}
++
+ #endif /* __ARM_KVM_HOST_H__ */
+diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
+index fa6f2174276b..eb46fc81a440 100644
+--- a/arch/arm/include/asm/kvm_mmu.h
++++ b/arch/arm/include/asm/kvm_mmu.h
+@@ -221,6 +221,16 @@ static inline unsigned int kvm_get_vmid_bits(void)
+ return 8;
+ }
+
++static inline void *kvm_get_hyp_vector(void)
++{
++ return kvm_ksym_ref(__kvm_hyp_vector);
++}
++
++static inline int kvm_map_vectors(void)
++{
++ return 0;
++}
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif /* __ARM_KVM_MMU_H__ */
+diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h
+deleted file mode 100644
+index 6bda945d31fa..000000000000
+--- a/arch/arm/include/asm/kvm_psci.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * Copyright (C) 2012 - ARM Ltd
+- * Author: Marc Zyngier <marc.zyngier@arm.com>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#ifndef __ARM_KVM_PSCI_H__
+-#define __ARM_KVM_PSCI_H__
+-
+-#define KVM_ARM_PSCI_0_1 1
+-#define KVM_ARM_PSCI_0_2 2
+-
+-int kvm_psci_version(struct kvm_vcpu *vcpu);
+-int kvm_psci_call(struct kvm_vcpu *vcpu);
+-
+-#endif /* __ARM_KVM_PSCI_H__ */
+diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
+index cf8bf6bf87c4..910bd8dabb3c 100644
+--- a/arch/arm/kvm/handle_exit.c
++++ b/arch/arm/kvm/handle_exit.c
+@@ -21,7 +21,7 @@
+ #include <asm/kvm_emulate.h>
+ #include <asm/kvm_coproc.h>
+ #include <asm/kvm_mmu.h>
+-#include <asm/kvm_psci.h>
++#include <kvm/arm_psci.h>
+ #include <trace/events/kvm.h>
+
+ #include "trace.h"
+@@ -36,9 +36,9 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+ kvm_vcpu_hvc_get_imm(vcpu));
+ vcpu->stat.hvc_exit_stat++;
+
+- ret = kvm_psci_call(vcpu);
++ ret = kvm_hvc_call_handler(vcpu);
+ if (ret < 0) {
+- kvm_inject_undefined(vcpu);
++ vcpu_set_reg(vcpu, 0, ~0UL);
+ return 1;
+ }
+
+@@ -47,7 +47,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+
+ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+ {
+- kvm_inject_undefined(vcpu);
++ /*
++ * "If an SMC instruction executed at Non-secure EL1 is
++ * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
++ * Trap exception, not a Secure Monitor Call exception [...]"
++ *
++ * We need to advance the PC after the trap, as it would
++ * otherwise return to the same address...
++ */
++ vcpu_set_reg(vcpu, 0, ~0UL);
++ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+ return 1;
+ }
+
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 0df64a6a56d4..c2abb4e88ff2 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -504,20 +504,13 @@ config CAVIUM_ERRATUM_30115
+ config QCOM_FALKOR_ERRATUM_1003
+ bool "Falkor E1003: Incorrect translation due to ASID change"
+ default y
+- select ARM64_PAN if ARM64_SW_TTBR0_PAN
+ help
+ On Falkor v1, an incorrect ASID may be cached in the TLB when ASID
+- and BADDR are changed together in TTBRx_EL1. The workaround for this
+- issue is to use a reserved ASID in cpu_do_switch_mm() before
+- switching to the new ASID. Saying Y here selects ARM64_PAN if
+- ARM64_SW_TTBR0_PAN is selected. This is done because implementing and
+- maintaining the E1003 workaround in the software PAN emulation code
+- would be an unnecessary complication. The affected Falkor v1 CPU
+- implements ARMv8.1 hardware PAN support and using hardware PAN
+- support versus software PAN emulation is mutually exclusive at
+- runtime.
+-
+- If unsure, say Y.
++ and BADDR are changed together in TTBRx_EL1. Since we keep the ASID
++ in TTBR1_EL1, this situation only occurs in the entry trampoline and
++ then only for entries in the walk cache, since the leaf translation
++ is unchanged. Work around the erratum by invalidating the walk cache
++ entries for the trampoline before entering the kernel proper.
+
+ config QCOM_FALKOR_ERRATUM_1009
+ bool "Falkor E1009: Prematurely complete a DSB after a TLBI"
+@@ -539,6 +532,16 @@ config QCOM_QDF2400_ERRATUM_0065
+
+ If unsure, say Y.
+
++config QCOM_FALKOR_ERRATUM_E1041
++ bool "Falkor E1041: Speculative instruction fetches might cause errant memory access"
++ default y
++ help
++ Falkor CPU may speculatively fetch instructions from an improper
++ memory location when MMU translation is changed from SCTLR_ELn[M]=1
++ to SCTLR_ELn[M]=0. Prefix an ISB instruction to fix the problem.
++
++ If unsure, say Y.
++
+ endmenu
+
+
+@@ -803,6 +806,35 @@ config FORCE_MAX_ZONEORDER
+ However for 4K, we choose a higher default value, 11 as opposed to 10, giving us
+ 4M allocations matching the default size used by generic code.
+
++config UNMAP_KERNEL_AT_EL0
++ bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT
++ default y
++ help
++ Speculation attacks against some high-performance processors can
++ be used to bypass MMU permission checks and leak kernel data to
++ userspace. This can be defended against by unmapping the kernel
++ when running in userspace, mapping it back in on exception entry
++ via a trampoline page in the vector table.
++
++ If unsure, say Y.
++
++config HARDEN_BRANCH_PREDICTOR
++ bool "Harden the branch predictor against aliasing attacks" if EXPERT
++ default y
++ help
++ Speculation attacks against some high-performance processors rely on
++ being able to manipulate the branch predictor for a victim context by
++ executing aliasing branches in the attacker context. Such attacks
++ can be partially mitigated against by clearing internal branch
++ predictor state and limiting the prediction logic in some situations.
++
++ This config option will take CPU-specific actions to harden the
++ branch predictor against aliasing attacks and may rely on specific
++ instruction sequences or control bits being set by the system
++ firmware.
++
++ If unsure, say Y.
++
+ menuconfig ARMV8_DEPRECATED
+ bool "Emulate deprecated/obsolete ARMv8 instructions"
+ depends on COMPAT
+diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
+index 9c3bdf87e543..51327645b3fb 100644
+--- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
++++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
+@@ -61,6 +61,12 @@
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
++ aliases {
++ ethernet0 = &cpm_eth0;
++ ethernet1 = &cpm_eth1;
++ ethernet2 = &cpm_eth2;
++ };
++
+ cpm_reg_usb3_0_vbus: cpm-usb3-0-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb3h0-vbus";
+diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
+index 0d7b2ae46610..a4f82f1efbbc 100644
+--- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts
++++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
+@@ -61,6 +61,13 @@
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
++ aliases {
++ ethernet0 = &cpm_eth0;
++ ethernet1 = &cpm_eth2;
++ ethernet2 = &cps_eth0;
++ ethernet3 = &cps_eth1;
++ };
++
+ cpm_reg_usb3_0_vbus: cpm-usb3-0-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "cpm-usb3h0-vbus";
+diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
+index acf5c7d16d79..2b6b792dab93 100644
+--- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
++++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
+@@ -62,6 +62,12 @@
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
++ aliases {
++ ethernet0 = &cpm_eth0;
++ ethernet1 = &cps_eth0;
++ ethernet2 = &cps_eth1;
++ };
++
+ /* Regulator labels correspond with schematics */
+ v_3_3: regulator-3-3v {
+ compatible = "regulator-fixed";
+diff --git a/arch/arm64/crypto/crc32-ce-glue.c b/arch/arm64/crypto/crc32-ce-glue.c
+index 624f4137918c..34b4e3d46aab 100644
+--- a/arch/arm64/crypto/crc32-ce-glue.c
++++ b/arch/arm64/crypto/crc32-ce-glue.c
+@@ -185,6 +185,7 @@ static struct shash_alg crc32_pmull_algs[] = { {
+ .base.cra_name = "crc32",
+ .base.cra_driver_name = "crc32-arm64-ce",
+ .base.cra_priority = 200,
++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+ }, {
+@@ -200,6 +201,7 @@ static struct shash_alg crc32_pmull_algs[] = { {
+ .base.cra_name = "crc32c",
+ .base.cra_driver_name = "crc32c-arm64-ce",
+ .base.cra_priority = 200,
++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .base.cra_blocksize = 1,
+ .base.cra_module = THIS_MODULE,
+ } };
+diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
+index b3da6c886835..dd49c3567f20 100644
+--- a/arch/arm64/include/asm/asm-uaccess.h
++++ b/arch/arm64/include/asm/asm-uaccess.h
+@@ -4,6 +4,7 @@
+
+ #include <asm/alternative.h>
+ #include <asm/kernel-pgtable.h>
++#include <asm/mmu.h>
+ #include <asm/sysreg.h>
+ #include <asm/assembler.h>
+
+@@ -13,51 +14,62 @@
+ #ifdef CONFIG_ARM64_SW_TTBR0_PAN
+ .macro __uaccess_ttbr0_disable, tmp1
+ mrs \tmp1, ttbr1_el1 // swapper_pg_dir
++ bic \tmp1, \tmp1, #TTBR_ASID_MASK
+ add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir
+ msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
+ isb
++ sub \tmp1, \tmp1, #SWAPPER_DIR_SIZE
++ msr ttbr1_el1, \tmp1 // set reserved ASID
++ isb
+ .endm
+
+- .macro __uaccess_ttbr0_enable, tmp1
++ .macro __uaccess_ttbr0_enable, tmp1, tmp2
+ get_thread_info \tmp1
+ ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1
++ mrs \tmp2, ttbr1_el1
++ extr \tmp2, \tmp2, \tmp1, #48
++ ror \tmp2, \tmp2, #16
++ msr ttbr1_el1, \tmp2 // set the active ASID
++ isb
+ msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1
+ isb
+ .endm
+
+- .macro uaccess_ttbr0_disable, tmp1
++ .macro uaccess_ttbr0_disable, tmp1, tmp2
+ alternative_if_not ARM64_HAS_PAN
++ save_and_disable_irq \tmp2 // avoid preemption
+ __uaccess_ttbr0_disable \tmp1
++ restore_irq \tmp2
+ alternative_else_nop_endif
+ .endm
+
+- .macro uaccess_ttbr0_enable, tmp1, tmp2
++ .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
+ alternative_if_not ARM64_HAS_PAN
+- save_and_disable_irq \tmp2 // avoid preemption
+- __uaccess_ttbr0_enable \tmp1
+- restore_irq \tmp2
++ save_and_disable_irq \tmp3 // avoid preemption
++ __uaccess_ttbr0_enable \tmp1, \tmp2
++ restore_irq \tmp3
+ alternative_else_nop_endif
+ .endm
+ #else
+- .macro uaccess_ttbr0_disable, tmp1
++ .macro uaccess_ttbr0_disable, tmp1, tmp2
+ .endm
+
+- .macro uaccess_ttbr0_enable, tmp1, tmp2
++ .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
+ .endm
+ #endif
+
+ /*
+ * These macros are no-ops when UAO is present.
+ */
+- .macro uaccess_disable_not_uao, tmp1
+- uaccess_ttbr0_disable \tmp1
++ .macro uaccess_disable_not_uao, tmp1, tmp2
++ uaccess_ttbr0_disable \tmp1, \tmp2
+ alternative_if ARM64_ALT_PAN_NOT_UAO
+ SET_PSTATE_PAN(1)
+ alternative_else_nop_endif
+ .endm
+
+- .macro uaccess_enable_not_uao, tmp1, tmp2
+- uaccess_ttbr0_enable \tmp1, \tmp2
++ .macro uaccess_enable_not_uao, tmp1, tmp2, tmp3
++ uaccess_ttbr0_enable \tmp1, \tmp2, \tmp3
+ alternative_if ARM64_ALT_PAN_NOT_UAO
+ SET_PSTATE_PAN(0)
+ alternative_else_nop_endif
+diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
+index d58a6253c6ab..463619dcadd4 100644
+--- a/arch/arm64/include/asm/assembler.h
++++ b/arch/arm64/include/asm/assembler.h
+@@ -25,7 +25,6 @@
+
+ #include <asm/asm-offsets.h>
+ #include <asm/cpufeature.h>
+-#include <asm/mmu_context.h>
+ #include <asm/page.h>
+ #include <asm/pgtable-hwdef.h>
+ #include <asm/ptrace.h>
+@@ -96,6 +95,24 @@
+ dmb \opt
+ .endm
+
++/*
++ * Value prediction barrier
++ */
++ .macro csdb
++ hint #20
++ .endm
++
++/*
++ * Sanitise a 64-bit bounded index wrt speculation, returning zero if out
++ * of bounds.
++ */
++ .macro mask_nospec64, idx, limit, tmp
++ sub \tmp, \idx, \limit
++ bic \tmp, \tmp, \idx
++ and \idx, \idx, \tmp, asr #63
++ csdb
++ .endm
++
+ /*
+ * NOP sequence
+ */
+@@ -464,39 +481,18 @@ alternative_endif
+ mrs \rd, sp_el0
+ .endm
+
+-/*
+- * Errata workaround prior to TTBR0_EL1 update
+- *
+- * val: TTBR value with new BADDR, preserved
+- * tmp0: temporary register, clobbered
+- * tmp1: other temporary register, clobbered
++/**
++ * Errata workaround prior to disable MMU. Insert an ISB immediately prior
++ * to executing the MSR that will change SCTLR_ELn[M] from a value of 1 to 0.
+ */
+- .macro pre_ttbr0_update_workaround, val, tmp0, tmp1
+-#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
+-alternative_if ARM64_WORKAROUND_QCOM_FALKOR_E1003
+- mrs \tmp0, ttbr0_el1
+- mov \tmp1, #FALKOR_RESERVED_ASID
+- bfi \tmp0, \tmp1, #48, #16 // reserved ASID + old BADDR
+- msr ttbr0_el1, \tmp0
++ .macro pre_disable_mmu_workaround
++#ifdef CONFIG_QCOM_FALKOR_ERRATUM_E1041
+ isb
+- bfi \tmp0, \val, #0, #48 // reserved ASID + new BADDR
+- msr ttbr0_el1, \tmp0
+- isb
+-alternative_else_nop_endif
+ #endif
+ .endm
+
+-/*
+- * Errata workaround post TTBR0_EL1 update.
+- */
+- .macro post_ttbr0_update_workaround
+-#ifdef CONFIG_CAVIUM_ERRATUM_27456
+-alternative_if ARM64_WORKAROUND_CAVIUM_27456
+- ic iallu
+- dsb nsh
+- isb
+-alternative_else_nop_endif
+-#endif
++ .macro pte_to_phys, phys, pte
++ and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT)
+ .endm
+
+ #endif /* __ASM_ASSEMBLER_H */
+diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
+index 0fe7e43b7fbc..0b0755c961ac 100644
+--- a/arch/arm64/include/asm/barrier.h
++++ b/arch/arm64/include/asm/barrier.h
+@@ -31,6 +31,8 @@
+ #define dmb(opt) asm volatile("dmb " #opt : : : "memory")
+ #define dsb(opt) asm volatile("dsb " #opt : : : "memory")
+
++#define csdb() asm volatile("hint #20" : : : "memory")
++
+ #define mb() dsb(sy)
+ #define rmb() dsb(ld)
+ #define wmb() dsb(st)
+@@ -38,6 +40,27 @@
+ #define dma_rmb() dmb(oshld)
+ #define dma_wmb() dmb(oshst)
+
++/*
++ * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz
++ * and 0 otherwise.
++ */
++#define array_index_mask_nospec array_index_mask_nospec
++static inline unsigned long array_index_mask_nospec(unsigned long idx,
++ unsigned long sz)
++{
++ unsigned long mask;
++
++ asm volatile(
++ " cmp %1, %2\n"
++ " sbc %0, xzr, xzr\n"
++ : "=r" (mask)
++ : "r" (idx), "Ir" (sz)
++ : "cc");
++
++ csdb();
++ return mask;
++}
++
+ #define __smp_mb() dmb(ish)
+ #define __smp_rmb() dmb(ishld)
+ #define __smp_wmb() dmb(ishst)
+diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
+index 8da621627d7c..2e7b236bc596 100644
+--- a/arch/arm64/include/asm/cpucaps.h
++++ b/arch/arm64/include/asm/cpucaps.h
+@@ -40,7 +40,10 @@
+ #define ARM64_WORKAROUND_858921 19
+ #define ARM64_WORKAROUND_CAVIUM_30115 20
+ #define ARM64_HAS_DCPOP 21
++#define ARM64_UNMAP_KERNEL_AT_EL0 23
++#define ARM64_HARDEN_BRANCH_PREDICTOR 24
++#define ARM64_HARDEN_BP_POST_GUEST_EXIT 25
+
+-#define ARM64_NCAPS 22
++#define ARM64_NCAPS 26
+
+ #endif /* __ASM_CPUCAPS_H */
+diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
+index 235e77d98261..be7bd19c87ec 100644
+--- a/arch/arm64/include/asm/cputype.h
++++ b/arch/arm64/include/asm/cputype.h
+@@ -79,26 +79,37 @@
+ #define ARM_CPU_PART_AEM_V8 0xD0F
+ #define ARM_CPU_PART_FOUNDATION 0xD00
+ #define ARM_CPU_PART_CORTEX_A57 0xD07
++#define ARM_CPU_PART_CORTEX_A72 0xD08
+ #define ARM_CPU_PART_CORTEX_A53 0xD03
+ #define ARM_CPU_PART_CORTEX_A73 0xD09
++#define ARM_CPU_PART_CORTEX_A75 0xD0A
+
+ #define APM_CPU_PART_POTENZA 0x000
+
+ #define CAVIUM_CPU_PART_THUNDERX 0x0A1
+ #define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2
+ #define CAVIUM_CPU_PART_THUNDERX_83XX 0x0A3
++#define CAVIUM_CPU_PART_THUNDERX2 0x0AF
+
+ #define BRCM_CPU_PART_VULCAN 0x516
+
+ #define QCOM_CPU_PART_FALKOR_V1 0x800
++#define QCOM_CPU_PART_FALKOR 0xC00
++#define QCOM_CPU_PART_KRYO 0x200
+
+ #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+ #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
++#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
+ #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
++#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+ #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
+ #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
+ #define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
++#define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2)
++#define MIDR_BRCM_VULCAN MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN)
+ #define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
++#define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR)
++#define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO)
+
+ #ifndef __ASSEMBLY__
+
+diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
+index c4cd5081d78b..8389050328bb 100644
+--- a/arch/arm64/include/asm/efi.h
++++ b/arch/arm64/include/asm/efi.h
+@@ -121,19 +121,21 @@ static inline void efi_set_pgd(struct mm_struct *mm)
+ if (mm != current->active_mm) {
+ /*
+ * Update the current thread's saved ttbr0 since it is
+- * restored as part of a return from exception. Set
+- * the hardware TTBR0_EL1 using cpu_switch_mm()
+- * directly to enable potential errata workarounds.
++ * restored as part of a return from exception. Enable
++ * access to the valid TTBR0_EL1 and invoke the errata
++ * workaround directly since there is no return from
++ * exception when invoking the EFI run-time services.
+ */
+ update_saved_ttbr0(current, mm);
+- cpu_switch_mm(mm->pgd, mm);
++ uaccess_ttbr0_enable();
++ post_ttbr_update_workaround();
+ } else {
+ /*
+ * Defer the switch to the current thread's TTBR0_EL1
+ * until uaccess_enable(). Restore the current
+ * thread's saved ttbr0 corresponding to its active_mm
+ */
+- cpu_set_reserved_ttbr0();
++ uaccess_ttbr0_disable();
+ update_saved_ttbr0(current, current->active_mm);
+ }
+ }
+diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
+index 4052ec39e8db..ec1e6d6fa14c 100644
+--- a/arch/arm64/include/asm/fixmap.h
++++ b/arch/arm64/include/asm/fixmap.h
+@@ -58,6 +58,11 @@ enum fixed_addresses {
+ FIX_APEI_GHES_NMI,
+ #endif /* CONFIG_ACPI_APEI_GHES */
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ FIX_ENTRY_TRAMP_DATA,
++ FIX_ENTRY_TRAMP_TEXT,
++#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
++#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
+ __end_of_permanent_fixed_addresses,
+
+ /*
+diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
+index 5bb2fd4674e7..07fe2479d310 100644
+--- a/arch/arm64/include/asm/futex.h
++++ b/arch/arm64/include/asm/futex.h
+@@ -48,9 +48,10 @@ do { \
+ } while (0)
+
+ static inline int
+-arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
++arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
+ {
+ int oldval = 0, ret, tmp;
++ u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
+
+ pagefault_disable();
+
+@@ -88,15 +89,17 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+ }
+
+ static inline int
+-futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
++futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
+ u32 oldval, u32 newval)
+ {
+ int ret = 0;
+ u32 val, tmp;
++ u32 __user *uaddr;
+
+- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
++ if (!access_ok(VERIFY_WRITE, _uaddr, sizeof(u32)))
+ return -EFAULT;
+
++ uaddr = __uaccess_mask_ptr(_uaddr);
+ uaccess_enable();
+ asm volatile("// futex_atomic_cmpxchg_inatomic\n"
+ " prfm pstl1strm, %2\n"
+diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
+index 26a64d0f9ab9..a7ef5a051911 100644
+--- a/arch/arm64/include/asm/kvm_asm.h
++++ b/arch/arm64/include/asm/kvm_asm.h
+@@ -66,6 +66,8 @@ extern u32 __kvm_get_mdcr_el2(void);
+
+ extern u32 __init_stage2_translation(void);
+
++extern void __qcom_hyp_sanitize_btac_predictors(void);
++
+ #endif
+
+ #endif /* __ARM_KVM_ASM_H__ */
+diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
+index e923b58606e2..8ad208cb866c 100644
+--- a/arch/arm64/include/asm/kvm_host.h
++++ b/arch/arm64/include/asm/kvm_host.h
+@@ -384,4 +384,9 @@ static inline void __cpu_init_stage2(void)
+ "PARange is %d bits, unsupported configuration!", parange);
+ }
+
++static inline bool kvm_arm_harden_branch_predictor(void)
++{
++ return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
++}
++
+ #endif /* __ARM64_KVM_HOST_H__ */
+diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
+index 672c8684d5c2..2d6d4bd9de52 100644
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -309,5 +309,43 @@ static inline unsigned int kvm_get_vmid_bits(void)
+ return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
+ }
+
++#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
++#include <asm/mmu.h>
++
++static inline void *kvm_get_hyp_vector(void)
++{
++ struct bp_hardening_data *data = arm64_get_bp_hardening_data();
++ void *vect = kvm_ksym_ref(__kvm_hyp_vector);
++
++ if (data->fn) {
++ vect = __bp_harden_hyp_vecs_start +
++ data->hyp_vectors_slot * SZ_2K;
++
++ if (!has_vhe())
++ vect = lm_alias(vect);
++ }
++
++ return vect;
++}
++
++static inline int kvm_map_vectors(void)
++{
++ return create_hyp_mappings(kvm_ksym_ref(__bp_harden_hyp_vecs_start),
++ kvm_ksym_ref(__bp_harden_hyp_vecs_end),
++ PAGE_HYP_EXEC);
++}
++
++#else
++static inline void *kvm_get_hyp_vector(void)
++{
++ return kvm_ksym_ref(__kvm_hyp_vector);
++}
++
++static inline int kvm_map_vectors(void)
++{
++ return 0;
++}
++#endif
++
+ #endif /* __ASSEMBLY__ */
+ #endif /* __ARM64_KVM_MMU_H__ */
+diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h
+deleted file mode 100644
+index bc39e557c56c..000000000000
+--- a/arch/arm64/include/asm/kvm_psci.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * Copyright (C) 2012,2013 - ARM Ltd
+- * Author: Marc Zyngier <marc.zyngier@arm.com>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#ifndef __ARM64_KVM_PSCI_H__
+-#define __ARM64_KVM_PSCI_H__
+-
+-#define KVM_ARM_PSCI_0_1 1
+-#define KVM_ARM_PSCI_0_2 2
+-
+-int kvm_psci_version(struct kvm_vcpu *vcpu);
+-int kvm_psci_call(struct kvm_vcpu *vcpu);
+-
+-#endif /* __ARM64_KVM_PSCI_H__ */
+diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
+index f7c4d2146aed..d4bae7d6e0d8 100644
+--- a/arch/arm64/include/asm/memory.h
++++ b/arch/arm64/include/asm/memory.h
+@@ -61,8 +61,6 @@
+ * KIMAGE_VADDR - the virtual address of the start of the kernel image
+ * VA_BITS - the maximum number of bits for virtual addresses.
+ * VA_START - the first kernel virtual address.
+- * TASK_SIZE - the maximum size of a user space task.
+- * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
+ */
+ #define VA_BITS (CONFIG_ARM64_VA_BITS)
+ #define VA_START (UL(0xffffffffffffffff) - \
+@@ -77,19 +75,6 @@
+ #define PCI_IO_END (VMEMMAP_START - SZ_2M)
+ #define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
+ #define FIXADDR_TOP (PCI_IO_START - SZ_2M)
+-#define TASK_SIZE_64 (UL(1) << VA_BITS)
+-
+-#ifdef CONFIG_COMPAT
+-#define TASK_SIZE_32 UL(0x100000000)
+-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+- TASK_SIZE_32 : TASK_SIZE_64)
+-#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
+- TASK_SIZE_32 : TASK_SIZE_64)
+-#else
+-#define TASK_SIZE TASK_SIZE_64
+-#endif /* CONFIG_COMPAT */
+-
+-#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
+
+ #define KERNEL_START _text
+ #define KERNEL_END _end
+diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
+index 0d34bf0a89c7..6dd83d75b82a 100644
+--- a/arch/arm64/include/asm/mmu.h
++++ b/arch/arm64/include/asm/mmu.h
+@@ -17,6 +17,10 @@
+ #define __ASM_MMU_H
+
+ #define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */
++#define USER_ASID_FLAG (UL(1) << 48)
++#define TTBR_ASID_MASK (UL(0xffff) << 48)
++
++#ifndef __ASSEMBLY__
+
+ typedef struct {
+ atomic64_t id;
+@@ -31,6 +35,49 @@ typedef struct {
+ */
+ #define ASID(mm) ((mm)->context.id.counter & 0xffff)
+
++static inline bool arm64_kernel_unmapped_at_el0(void)
++{
++ return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) &&
++ cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
++}
++
++typedef void (*bp_hardening_cb_t)(void);
++
++struct bp_hardening_data {
++ int hyp_vectors_slot;
++ bp_hardening_cb_t fn;
++};
++
++#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
++extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[];
++
++DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
++
++static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
++{
++ return this_cpu_ptr(&bp_hardening_data);
++}
++
++static inline void arm64_apply_bp_hardening(void)
++{
++ struct bp_hardening_data *d;
++
++ if (!cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
++ return;
++
++ d = arm64_get_bp_hardening_data();
++ if (d->fn)
++ d->fn();
++}
++#else
++static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
++{
++ return NULL;
++}
++
++static inline void arm64_apply_bp_hardening(void) { }
++#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
++
+ extern void paging_init(void);
+ extern void bootmem_init(void);
+ extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
+@@ -41,4 +88,5 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
+ extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
+ extern void mark_linear_text_alias_ro(void);
+
++#endif /* !__ASSEMBLY__ */
+ #endif
+diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
+index 9d155fa9a507..779d7a2ec5ec 100644
+--- a/arch/arm64/include/asm/mmu_context.h
++++ b/arch/arm64/include/asm/mmu_context.h
+@@ -19,8 +19,6 @@
+ #ifndef __ASM_MMU_CONTEXT_H
+ #define __ASM_MMU_CONTEXT_H
+
+-#define FALKOR_RESERVED_ASID 1
+-
+ #ifndef __ASSEMBLY__
+
+ #include <linux/compiler.h>
+@@ -57,6 +55,13 @@ static inline void cpu_set_reserved_ttbr0(void)
+ isb();
+ }
+
++static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
++{
++ BUG_ON(pgd == swapper_pg_dir);
++ cpu_set_reserved_ttbr0();
++ cpu_do_switch_mm(virt_to_phys(pgd),mm);
++}
++
+ /*
+ * TCR.T0SZ value to use when the ID map is active. Usually equals
+ * TCR_T0SZ(VA_BITS), unless system RAM is positioned very high in
+@@ -170,7 +175,7 @@ static inline void update_saved_ttbr0(struct task_struct *tsk,
+ else
+ ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
+
+- task_thread_info(tsk)->ttbr0 = ttbr;
++ WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr);
+ }
+ #else
+ static inline void update_saved_ttbr0(struct task_struct *tsk,
+@@ -225,6 +230,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ #define activate_mm(prev,next) switch_mm(prev, next, current)
+
+ void verify_cpu_asid_bits(void);
++void post_ttbr_update_workaround(void);
+
+ #endif /* !__ASSEMBLY__ */
+
+diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
+index eb0c2bd90de9..8df4cb6ac6f7 100644
+--- a/arch/arm64/include/asm/pgtable-hwdef.h
++++ b/arch/arm64/include/asm/pgtable-hwdef.h
+@@ -272,6 +272,7 @@
+ #define TCR_TG1_4K (UL(2) << TCR_TG1_SHIFT)
+ #define TCR_TG1_64K (UL(3) << TCR_TG1_SHIFT)
+
++#define TCR_A1 (UL(1) << 22)
+ #define TCR_ASID16 (UL(1) << 36)
+ #define TCR_TBI0 (UL(1) << 37)
+ #define TCR_HA (UL(1) << 39)
+diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
+index 0a5635fb0ef9..2db84df5eb42 100644
+--- a/arch/arm64/include/asm/pgtable-prot.h
++++ b/arch/arm64/include/asm/pgtable-prot.h
+@@ -34,8 +34,14 @@
+
+ #include <asm/pgtable-types.h>
+
+-#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
+-#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
++#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
++#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
++
++#define PTE_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0)
++#define PMD_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0)
++
++#define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG)
++#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
+
+ #define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+ #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
+@@ -47,23 +53,24 @@
+ #define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
+ #define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
+
+-#define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
++#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
++#define _HYP_PAGE_DEFAULT _PAGE_DEFAULT
+
+-#define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
+-#define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+-#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+-#define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
+-#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
++#define PAGE_KERNEL __pgprot(PROT_NORMAL)
++#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
++#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
++#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN)
++#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
+
+-#define PAGE_HYP __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
+-#define PAGE_HYP_EXEC __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
+-#define PAGE_HYP_RO __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
++#define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
++#define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
++#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
+ #define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
+
+-#define PAGE_S2 __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
+-#define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
++#define PAGE_S2 __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
++#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
+
+-#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
++#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
+ #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
+ #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
+ #define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index 960d05c8816a..aafea648a30f 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -684,6 +684,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
+
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
++extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
+
+ /*
+ * Encode and decode a swap entry:
+diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h
+index 14ad6e4e87d1..16cef2e8449e 100644
+--- a/arch/arm64/include/asm/proc-fns.h
++++ b/arch/arm64/include/asm/proc-fns.h
+@@ -35,12 +35,6 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
+
+ #include <asm/memory.h>
+
+-#define cpu_switch_mm(pgd,mm) \
+-do { \
+- BUG_ON(pgd == swapper_pg_dir); \
+- cpu_do_switch_mm(virt_to_phys(pgd),mm); \
+-} while (0)
+-
+ #endif /* __ASSEMBLY__ */
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_PROCFNS_H */
+diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
+index 29adab8138c3..fda6f5812281 100644
+--- a/arch/arm64/include/asm/processor.h
++++ b/arch/arm64/include/asm/processor.h
+@@ -19,6 +19,13 @@
+ #ifndef __ASM_PROCESSOR_H
+ #define __ASM_PROCESSOR_H
+
++#define TASK_SIZE_64 (UL(1) << VA_BITS)
++
++#define KERNEL_DS UL(-1)
++#define USER_DS (TASK_SIZE_64 - 1)
++
++#ifndef __ASSEMBLY__
++
+ /*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+@@ -37,6 +44,22 @@
+ #include <asm/ptrace.h>
+ #include <asm/types.h>
+
++/*
++ * TASK_SIZE - the maximum size of a user space task.
++ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
++ */
++#ifdef CONFIG_COMPAT
++#define TASK_SIZE_32 UL(0x100000000)
++#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
++ TASK_SIZE_32 : TASK_SIZE_64)
++#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
++ TASK_SIZE_32 : TASK_SIZE_64)
++#else
++#define TASK_SIZE TASK_SIZE_64
++#endif /* CONFIG_COMPAT */
++
++#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
++
+ #define STACK_TOP_MAX TASK_SIZE_64
+ #ifdef CONFIG_COMPAT
+ #define AARCH32_VECTORS_BASE 0xffff0000
+@@ -194,4 +217,5 @@ static inline void spin_lock_prefetch(const void *ptr)
+ int cpu_enable_pan(void *__unused);
+ int cpu_enable_cache_maint_trap(void *__unused);
+
++#endif /* __ASSEMBLY__ */
+ #endif /* __ASM_PROCESSOR_H */
+diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
+index f707fed5886f..ede80d47d0ef 100644
+--- a/arch/arm64/include/asm/sysreg.h
++++ b/arch/arm64/include/asm/sysreg.h
+@@ -332,6 +332,8 @@
+ #define ID_AA64ISAR1_DPB_SHIFT 0
+
+ /* id_aa64pfr0 */
++#define ID_AA64PFR0_CSV3_SHIFT 60
++#define ID_AA64PFR0_CSV2_SHIFT 56
+ #define ID_AA64PFR0_GIC_SHIFT 24
+ #define ID_AA64PFR0_ASIMD_SHIFT 20
+ #define ID_AA64PFR0_FP_SHIFT 16
+diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
+index af1c76981911..9e82dd79c7db 100644
+--- a/arch/arm64/include/asm/tlbflush.h
++++ b/arch/arm64/include/asm/tlbflush.h
+@@ -23,6 +23,7 @@
+
+ #include <linux/sched.h>
+ #include <asm/cputype.h>
++#include <asm/mmu.h>
+
+ /*
+ * Raw TLBI operations.
+@@ -54,6 +55,11 @@
+
+ #define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0)
+
++#define __tlbi_user(op, arg) do { \
++ if (arm64_kernel_unmapped_at_el0()) \
++ __tlbi(op, (arg) | USER_ASID_FLAG); \
++} while (0)
++
+ /*
+ * TLB Management
+ * ==============
+@@ -115,6 +121,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
+
+ dsb(ishst);
+ __tlbi(aside1is, asid);
++ __tlbi_user(aside1is, asid);
+ dsb(ish);
+ }
+
+@@ -125,6 +132,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
+
+ dsb(ishst);
+ __tlbi(vale1is, addr);
++ __tlbi_user(vale1is, addr);
+ dsb(ish);
+ }
+
+@@ -151,10 +159,13 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
+
+ dsb(ishst);
+ for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) {
+- if (last_level)
++ if (last_level) {
+ __tlbi(vale1is, addr);
+- else
++ __tlbi_user(vale1is, addr);
++ } else {
+ __tlbi(vae1is, addr);
++ __tlbi_user(vae1is, addr);
++ }
+ }
+ dsb(ish);
+ }
+@@ -194,6 +205,7 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm,
+ unsigned long addr = uaddr >> 12 | (ASID(mm) << 48);
+
+ __tlbi(vae1is, addr);
++ __tlbi_user(vae1is, addr);
+ dsb(ish);
+ }
+
+diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
+index fc0f9eb66039..fad8c1b2ca3e 100644
+--- a/arch/arm64/include/asm/uaccess.h
++++ b/arch/arm64/include/asm/uaccess.h
+@@ -35,16 +35,20 @@
+ #include <asm/compiler.h>
+ #include <asm/extable.h>
+
+-#define KERNEL_DS (-1UL)
+ #define get_ds() (KERNEL_DS)
+-
+-#define USER_DS TASK_SIZE_64
+ #define get_fs() (current_thread_info()->addr_limit)
+
+ static inline void set_fs(mm_segment_t fs)
+ {
+ current_thread_info()->addr_limit = fs;
+
++ /*
++ * Prevent a mispredicted conditional call to set_fs from forwarding
++ * the wrong address limit to access_ok under speculation.
++ */
++ dsb(nsh);
++ isb();
++
+ /* On user-mode return, check fs is correct */
+ set_thread_flag(TIF_FSCHECK);
+
+@@ -66,22 +70,32 @@ static inline void set_fs(mm_segment_t fs)
+ * Returns 1 if the range is valid, 0 otherwise.
+ *
+ * This is equivalent to the following test:
+- * (u65)addr + (u65)size <= current->addr_limit
+- *
+- * This needs 65-bit arithmetic.
++ * (u65)addr + (u65)size <= (u65)current->addr_limit + 1
+ */
+-#define __range_ok(addr, size) \
+-({ \
+- unsigned long __addr = (unsigned long)(addr); \
+- unsigned long flag, roksum; \
+- __chk_user_ptr(addr); \
+- asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
+- : "=&r" (flag), "=&r" (roksum) \
+- : "1" (__addr), "Ir" (size), \
+- "r" (current_thread_info()->addr_limit) \
+- : "cc"); \
+- flag; \
+-})
++static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
++{
++ unsigned long limit = current_thread_info()->addr_limit;
++
++ __chk_user_ptr(addr);
++ asm volatile(
++ // A + B <= C + 1 for all A,B,C, in four easy steps:
++ // 1: X = A + B; X' = X % 2^64
++ " adds %0, %0, %2\n"
++ // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
++ " csel %1, xzr, %1, hi\n"
++ // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
++ // to compensate for the carry flag being set in step 4. For
++ // X > 2^64, X' merely has to remain nonzero, which it does.
++ " csinv %0, %0, xzr, cc\n"
++ // 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1
++ // comes from the carry in being clear. Otherwise, we are
++ // testing X' - C == 0, subject to the previous adjustments.
++ " sbcs xzr, %0, %1\n"
++ " cset %0, ls\n"
++ : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc");
++
++ return addr;
++}
+
+ /*
+ * When dealing with data aborts, watchpoints, or instruction traps we may end
+@@ -90,7 +104,7 @@ static inline void set_fs(mm_segment_t fs)
+ */
+ #define untagged_addr(addr) sign_extend64(addr, 55)
+
+-#define access_ok(type, addr, size) __range_ok(addr, size)
++#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size)
+ #define user_addr_max get_fs
+
+ #define _ASM_EXTABLE(from, to) \
+@@ -105,17 +119,23 @@ static inline void set_fs(mm_segment_t fs)
+ #ifdef CONFIG_ARM64_SW_TTBR0_PAN
+ static inline void __uaccess_ttbr0_disable(void)
+ {
+- unsigned long ttbr;
++ unsigned long flags, ttbr;
+
++ local_irq_save(flags);
++ ttbr = read_sysreg(ttbr1_el1);
++ ttbr &= ~TTBR_ASID_MASK;
+ /* reserved_ttbr0 placed at the end of swapper_pg_dir */
+- ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE;
+- write_sysreg(ttbr, ttbr0_el1);
++ write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1);
+ isb();
++ /* Set reserved ASID */
++ write_sysreg(ttbr, ttbr1_el1);
++ isb();
++ local_irq_restore(flags);
+ }
+
+ static inline void __uaccess_ttbr0_enable(void)
+ {
+- unsigned long flags;
++ unsigned long flags, ttbr0, ttbr1;
+
+ /*
+ * Disable interrupts to avoid preemption between reading the 'ttbr0'
+@@ -123,7 +143,17 @@ static inline void __uaccess_ttbr0_enable(void)
+ * roll-over and an update of 'ttbr0'.
+ */
+ local_irq_save(flags);
+- write_sysreg(current_thread_info()->ttbr0, ttbr0_el1);
++ ttbr0 = READ_ONCE(current_thread_info()->ttbr0);
++
++ /* Restore active ASID */
++ ttbr1 = read_sysreg(ttbr1_el1);
++ ttbr1 &= ~TTBR_ASID_MASK; /* safety measure */
++ ttbr1 |= ttbr0 & TTBR_ASID_MASK;
++ write_sysreg(ttbr1, ttbr1_el1);
++ isb();
++
++ /* Restore user page table */
++ write_sysreg(ttbr0, ttbr0_el1);
+ isb();
+ local_irq_restore(flags);
+ }
+@@ -192,6 +222,26 @@ static inline void uaccess_enable_not_uao(void)
+ __uaccess_enable(ARM64_ALT_PAN_NOT_UAO);
+ }
+
++/*
++ * Sanitise a uaccess pointer such that it becomes NULL if above the
++ * current addr_limit.
++ */
++#define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
++static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
++{
++ void __user *safe_ptr;
++
++ asm volatile(
++ " bics xzr, %1, %2\n"
++ " csel %0, %1, xzr, eq\n"
++ : "=&r" (safe_ptr)
++ : "r" (ptr), "r" (current_thread_info()->addr_limit)
++ : "cc");
++
++ csdb();
++ return safe_ptr;
++}
++
+ /*
+ * The "__xxx" versions of the user access functions do not verify the address
+ * space - it must have been done previously with a separate "access_ok()"
+@@ -244,28 +294,33 @@ do { \
+ (x) = (__force __typeof__(*(ptr)))__gu_val; \
+ } while (0)
+
+-#define __get_user(x, ptr) \
++#define __get_user_check(x, ptr, err) \
+ ({ \
+- int __gu_err = 0; \
+- __get_user_err((x), (ptr), __gu_err); \
+- __gu_err; \
++ __typeof__(*(ptr)) __user *__p = (ptr); \
++ might_fault(); \
++ if (access_ok(VERIFY_READ, __p, sizeof(*__p))) { \
++ __p = uaccess_mask_ptr(__p); \
++ __get_user_err((x), __p, (err)); \
++ } else { \
++ (x) = 0; (err) = -EFAULT; \
++ } \
+ })
+
+ #define __get_user_error(x, ptr, err) \
+ ({ \
+- __get_user_err((x), (ptr), (err)); \
++ __get_user_check((x), (ptr), (err)); \
+ (void)0; \
+ })
+
+-#define get_user(x, ptr) \
++#define __get_user(x, ptr) \
+ ({ \
+- __typeof__(*(ptr)) __user *__p = (ptr); \
+- might_fault(); \
+- access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \
+- __get_user((x), __p) : \
+- ((x) = 0, -EFAULT); \
++ int __gu_err = 0; \
++ __get_user_check((x), (ptr), __gu_err); \
++ __gu_err; \
+ })
+
++#define get_user __get_user
++
+ #define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \
+ asm volatile( \
+ "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \
+@@ -308,43 +363,63 @@ do { \
+ uaccess_disable_not_uao(); \
+ } while (0)
+
+-#define __put_user(x, ptr) \
++#define __put_user_check(x, ptr, err) \
+ ({ \
+- int __pu_err = 0; \
+- __put_user_err((x), (ptr), __pu_err); \
+- __pu_err; \
++ __typeof__(*(ptr)) __user *__p = (ptr); \
++ might_fault(); \
++ if (access_ok(VERIFY_WRITE, __p, sizeof(*__p))) { \
++ __p = uaccess_mask_ptr(__p); \
++ __put_user_err((x), __p, (err)); \
++ } else { \
++ (err) = -EFAULT; \
++ } \
+ })
+
+ #define __put_user_error(x, ptr, err) \
+ ({ \
+- __put_user_err((x), (ptr), (err)); \
++ __put_user_check((x), (ptr), (err)); \
+ (void)0; \
+ })
+
+-#define put_user(x, ptr) \
++#define __put_user(x, ptr) \
+ ({ \
+- __typeof__(*(ptr)) __user *__p = (ptr); \
+- might_fault(); \
+- access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \
+- __put_user((x), __p) : \
+- -EFAULT; \
++ int __pu_err = 0; \
++ __put_user_check((x), (ptr), __pu_err); \
++ __pu_err; \
+ })
+
++#define put_user __put_user
++
+ extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
+-#define raw_copy_from_user __arch_copy_from_user
++#define raw_copy_from_user(to, from, n) \
++({ \
++ __arch_copy_from_user((to), __uaccess_mask_ptr(from), (n)); \
++})
++
+ extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
+-#define raw_copy_to_user __arch_copy_to_user
+-extern unsigned long __must_check raw_copy_in_user(void __user *to, const void __user *from, unsigned long n);
+-extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
++#define raw_copy_to_user(to, from, n) \
++({ \
++ __arch_copy_to_user(__uaccess_mask_ptr(to), (from), (n)); \
++})
++
++extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n);
++#define raw_copy_in_user(to, from, n) \
++({ \
++ __arch_copy_in_user(__uaccess_mask_ptr(to), \
++ __uaccess_mask_ptr(from), (n)); \
++})
++
+ #define INLINE_COPY_TO_USER
+ #define INLINE_COPY_FROM_USER
+
+-static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
++extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n);
++static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n)
+ {
+ if (access_ok(VERIFY_WRITE, to, n))
+- n = __clear_user(to, n);
++ n = __arch_clear_user(__uaccess_mask_ptr(to), n);
+ return n;
+ }
++#define clear_user __clear_user
+
+ extern long strncpy_from_user(char *dest, const char __user *src, long count);
+
+@@ -358,7 +433,7 @@ extern unsigned long __must_check __copy_user_flushcache(void *to, const void __
+ static inline int __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
+ {
+ kasan_check_write(dst, size);
+- return __copy_user_flushcache(dst, src, size);
++ return __copy_user_flushcache(dst, __uaccess_mask_ptr(src), size);
+ }
+ #endif
+
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index 2f5ff2a65db3..def8d5623fd1 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -55,6 +55,10 @@ arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
+ arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
+ arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+
++ifeq ($(CONFIG_KVM),y)
++arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o
++endif
++
+ obj-y += $(arm64-obj-y) vdso/ probes/
+ obj-m += $(arm64-obj-m)
+ head-y := head.o
+diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
+index 67368c7329c0..66be504edb6c 100644
+--- a/arch/arm64/kernel/arm64ksyms.c
++++ b/arch/arm64/kernel/arm64ksyms.c
+@@ -37,8 +37,8 @@ EXPORT_SYMBOL(clear_page);
+ /* user mem (segment) */
+ EXPORT_SYMBOL(__arch_copy_from_user);
+ EXPORT_SYMBOL(__arch_copy_to_user);
+-EXPORT_SYMBOL(__clear_user);
+-EXPORT_SYMBOL(raw_copy_in_user);
++EXPORT_SYMBOL(__arch_clear_user);
++EXPORT_SYMBOL(__arch_copy_in_user);
+
+ /* physical memory */
+ EXPORT_SYMBOL(memstart_addr);
+diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
+index 71bf088f1e4b..af247d10252f 100644
+--- a/arch/arm64/kernel/asm-offsets.c
++++ b/arch/arm64/kernel/asm-offsets.c
+@@ -24,6 +24,7 @@
+ #include <linux/kvm_host.h>
+ #include <linux/suspend.h>
+ #include <asm/cpufeature.h>
++#include <asm/fixmap.h>
+ #include <asm/thread_info.h>
+ #include <asm/memory.h>
+ #include <asm/smp_plat.h>
+@@ -148,11 +149,14 @@ int main(void)
+ DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
+ DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
+ DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
+-
+ BLANK();
+ DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address));
+ DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address));
+ DEFINE(HIBERN_PBE_NEXT, offsetof(struct pbe, next));
+ DEFINE(ARM64_FTR_SYSVAL, offsetof(struct arm64_ftr_reg, sys_val));
++ BLANK();
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ DEFINE(TRAMP_VALIAS, TRAMP_VALIAS);
++#endif
+ return 0;
+ }
+diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
+new file mode 100644
+index 000000000000..e5de33513b5d
+--- /dev/null
++++ b/arch/arm64/kernel/bpi.S
+@@ -0,0 +1,83 @@
++/*
++ * Contains CPU specific branch predictor invalidation sequences
++ *
++ * Copyright (C) 2018 ARM Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/linkage.h>
++#include <linux/arm-smccc.h>
++
++.macro ventry target
++ .rept 31
++ nop
++ .endr
++ b \target
++.endm
++
++.macro vectors target
++ ventry \target + 0x000
++ ventry \target + 0x080
++ ventry \target + 0x100
++ ventry \target + 0x180
++
++ ventry \target + 0x200
++ ventry \target + 0x280
++ ventry \target + 0x300
++ ventry \target + 0x380
++
++ ventry \target + 0x400
++ ventry \target + 0x480
++ ventry \target + 0x500
++ ventry \target + 0x580
++
++ ventry \target + 0x600
++ ventry \target + 0x680
++ ventry \target + 0x700
++ ventry \target + 0x780
++.endm
++
++ .align 11
++ENTRY(__bp_harden_hyp_vecs_start)
++ .rept 4
++ vectors __kvm_hyp_vector
++ .endr
++ENTRY(__bp_harden_hyp_vecs_end)
++
++ENTRY(__qcom_hyp_sanitize_link_stack_start)
++ stp x29, x30, [sp, #-16]!
++ .rept 16
++ bl . + 4
++ .endr
++ ldp x29, x30, [sp], #16
++ENTRY(__qcom_hyp_sanitize_link_stack_end)
++
++.macro smccc_workaround_1 inst
++ sub sp, sp, #(8 * 4)
++ stp x2, x3, [sp, #(8 * 0)]
++ stp x0, x1, [sp, #(8 * 2)]
++ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_1
++ \inst #0
++ ldp x2, x3, [sp, #(8 * 0)]
++ ldp x0, x1, [sp, #(8 * 2)]
++ add sp, sp, #(8 * 4)
++.endm
++
++ENTRY(__smccc_workaround_1_smc_start)
++ smccc_workaround_1 smc
++ENTRY(__smccc_workaround_1_smc_end)
++
++ENTRY(__smccc_workaround_1_hvc_start)
++ smccc_workaround_1 hvc
++ENTRY(__smccc_workaround_1_hvc_end)
+diff --git a/arch/arm64/kernel/cpu-reset.S b/arch/arm64/kernel/cpu-reset.S
+index 65f42d257414..8021b46c9743 100644
+--- a/arch/arm64/kernel/cpu-reset.S
++++ b/arch/arm64/kernel/cpu-reset.S
+@@ -16,7 +16,7 @@
+ #include <asm/virt.h>
+
+ .text
+-.pushsection .idmap.text, "ax"
++.pushsection .idmap.text, "awx"
+
+ /*
+ * __cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2) - Helper for
+@@ -37,6 +37,7 @@ ENTRY(__cpu_soft_restart)
+ mrs x12, sctlr_el1
+ ldr x13, =SCTLR_ELx_FLAGS
+ bic x12, x12, x13
++ pre_disable_mmu_workaround
+ msr sctlr_el1, x12
+ isb
+
+diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
+index 0e27f86ee709..07823595b7f0 100644
+--- a/arch/arm64/kernel/cpu_errata.c
++++ b/arch/arm64/kernel/cpu_errata.c
+@@ -30,6 +30,20 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
+ entry->midr_range_max);
+ }
+
++static bool __maybe_unused
++is_kryo_midr(const struct arm64_cpu_capabilities *entry, int scope)
++{
++ u32 model;
++
++ WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
++
++ model = read_cpuid_id();
++ model &= MIDR_IMPLEMENTOR_MASK | (0xf00 << MIDR_PARTNUM_SHIFT) |
++ MIDR_ARCHITECTURE_MASK;
++
++ return model == entry->midr_model;
++}
++
+ static bool
+ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
+ int scope)
+@@ -46,6 +60,174 @@ static int cpu_enable_trap_ctr_access(void *__unused)
+ return 0;
+ }
+
++#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
++#include <asm/mmu_context.h>
++#include <asm/cacheflush.h>
++
++DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
++
++#ifdef CONFIG_KVM
++extern char __qcom_hyp_sanitize_link_stack_start[];
++extern char __qcom_hyp_sanitize_link_stack_end[];
++extern char __smccc_workaround_1_smc_start[];
++extern char __smccc_workaround_1_smc_end[];
++extern char __smccc_workaround_1_hvc_start[];
++extern char __smccc_workaround_1_hvc_end[];
++
++static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
++ const char *hyp_vecs_end)
++{
++ void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
++ int i;
++
++ for (i = 0; i < SZ_2K; i += 0x80)
++ memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
++
++ flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
++}
++
++static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
++ const char *hyp_vecs_start,
++ const char *hyp_vecs_end)
++{
++ static int last_slot = -1;
++ static DEFINE_SPINLOCK(bp_lock);
++ int cpu, slot = -1;
++
++ spin_lock(&bp_lock);
++ for_each_possible_cpu(cpu) {
++ if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
++ slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
++ break;
++ }
++ }
++
++ if (slot == -1) {
++ last_slot++;
++ BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start)
++ / SZ_2K) <= last_slot);
++ slot = last_slot;
++ __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
++ }
++
++ __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
++ __this_cpu_write(bp_hardening_data.fn, fn);
++ spin_unlock(&bp_lock);
++}
++#else
++#define __qcom_hyp_sanitize_link_stack_start NULL
++#define __qcom_hyp_sanitize_link_stack_end NULL
++#define __smccc_workaround_1_smc_start NULL
++#define __smccc_workaround_1_smc_end NULL
++#define __smccc_workaround_1_hvc_start NULL
++#define __smccc_workaround_1_hvc_end NULL
++
++static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
++ const char *hyp_vecs_start,
++ const char *hyp_vecs_end)
++{
++ __this_cpu_write(bp_hardening_data.fn, fn);
++}
++#endif /* CONFIG_KVM */
++
++static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
++ bp_hardening_cb_t fn,
++ const char *hyp_vecs_start,
++ const char *hyp_vecs_end)
++{
++ u64 pfr0;
++
++ if (!entry->matches(entry, SCOPE_LOCAL_CPU))
++ return;
++
++ pfr0 = read_cpuid(ID_AA64PFR0_EL1);
++ if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT))
++ return;
++
++ __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
++}
++
++#include <uapi/linux/psci.h>
++#include <linux/arm-smccc.h>
++#include <linux/psci.h>
++
++static void call_smc_arch_workaround_1(void)
++{
++ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
++}
++
++static void call_hvc_arch_workaround_1(void)
++{
++ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
++}
++
++static int enable_smccc_arch_workaround_1(void *data)
++{
++ const struct arm64_cpu_capabilities *entry = data;
++ bp_hardening_cb_t cb;
++ void *smccc_start, *smccc_end;
++ struct arm_smccc_res res;
++
++ if (!entry->matches(entry, SCOPE_LOCAL_CPU))
++ return 0;
++
++ if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
++ return 0;
++
++ switch (psci_ops.conduit) {
++ case PSCI_CONDUIT_HVC:
++ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
++ ARM_SMCCC_ARCH_WORKAROUND_1, &res);
++ if (res.a0)
++ return 0;
++ cb = call_hvc_arch_workaround_1;
++ smccc_start = __smccc_workaround_1_hvc_start;
++ smccc_end = __smccc_workaround_1_hvc_end;
++ break;
++
++ case PSCI_CONDUIT_SMC:
++ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
++ ARM_SMCCC_ARCH_WORKAROUND_1, &res);
++ if (res.a0)
++ return 0;
++ cb = call_smc_arch_workaround_1;
++ smccc_start = __smccc_workaround_1_smc_start;
++ smccc_end = __smccc_workaround_1_smc_end;
++ break;
++
++ default:
++ return 0;
++ }
++
++ install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
++
++ return 0;
++}
++
++static void qcom_link_stack_sanitization(void)
++{
++ u64 tmp;
++
++ asm volatile("mov %0, x30 \n"
++ ".rept 16 \n"
++ "bl . + 4 \n"
++ ".endr \n"
++ "mov x30, %0 \n"
++ : "=&r" (tmp));
++}
++
++static int qcom_enable_link_stack_sanitization(void *data)
++{
++ const struct arm64_cpu_capabilities *entry = data;
++
++ install_bp_hardening_cb(entry, qcom_link_stack_sanitization,
++ __qcom_hyp_sanitize_link_stack_start,
++ __qcom_hyp_sanitize_link_stack_end);
++
++ return 0;
++}
++#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
++
+ #define MIDR_RANGE(model, min, max) \
+ .def_scope = SCOPE_LOCAL_CPU, \
+ .matches = is_affected_midr_range, \
+@@ -169,6 +351,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
+ MIDR_CPU_VAR_REV(0, 0),
+ MIDR_CPU_VAR_REV(0, 0)),
+ },
++ {
++ .desc = "Qualcomm Technologies Kryo erratum 1003",
++ .capability = ARM64_WORKAROUND_QCOM_FALKOR_E1003,
++ .def_scope = SCOPE_LOCAL_CPU,
++ .midr_model = MIDR_QCOM_KRYO,
++ .matches = is_kryo_midr,
++ },
+ #endif
+ #ifdef CONFIG_QCOM_FALKOR_ERRATUM_1009
+ {
+@@ -186,6 +375,47 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
+ .capability = ARM64_WORKAROUND_858921,
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+ },
++#endif
++#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
++ .enable = enable_smccc_arch_workaround_1,
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
++ .enable = enable_smccc_arch_workaround_1,
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
++ .enable = enable_smccc_arch_workaround_1,
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
++ .enable = enable_smccc_arch_workaround_1,
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
++ .enable = qcom_enable_link_stack_sanitization,
++ },
++ {
++ .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
++ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
++ .enable = enable_smccc_arch_workaround_1,
++ },
++ {
++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
++ MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
++ .enable = enable_smccc_arch_workaround_1,
++ },
+ #endif
+ {
+ }
+@@ -200,15 +430,18 @@ void verify_local_cpu_errata_workarounds(void)
+ {
+ const struct arm64_cpu_capabilities *caps = arm64_errata;
+
+- for (; caps->matches; caps++)
+- if (!cpus_have_cap(caps->capability) &&
+- caps->matches(caps, SCOPE_LOCAL_CPU)) {
++ for (; caps->matches; caps++) {
++ if (cpus_have_cap(caps->capability)) {
++ if (caps->enable)
++ caps->enable((void *)caps);
++ } else if (caps->matches(caps, SCOPE_LOCAL_CPU)) {
+ pr_crit("CPU%d: Requires work around for %s, not detected"
+ " at boot time\n",
+ smp_processor_id(),
+ caps->desc ? : "an erratum");
+ cpu_die_early();
+ }
++ }
+ }
+
+ void update_cpu_errata_workarounds(void)
+diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
+index 21e2c95d24e7..582142ae92e1 100644
+--- a/arch/arm64/kernel/cpufeature.c
++++ b/arch/arm64/kernel/cpufeature.c
+@@ -125,6 +125,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
+ };
+
+ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
+ S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
+ S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
+@@ -796,6 +798,86 @@ static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unus
+ ID_AA64PFR0_FP_SHIFT) < 0;
+ }
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
++
++static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
++ int __unused)
++{
++ char const *str = "command line option";
++ u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
++
++ /*
++ * For reasons that aren't entirely clear, enabling KPTI on Cavium
++ * ThunderX leads to apparent I-cache corruption of kernel text, which
++ * ends as well as you might imagine. Don't even try.
++ */
++ if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456)) {
++ str = "ARM64_WORKAROUND_CAVIUM_27456";
++ __kpti_forced = -1;
++ }
++
++ /* Forced? */
++ if (__kpti_forced) {
++ pr_info_once("kernel page table isolation forced %s by %s\n",
++ __kpti_forced > 0 ? "ON" : "OFF", str);
++ return __kpti_forced > 0;
++ }
++
++ /* Useful for KASLR robustness */
++ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
++ return true;
++
++ /* Don't force KPTI for CPUs that are not vulnerable */
++ switch (read_cpuid_id() & MIDR_CPU_MODEL_MASK) {
++ case MIDR_CAVIUM_THUNDERX2:
++ case MIDR_BRCM_VULCAN:
++ return false;
++ }
++
++ /* Defer to CPU feature registers */
++ return !cpuid_feature_extract_unsigned_field(pfr0,
++ ID_AA64PFR0_CSV3_SHIFT);
++}
++
++static int kpti_install_ng_mappings(void *__unused)
++{
++ typedef void (kpti_remap_fn)(int, int, phys_addr_t);
++ extern kpti_remap_fn idmap_kpti_install_ng_mappings;
++ kpti_remap_fn *remap_fn;
++
++ static bool kpti_applied = false;
++ int cpu = smp_processor_id();
++
++ if (kpti_applied)
++ return 0;
++
++ remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
++
++ cpu_install_idmap();
++ remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
++ cpu_uninstall_idmap();
++
++ if (!cpu)
++ kpti_applied = true;
++
++ return 0;
++}
++
++static int __init parse_kpti(char *str)
++{
++ bool enabled;
++ int ret = strtobool(str, &enabled);
++
++ if (ret)
++ return ret;
++
++ __kpti_forced = enabled ? 1 : -1;
++ return 0;
++}
++__setup("kpti=", parse_kpti);
++#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
++
+ static const struct arm64_cpu_capabilities arm64_features[] = {
+ {
+ .desc = "GIC system register CPU interface",
+@@ -882,6 +964,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
+ .def_scope = SCOPE_SYSTEM,
+ .matches = hyp_offset_low,
+ },
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ {
++ .desc = "Kernel page table isolation (KPTI)",
++ .capability = ARM64_UNMAP_KERNEL_AT_EL0,
++ .def_scope = SCOPE_SYSTEM,
++ .matches = unmap_kernel_at_el0,
++ .enable = kpti_install_ng_mappings,
++ },
++#endif
+ {
+ /* FP/SIMD is not implemented */
+ .capability = ARM64_HAS_NO_FPSIMD,
+@@ -1000,6 +1091,25 @@ static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
+ cap_set_elf_hwcap(hwcaps);
+ }
+
++/*
++ * Check if the current CPU has a given feature capability.
++ * Should be called from non-preemptible context.
++ */
++static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
++ unsigned int cap)
++{
++ const struct arm64_cpu_capabilities *caps;
++
++ if (WARN_ON(preemptible()))
++ return false;
++
++ for (caps = cap_array; caps->matches; caps++)
++ if (caps->capability == cap &&
++ caps->matches(caps, SCOPE_LOCAL_CPU))
++ return true;
++ return false;
++}
++
+ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
+ const char *info)
+ {
+@@ -1035,7 +1145,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
+ * uses an IPI, giving us a PSTATE that disappears when
+ * we return.
+ */
+- stop_machine(caps->enable, NULL, cpu_online_mask);
++ stop_machine(caps->enable, (void *)caps, cpu_online_mask);
+ }
+ }
+ }
+@@ -1078,8 +1188,9 @@ verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
+ }
+
+ static void
+-verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
++verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list)
+ {
++ const struct arm64_cpu_capabilities *caps = caps_list;
+ for (; caps->matches; caps++) {
+ if (!cpus_have_cap(caps->capability))
+ continue;
+@@ -1087,13 +1198,13 @@ verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
+ * If the new CPU misses an advertised feature, we cannot proceed
+ * further, park the cpu.
+ */
+- if (!caps->matches(caps, SCOPE_LOCAL_CPU)) {
++ if (!__this_cpu_has_cap(caps_list, caps->capability)) {
+ pr_crit("CPU%d: missing feature: %s\n",
+ smp_processor_id(), caps->desc);
+ cpu_die_early();
+ }
+ if (caps->enable)
+- caps->enable(NULL);
++ caps->enable((void *)caps);
+ }
+ }
+
+@@ -1148,25 +1259,6 @@ static void __init mark_const_caps_ready(void)
+ static_branch_enable(&arm64_const_caps_ready);
+ }
+
+-/*
+- * Check if the current CPU has a given feature capability.
+- * Should be called from non-preemptible context.
+- */
+-static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
+- unsigned int cap)
+-{
+- const struct arm64_cpu_capabilities *caps;
+-
+- if (WARN_ON(preemptible()))
+- return false;
+-
+- for (caps = cap_array; caps->desc; caps++)
+- if (caps->capability == cap && caps->matches)
+- return caps->matches(caps, SCOPE_LOCAL_CPU);
+-
+- return false;
+-}
+-
+ extern const struct arm64_cpu_capabilities arm64_errata[];
+
+ bool this_cpu_has_cap(unsigned int cap)
+diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
+index 4e6ad355bd05..6b9736c3fb56 100644
+--- a/arch/arm64/kernel/efi-entry.S
++++ b/arch/arm64/kernel/efi-entry.S
+@@ -96,6 +96,7 @@ ENTRY(entry)
+ mrs x0, sctlr_el2
+ bic x0, x0, #1 << 0 // clear SCTLR.M
+ bic x0, x0, #1 << 2 // clear SCTLR.C
++ pre_disable_mmu_workaround
+ msr sctlr_el2, x0
+ isb
+ b 2f
+@@ -103,6 +104,7 @@ ENTRY(entry)
+ mrs x0, sctlr_el1
+ bic x0, x0, #1 << 0 // clear SCTLR.M
+ bic x0, x0, #1 << 2 // clear SCTLR.C
++ pre_disable_mmu_workaround
+ msr sctlr_el1, x0
+ isb
+ 2:
+diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
+index e1c59d4008a8..93958d1341bb 100644
+--- a/arch/arm64/kernel/entry.S
++++ b/arch/arm64/kernel/entry.S
+@@ -29,6 +29,8 @@
+ #include <asm/esr.h>
+ #include <asm/irq.h>
+ #include <asm/memory.h>
++#include <asm/mmu.h>
++#include <asm/processor.h>
+ #include <asm/ptrace.h>
+ #include <asm/thread_info.h>
+ #include <asm/asm-uaccess.h>
+@@ -69,8 +71,21 @@
+ #define BAD_FIQ 2
+ #define BAD_ERROR 3
+
+- .macro kernel_ventry label
++ .macro kernel_ventry, el, label, regsize = 64
+ .align 7
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++alternative_if ARM64_UNMAP_KERNEL_AT_EL0
++ .if \el == 0
++ .if \regsize == 64
++ mrs x30, tpidrro_el0
++ msr tpidrro_el0, xzr
++ .else
++ mov x30, xzr
++ .endif
++ .endif
++alternative_else_nop_endif
++#endif
++
+ sub sp, sp, #S_FRAME_SIZE
+ #ifdef CONFIG_VMAP_STACK
+ /*
+@@ -82,7 +97,7 @@
+ tbnz x0, #THREAD_SHIFT, 0f
+ sub x0, sp, x0 // x0'' = sp' - x0' = (sp + x0) - sp = x0
+ sub sp, sp, x0 // sp'' = sp' - x0 = (sp + x0) - x0 = sp
+- b \label
++ b el\()\el\()_\label
+
+ 0:
+ /*
+@@ -114,7 +129,12 @@
+ sub sp, sp, x0
+ mrs x0, tpidrro_el0
+ #endif
+- b \label
++ b el\()\el\()_\label
++ .endm
++
++ .macro tramp_alias, dst, sym
++ mov_q \dst, TRAMP_VALIAS
++ add \dst, \dst, #(\sym - .entry.tramp.text)
+ .endm
+
+ .macro kernel_entry, el, regsize = 64
+@@ -147,10 +167,10 @@
+ .else
+ add x21, sp, #S_FRAME_SIZE
+ get_thread_info tsk
+- /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
++ /* Save the task's original addr_limit and set USER_DS */
+ ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
+ str x20, [sp, #S_ORIG_ADDR_LIMIT]
+- mov x20, #TASK_SIZE_64
++ mov x20, #USER_DS
+ str x20, [tsk, #TSK_TI_ADDR_LIMIT]
+ /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
+ .endif /* \el == 0 */
+@@ -185,7 +205,7 @@ alternative_else_nop_endif
+
+ .if \el != 0
+ mrs x21, ttbr0_el1
+- tst x21, #0xffff << 48 // Check for the reserved ASID
++ tst x21, #TTBR_ASID_MASK // Check for the reserved ASID
+ orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR
+ b.eq 1f // TTBR0 access already disabled
+ and x23, x23, #~PSR_PAN_BIT // Clear the emulated PAN in the saved SPSR
+@@ -246,7 +266,7 @@ alternative_else_nop_endif
+ tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set
+ .endif
+
+- __uaccess_ttbr0_enable x0
++ __uaccess_ttbr0_enable x0, x1
+
+ .if \el == 0
+ /*
+@@ -255,7 +275,7 @@ alternative_else_nop_endif
+ * Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
+ * corruption).
+ */
+- post_ttbr0_update_workaround
++ bl post_ttbr_update_workaround
+ .endif
+ 1:
+ .if \el != 0
+@@ -267,18 +287,20 @@ alternative_else_nop_endif
+ .if \el == 0
+ ldr x23, [sp, #S_SP] // load return stack pointer
+ msr sp_el0, x23
++ tst x22, #PSR_MODE32_BIT // native task?
++ b.eq 3f
++
+ #ifdef CONFIG_ARM64_ERRATUM_845719
+ alternative_if ARM64_WORKAROUND_845719
+- tbz x22, #4, 1f
+ #ifdef CONFIG_PID_IN_CONTEXTIDR
+ mrs x29, contextidr_el1
+ msr contextidr_el1, x29
+ #else
+ msr contextidr_el1, xzr
+ #endif
+-1:
+ alternative_else_nop_endif
+ #endif
++3:
+ .endif
+
+ msr elr_el1, x21 // set up the return data
+@@ -300,7 +322,21 @@ alternative_else_nop_endif
+ ldp x28, x29, [sp, #16 * 14]
+ ldr lr, [sp, #S_LR]
+ add sp, sp, #S_FRAME_SIZE // restore sp
+- eret // return to kernel
++
++ .if \el == 0
++alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ bne 4f
++ msr far_el1, x30
++ tramp_alias x30, tramp_exit_native
++ br x30
++4:
++ tramp_alias x30, tramp_exit_compat
++ br x30
++#endif
++ .else
++ eret
++ .endif
+ .endm
+
+ .macro irq_stack_entry
+@@ -340,6 +376,7 @@ alternative_else_nop_endif
+ * x7 is reserved for the system call number in 32-bit mode.
+ */
+ wsc_nr .req w25 // number of system calls
++xsc_nr .req x25 // number of system calls (zero-extended)
+ wscno .req w26 // syscall number
+ xscno .req x26 // syscall number (zero-extended)
+ stbl .req x27 // syscall table pointer
+@@ -365,31 +402,31 @@ tsk .req x28 // current thread_info
+
+ .align 11
+ ENTRY(vectors)
+- kernel_ventry el1_sync_invalid // Synchronous EL1t
+- kernel_ventry el1_irq_invalid // IRQ EL1t
+- kernel_ventry el1_fiq_invalid // FIQ EL1t
+- kernel_ventry el1_error_invalid // Error EL1t
++ kernel_ventry 1, sync_invalid // Synchronous EL1t
++ kernel_ventry 1, irq_invalid // IRQ EL1t
++ kernel_ventry 1, fiq_invalid // FIQ EL1t
++ kernel_ventry 1, error_invalid // Error EL1t
+
+- kernel_ventry el1_sync // Synchronous EL1h
+- kernel_ventry el1_irq // IRQ EL1h
+- kernel_ventry el1_fiq_invalid // FIQ EL1h
+- kernel_ventry el1_error_invalid // Error EL1h
++ kernel_ventry 1, sync // Synchronous EL1h
++ kernel_ventry 1, irq // IRQ EL1h
++ kernel_ventry 1, fiq_invalid // FIQ EL1h
++ kernel_ventry 1, error_invalid // Error EL1h
+
+- kernel_ventry el0_sync // Synchronous 64-bit EL0
+- kernel_ventry el0_irq // IRQ 64-bit EL0
+- kernel_ventry el0_fiq_invalid // FIQ 64-bit EL0
+- kernel_ventry el0_error_invalid // Error 64-bit EL0
++ kernel_ventry 0, sync // Synchronous 64-bit EL0
++ kernel_ventry 0, irq // IRQ 64-bit EL0
++ kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
++ kernel_ventry 0, error_invalid // Error 64-bit EL0
+
+ #ifdef CONFIG_COMPAT
+- kernel_ventry el0_sync_compat // Synchronous 32-bit EL0
+- kernel_ventry el0_irq_compat // IRQ 32-bit EL0
+- kernel_ventry el0_fiq_invalid_compat // FIQ 32-bit EL0
+- kernel_ventry el0_error_invalid_compat // Error 32-bit EL0
++ kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
++ kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0
++ kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0
++ kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0
+ #else
+- kernel_ventry el0_sync_invalid // Synchronous 32-bit EL0
+- kernel_ventry el0_irq_invalid // IRQ 32-bit EL0
+- kernel_ventry el0_fiq_invalid // FIQ 32-bit EL0
+- kernel_ventry el0_error_invalid // Error 32-bit EL0
++ kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
++ kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0
++ kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0
++ kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0
+ #endif
+ END(vectors)
+
+@@ -687,13 +724,15 @@ el0_ia:
+ * Instruction abort handling
+ */
+ mrs x26, far_el1
+- // enable interrupts before calling the main handler
+- enable_dbg_and_irq
++ enable_dbg
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bl trace_hardirqs_off
++#endif
+ ct_user_exit
+ mov x0, x26
+ mov x1, x25
+ mov x2, sp
+- bl do_mem_abort
++ bl do_el0_ia_bp_hardening
+ b ret_to_user
+ el0_fpsimd_acc:
+ /*
+@@ -720,8 +759,10 @@ el0_sp_pc:
+ * Stack or PC alignment exception handling
+ */
+ mrs x26, far_el1
+- // enable interrupts before calling the main handler
+- enable_dbg_and_irq
++ enable_dbg
++#ifdef CONFIG_TRACE_IRQFLAGS
++ bl trace_hardirqs_off
++#endif
+ ct_user_exit
+ mov x0, x26
+ mov x1, x25
+@@ -780,6 +821,11 @@ el0_irq_naked:
+ #endif
+
+ ct_user_exit
++#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
++ tbz x22, #55, 1f
++ bl do_el0_irq_bp_hardening
++1:
++#endif
+ irq_handler
+
+ #ifdef CONFIG_TRACE_IRQFLAGS
+@@ -848,6 +894,7 @@ el0_svc_naked: // compat entry point
+ b.ne __sys_trace
+ cmp wscno, wsc_nr // check upper syscall limit
+ b.hs ni_sys
++ mask_nospec64 xscno, xsc_nr, x19 // enforce bounds for syscall number
+ ldr x16, [stbl, xscno, lsl #3] // address in the syscall table
+ blr x16 // call sys_* routine
+ b ret_fast_syscall
+@@ -895,6 +942,117 @@ __ni_sys_trace:
+
+ .popsection // .entry.text
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++/*
++ * Exception vectors trampoline.
++ */
++ .pushsection ".entry.tramp.text", "ax"
++
++ .macro tramp_map_kernel, tmp
++ mrs \tmp, ttbr1_el1
++ sub \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
++ bic \tmp, \tmp, #USER_ASID_FLAG
++ msr ttbr1_el1, \tmp
++#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
++alternative_if ARM64_WORKAROUND_QCOM_FALKOR_E1003
++ /* ASID already in \tmp[63:48] */
++ movk \tmp, #:abs_g2_nc:(TRAMP_VALIAS >> 12)
++ movk \tmp, #:abs_g1_nc:(TRAMP_VALIAS >> 12)
++ /* 2MB boundary containing the vectors, so we nobble the walk cache */
++ movk \tmp, #:abs_g0_nc:((TRAMP_VALIAS & ~(SZ_2M - 1)) >> 12)
++ isb
++ tlbi vae1, \tmp
++ dsb nsh
++alternative_else_nop_endif
++#endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
++ .endm
++
++ .macro tramp_unmap_kernel, tmp
++ mrs \tmp, ttbr1_el1
++ add \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
++ orr \tmp, \tmp, #USER_ASID_FLAG
++ msr ttbr1_el1, \tmp
++ /*
++ * We avoid running the post_ttbr_update_workaround here because
++ * it's only needed by Cavium ThunderX, which requires KPTI to be
++ * disabled.
++ */
++ .endm
++
++ .macro tramp_ventry, regsize = 64
++ .align 7
++1:
++ .if \regsize == 64
++ msr tpidrro_el0, x30 // Restored in kernel_ventry
++ .endif
++ /*
++ * Defend against branch aliasing attacks by pushing a dummy
++ * entry onto the return stack and using a RET instruction to
++ * enter the full-fat kernel vectors.
++ */
++ bl 2f
++ b .
++2:
++ tramp_map_kernel x30
++#ifdef CONFIG_RANDOMIZE_BASE
++ adr x30, tramp_vectors + PAGE_SIZE
++alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
++ ldr x30, [x30]
++#else
++ ldr x30, =vectors
++#endif
++ prfm plil1strm, [x30, #(1b - tramp_vectors)]
++ msr vbar_el1, x30
++ add x30, x30, #(1b - tramp_vectors)
++ isb
++ ret
++ .endm
++
++ .macro tramp_exit, regsize = 64
++ adr x30, tramp_vectors
++ msr vbar_el1, x30
++ tramp_unmap_kernel x30
++ .if \regsize == 64
++ mrs x30, far_el1
++ .endif
++ eret
++ .endm
++
++ .align 11
++ENTRY(tramp_vectors)
++ .space 0x400
++
++ tramp_ventry
++ tramp_ventry
++ tramp_ventry
++ tramp_ventry
++
++ tramp_ventry 32
++ tramp_ventry 32
++ tramp_ventry 32
++ tramp_ventry 32
++END(tramp_vectors)
++
++ENTRY(tramp_exit_native)
++ tramp_exit
++END(tramp_exit_native)
++
++ENTRY(tramp_exit_compat)
++ tramp_exit 32
++END(tramp_exit_compat)
++
++ .ltorg
++ .popsection // .entry.tramp.text
++#ifdef CONFIG_RANDOMIZE_BASE
++ .pushsection ".rodata", "a"
++ .align PAGE_SHIFT
++ .globl __entry_tramp_data_start
++__entry_tramp_data_start:
++ .quad vectors
++ .popsection // .rodata
++#endif /* CONFIG_RANDOMIZE_BASE */
++#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
++
+ /*
+ * Special system call wrappers.
+ */
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 0b243ecaf7ac..261f3f88364c 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -371,7 +371,7 @@ ENDPROC(__primary_switched)
+ * end early head section, begin head code that is also used for
+ * hotplug and needs to have the same protections as the text region
+ */
+- .section ".idmap.text","ax"
++ .section ".idmap.text","awx"
+
+ ENTRY(kimage_vaddr)
+ .quad _text - TEXT_OFFSET
+@@ -732,6 +732,7 @@ __primary_switch:
+ * to take into account by discarding the current kernel mapping and
+ * creating a new one.
+ */
++ pre_disable_mmu_workaround
+ msr sctlr_el1, x20 // disable the MMU
+ isb
+ bl __create_page_tables // recreate kernel mapping
+diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
+index bcd22d7ee590..9e773732520c 100644
+--- a/arch/arm64/kernel/process.c
++++ b/arch/arm64/kernel/process.c
+@@ -314,16 +314,14 @@ void tls_preserve_current_state(void)
+
+ static void tls_thread_switch(struct task_struct *next)
+ {
+- unsigned long tpidr, tpidrro;
+-
+ tls_preserve_current_state();
+
+- tpidr = *task_user_tls(next);
+- tpidrro = is_compat_thread(task_thread_info(next)) ?
+- next->thread.tp_value : 0;
++ if (is_compat_thread(task_thread_info(next)))
++ write_sysreg(next->thread.tp_value, tpidrro_el0);
++ else if (!arm64_kernel_unmapped_at_el0())
++ write_sysreg(0, tpidrro_el0);
+
+- write_sysreg(tpidr, tpidr_el0);
+- write_sysreg(tpidrro, tpidrro_el0);
++ write_sysreg(*task_user_tls(next), tpidr_el0);
+ }
+
+ /* Restore the UAO state depending on next's addr_limit */
+diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
+index ce704a4aeadd..f407e422a720 100644
+--- a/arch/arm64/kernel/relocate_kernel.S
++++ b/arch/arm64/kernel/relocate_kernel.S
+@@ -45,6 +45,7 @@ ENTRY(arm64_relocate_new_kernel)
+ mrs x0, sctlr_el2
+ ldr x1, =SCTLR_ELx_FLAGS
+ bic x0, x0, x1
++ pre_disable_mmu_workaround
+ msr sctlr_el2, x0
+ isb
+ 1:
+diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
+index 10dd16d7902d..bebec8ef9372 100644
+--- a/arch/arm64/kernel/sleep.S
++++ b/arch/arm64/kernel/sleep.S
+@@ -96,7 +96,7 @@ ENTRY(__cpu_suspend_enter)
+ ret
+ ENDPROC(__cpu_suspend_enter)
+
+- .pushsection ".idmap.text", "ax"
++ .pushsection ".idmap.text", "awx"
+ ENTRY(cpu_resume)
+ bl el2_setup // if in EL2 drop to EL1 cleanly
+ bl __cpu_setup
+diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
+index 7da3e5c366a0..ddfd3c0942f7 100644
+--- a/arch/arm64/kernel/vmlinux.lds.S
++++ b/arch/arm64/kernel/vmlinux.lds.S
+@@ -57,6 +57,17 @@ jiffies = jiffies_64;
+ #define HIBERNATE_TEXT
+ #endif
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++#define TRAMP_TEXT \
++ . = ALIGN(PAGE_SIZE); \
++ VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \
++ *(.entry.tramp.text) \
++ . = ALIGN(PAGE_SIZE); \
++ VMLINUX_SYMBOL(__entry_tramp_text_end) = .;
++#else
++#define TRAMP_TEXT
++#endif
++
+ /*
+ * The size of the PE/COFF section that covers the kernel image, which
+ * runs from stext to _edata, must be a round multiple of the PE/COFF
+@@ -113,6 +124,7 @@ SECTIONS
+ HYPERVISOR_TEXT
+ IDMAP_TEXT
+ HIBERNATE_TEXT
++ TRAMP_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+ . = ALIGN(16);
+@@ -214,6 +226,11 @@ SECTIONS
+ . += RESERVED_TTBR0_SIZE;
+ #endif
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ tramp_pg_dir = .;
++ . += PAGE_SIZE;
++#endif
++
+ __pecoff_data_size = ABSOLUTE(. - __initdata_begin);
+ _end = .;
+
+@@ -234,7 +251,10 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
+ ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1))
+ <= SZ_4K, "Hibernate exit text too big or misaligned")
+ #endif
+-
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE,
++ "Entry trampoline text too big")
++#endif
+ /*
+ * If padding is applied before .head.text, virt<->phys conversions will fail.
+ */
+diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
+index 380261e258ef..ab48c5ed3943 100644
+--- a/arch/arm64/kvm/handle_exit.c
++++ b/arch/arm64/kvm/handle_exit.c
+@@ -22,12 +22,13 @@
+ #include <linux/kvm.h>
+ #include <linux/kvm_host.h>
+
++#include <kvm/arm_psci.h>
++
+ #include <asm/esr.h>
+ #include <asm/kvm_asm.h>
+ #include <asm/kvm_coproc.h>
+ #include <asm/kvm_emulate.h>
+ #include <asm/kvm_mmu.h>
+-#include <asm/kvm_psci.h>
+
+ #define CREATE_TRACE_POINTS
+ #include "trace.h"
+@@ -42,7 +43,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+ kvm_vcpu_hvc_get_imm(vcpu));
+ vcpu->stat.hvc_exit_stat++;
+
+- ret = kvm_psci_call(vcpu);
++ ret = kvm_hvc_call_handler(vcpu);
+ if (ret < 0) {
+ vcpu_set_reg(vcpu, 0, ~0UL);
+ return 1;
+@@ -53,7 +54,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+
+ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+ {
++ /*
++ * "If an SMC instruction executed at Non-secure EL1 is
++ * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
++ * Trap exception, not a Secure Monitor Call exception [...]"
++ *
++ * We need to advance the PC after the trap, as it would
++ * otherwise return to the same address...
++ */
+ vcpu_set_reg(vcpu, 0, ~0UL);
++ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+ return 1;
+ }
+
+diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
+index 3f9615582377..870828c364c5 100644
+--- a/arch/arm64/kvm/hyp-init.S
++++ b/arch/arm64/kvm/hyp-init.S
+@@ -151,6 +151,7 @@ reset:
+ mrs x5, sctlr_el2
+ ldr x6, =SCTLR_ELx_FLAGS
+ bic x5, x5, x6 // Clear SCTL_M and etc
++ pre_disable_mmu_workaround
+ msr sctlr_el2, x5
+ isb
+
+diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
+index 12ee62d6d410..9c45c6af1f58 100644
+--- a/arch/arm64/kvm/hyp/entry.S
++++ b/arch/arm64/kvm/hyp/entry.S
+@@ -196,3 +196,15 @@ alternative_endif
+
+ eret
+ ENDPROC(__fpsimd_guest_restore)
++
++ENTRY(__qcom_hyp_sanitize_btac_predictors)
++ /**
++ * Call SMC64 with Silicon provider serviceID 23<<8 (0xc2001700)
++ * 0xC2000000-0xC200FFFF: assigned to SiP Service Calls
++ * b15-b0: contains SiP functionID
++ */
++ movz x0, #0x1700
++ movk x0, #0xc200, lsl #16
++ smc #0
++ ret
++ENDPROC(__qcom_hyp_sanitize_btac_predictors)
+diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
+index 5170ce1021da..f49b53331d28 100644
+--- a/arch/arm64/kvm/hyp/hyp-entry.S
++++ b/arch/arm64/kvm/hyp/hyp-entry.S
+@@ -15,6 +15,7 @@
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <linux/arm-smccc.h>
+ #include <linux/linkage.h>
+
+ #include <asm/alternative.h>
+@@ -64,10 +65,11 @@ alternative_endif
+ lsr x0, x1, #ESR_ELx_EC_SHIFT
+
+ cmp x0, #ESR_ELx_EC_HVC64
++ ccmp x0, #ESR_ELx_EC_HVC32, #4, ne
+ b.ne el1_trap
+
+- mrs x1, vttbr_el2 // If vttbr is valid, the 64bit guest
+- cbnz x1, el1_trap // called HVC
++ mrs x1, vttbr_el2 // If vttbr is valid, the guest
++ cbnz x1, el1_hvc_guest // called HVC
+
+ /* Here, we're pretty sure the host called HVC. */
+ ldp x0, x1, [sp], #16
+@@ -100,6 +102,20 @@ alternative_endif
+
+ eret
+
++el1_hvc_guest:
++ /*
++ * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
++ * The workaround has already been applied on the host,
++ * so let's quickly get back to the guest. We don't bother
++ * restoring x1, as it can be clobbered anyway.
++ */
++ ldr x1, [sp] // Guest's x0
++ eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
++ cbnz w1, el1_trap
++ mov x0, x1
++ add sp, sp, #16
++ eret
++
+ el1_trap:
+ /*
+ * x0: ESR_EC
+diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
+index 945e79c641c4..79364d3455c0 100644
+--- a/arch/arm64/kvm/hyp/switch.c
++++ b/arch/arm64/kvm/hyp/switch.c
+@@ -17,6 +17,9 @@
+
+ #include <linux/types.h>
+ #include <linux/jump_label.h>
++#include <uapi/linux/psci.h>
++
++#include <kvm/arm_psci.h>
+
+ #include <asm/kvm_asm.h>
+ #include <asm/kvm_emulate.h>
+@@ -51,7 +54,7 @@ static void __hyp_text __activate_traps_vhe(void)
+ val &= ~CPACR_EL1_FPEN;
+ write_sysreg(val, cpacr_el1);
+
+- write_sysreg(__kvm_hyp_vector, vbar_el1);
++ write_sysreg(kvm_get_hyp_vector(), vbar_el1);
+ }
+
+ static void __hyp_text __activate_traps_nvhe(void)
+@@ -364,6 +367,14 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+ /* 0 falls through to be handled out of EL2 */
+ }
+
++ if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
++ u32 midr = read_cpuid_id();
++
++ /* Apply BTAC predictors mitigation to all Falkor chips */
++ if ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)
++ __qcom_hyp_sanitize_btac_predictors();
++ }
++
+ fp_enabled = __fpsimd_enabled();
+
+ __sysreg_save_guest_state(guest_ctxt);
+diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
+index e88fb99c1561..21ba0b29621b 100644
+--- a/arch/arm64/lib/clear_user.S
++++ b/arch/arm64/lib/clear_user.S
+@@ -21,7 +21,7 @@
+
+ .text
+
+-/* Prototype: int __clear_user(void *addr, size_t sz)
++/* Prototype: int __arch_clear_user(void *addr, size_t sz)
+ * Purpose : clear some user memory
+ * Params : addr - user memory address to clear
+ * : sz - number of bytes to clear
+@@ -29,8 +29,8 @@
+ *
+ * Alignment fixed up by hardware.
+ */
+-ENTRY(__clear_user)
+- uaccess_enable_not_uao x2, x3
++ENTRY(__arch_clear_user)
++ uaccess_enable_not_uao x2, x3, x4
+ mov x2, x1 // save the size for fixup return
+ subs x1, x1, #8
+ b.mi 2f
+@@ -50,9 +50,9 @@ uao_user_alternative 9f, strh, sttrh, wzr, x0, 2
+ b.mi 5f
+ uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
+ 5: mov x0, #0
+- uaccess_disable_not_uao x2
++ uaccess_disable_not_uao x2, x3
+ ret
+-ENDPROC(__clear_user)
++ENDPROC(__arch_clear_user)
+
+ .section .fixup,"ax"
+ .align 2
+diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
+index 4b5d826895ff..20305d485046 100644
+--- a/arch/arm64/lib/copy_from_user.S
++++ b/arch/arm64/lib/copy_from_user.S
+@@ -64,10 +64,10 @@
+
+ end .req x5
+ ENTRY(__arch_copy_from_user)
+- uaccess_enable_not_uao x3, x4
++ uaccess_enable_not_uao x3, x4, x5
+ add end, x0, x2
+ #include "copy_template.S"
+- uaccess_disable_not_uao x3
++ uaccess_disable_not_uao x3, x4
+ mov x0, #0 // Nothing to copy
+ ret
+ ENDPROC(__arch_copy_from_user)
+diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
+index b24a830419ad..54b75deb1d16 100644
+--- a/arch/arm64/lib/copy_in_user.S
++++ b/arch/arm64/lib/copy_in_user.S
+@@ -64,14 +64,15 @@
+ .endm
+
+ end .req x5
+-ENTRY(raw_copy_in_user)
+- uaccess_enable_not_uao x3, x4
++
++ENTRY(__arch_copy_in_user)
++ uaccess_enable_not_uao x3, x4, x5
+ add end, x0, x2
+ #include "copy_template.S"
+- uaccess_disable_not_uao x3
++ uaccess_disable_not_uao x3, x4
+ mov x0, #0
+ ret
+-ENDPROC(raw_copy_in_user)
++ENDPROC(__arch_copy_in_user)
+
+ .section .fixup,"ax"
+ .align 2
+diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
+index 351f0766f7a6..fda6172d6b88 100644
+--- a/arch/arm64/lib/copy_to_user.S
++++ b/arch/arm64/lib/copy_to_user.S
+@@ -63,10 +63,10 @@
+
+ end .req x5
+ ENTRY(__arch_copy_to_user)
+- uaccess_enable_not_uao x3, x4
++ uaccess_enable_not_uao x3, x4, x5
+ add end, x0, x2
+ #include "copy_template.S"
+- uaccess_disable_not_uao x3
++ uaccess_disable_not_uao x3, x4
+ mov x0, #0
+ ret
+ ENDPROC(__arch_copy_to_user)
+diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
+index 7f1dbe962cf5..91464e7f77cc 100644
+--- a/arch/arm64/mm/cache.S
++++ b/arch/arm64/mm/cache.S
+@@ -49,7 +49,7 @@ ENTRY(flush_icache_range)
+ * - end - virtual end address of region
+ */
+ ENTRY(__flush_cache_user_range)
+- uaccess_ttbr0_enable x2, x3
++ uaccess_ttbr0_enable x2, x3, x4
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x4, x0, x3
+@@ -72,7 +72,7 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU
+ isb
+ mov x0, #0
+ 1:
+- uaccess_ttbr0_disable x1
++ uaccess_ttbr0_disable x1, x2
+ ret
+ 9:
+ mov x0, #-EFAULT
+diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
+index ab9f5f0fb2c7..9284788733d6 100644
+--- a/arch/arm64/mm/context.c
++++ b/arch/arm64/mm/context.c
+@@ -39,7 +39,16 @@ static cpumask_t tlb_flush_pending;
+
+ #define ASID_MASK (~GENMASK(asid_bits - 1, 0))
+ #define ASID_FIRST_VERSION (1UL << asid_bits)
+-#define NUM_USER_ASIDS ASID_FIRST_VERSION
++
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1)
++#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1)
++#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK)
++#else
++#define NUM_USER_ASIDS (ASID_FIRST_VERSION)
++#define asid2idx(asid) ((asid) & ~ASID_MASK)
++#define idx2asid(idx) asid2idx(idx)
++#endif
+
+ /* Get the ASIDBits supported by the current CPU */
+ static u32 get_cpu_asid_bits(void)
+@@ -79,13 +88,6 @@ void verify_cpu_asid_bits(void)
+ }
+ }
+
+-static void set_reserved_asid_bits(void)
+-{
+- if (IS_ENABLED(CONFIG_QCOM_FALKOR_ERRATUM_1003) &&
+- cpus_have_const_cap(ARM64_WORKAROUND_QCOM_FALKOR_E1003))
+- __set_bit(FALKOR_RESERVED_ASID, asid_map);
+-}
+-
+ static void flush_context(unsigned int cpu)
+ {
+ int i;
+@@ -94,8 +96,6 @@ static void flush_context(unsigned int cpu)
+ /* Update the list of reserved ASIDs and the ASID bitmap. */
+ bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
+
+- set_reserved_asid_bits();
+-
+ /*
+ * Ensure the generation bump is observed before we xchg the
+ * active_asids.
+@@ -113,7 +113,7 @@ static void flush_context(unsigned int cpu)
+ */
+ if (asid == 0)
+ asid = per_cpu(reserved_asids, i);
+- __set_bit(asid & ~ASID_MASK, asid_map);
++ __set_bit(asid2idx(asid), asid_map);
+ per_cpu(reserved_asids, i) = asid;
+ }
+
+@@ -165,16 +165,16 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
+ * We had a valid ASID in a previous life, so try to re-use
+ * it if possible.
+ */
+- asid &= ~ASID_MASK;
+- if (!__test_and_set_bit(asid, asid_map))
++ if (!__test_and_set_bit(asid2idx(asid), asid_map))
+ return newasid;
+ }
+
+ /*
+ * Allocate a free ASID. If we can't find one, take a note of the
+- * currently active ASIDs and mark the TLBs as requiring flushes.
+- * We always count from ASID #1, as we use ASID #0 when setting a
+- * reserved TTBR0 for the init_mm.
++ * currently active ASIDs and mark the TLBs as requiring flushes. We
++ * always count from ASID #2 (index 1), as we use ASID #0 when setting
++ * a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd
++ * pairs.
+ */
+ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
+ if (asid != NUM_USER_ASIDS)
+@@ -191,7 +191,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
+ set_asid:
+ __set_bit(asid, asid_map);
+ cur_idx = asid;
+- return asid | generation;
++ return idx2asid(asid) | generation;
+ }
+
+ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
+@@ -227,6 +227,9 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
+ raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
+
+ switch_mm_fastpath:
++
++ arm64_apply_bp_hardening();
++
+ /*
+ * Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
+ * emulating PAN.
+@@ -235,6 +238,15 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
+ cpu_switch_mm(mm->pgd, mm);
+ }
+
++/* Errata workaround post TTBRx_EL1 update. */
++asmlinkage void post_ttbr_update_workaround(void)
++{
++ asm(ALTERNATIVE("nop; nop; nop",
++ "ic iallu; dsb nsh; isb",
++ ARM64_WORKAROUND_CAVIUM_27456,
++ CONFIG_CAVIUM_ERRATUM_27456));
++}
++
+ static int asids_init(void)
+ {
+ asid_bits = get_cpu_asid_bits();
+@@ -250,8 +262,6 @@ static int asids_init(void)
+ panic("Failed to allocate bitmap for %lu ASIDs\n",
+ NUM_USER_ASIDS);
+
+- set_reserved_asid_bits();
+-
+ pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS);
+ return 0;
+ }
+diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
+index b64958b23a7f..5edb706aacb0 100644
+--- a/arch/arm64/mm/fault.c
++++ b/arch/arm64/mm/fault.c
+@@ -242,7 +242,7 @@ static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs,
+ if (fsc_type == ESR_ELx_FSC_PERM)
+ return true;
+
+- if (addr < USER_DS && system_uses_ttbr0_pan())
++ if (addr < TASK_SIZE && system_uses_ttbr0_pan())
+ return fsc_type == ESR_ELx_FSC_FAULT &&
+ (regs->pstate & PSR_PAN_BIT);
+
+@@ -426,7 +426,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
+ mm_flags |= FAULT_FLAG_WRITE;
+ }
+
+- if (addr < USER_DS && is_permission_fault(esr, regs, addr)) {
++ if (addr < TASK_SIZE && is_permission_fault(esr, regs, addr)) {
+ /* regs->orig_addr_limit may be 0 if we entered from EL0 */
+ if (regs->orig_addr_limit == KERNEL_DS)
+ die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
+@@ -751,6 +751,29 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
+ arm64_notify_die("", regs, &info, esr);
+ }
+
++asmlinkage void __exception do_el0_irq_bp_hardening(void)
++{
++ /* PC has already been checked in entry.S */
++ arm64_apply_bp_hardening();
++}
++
++asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr,
++ unsigned int esr,
++ struct pt_regs *regs)
++{
++ /*
++ * We've taken an instruction abort from userspace and not yet
++ * re-enabled IRQs. If the address is a kernel address, apply
++ * BP hardening prior to enabling IRQs and pre-emption.
++ */
++ if (addr > TASK_SIZE)
++ arm64_apply_bp_hardening();
++
++ local_irq_enable();
++ do_mem_abort(addr, esr, regs);
++}
++
++
+ /*
+ * Handle stack alignment exceptions.
+ */
+@@ -761,6 +784,12 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
+ struct siginfo info;
+ struct task_struct *tsk = current;
+
++ if (user_mode(regs)) {
++ if (instruction_pointer(regs) > TASK_SIZE)
++ arm64_apply_bp_hardening();
++ local_irq_enable();
++ }
++
+ if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS))
+ pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n",
+ tsk->comm, task_pid_nr(tsk),
+@@ -820,6 +849,9 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
+ if (interrupts_enabled(regs))
+ trace_hardirqs_off();
+
++ if (user_mode(regs) && instruction_pointer(regs) > TASK_SIZE)
++ arm64_apply_bp_hardening();
++
+ if (!inf->fn(addr, esr, regs)) {
+ rv = 1;
+ } else {
+diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
+index f1eb15e0e864..fa20124c19d5 100644
+--- a/arch/arm64/mm/mmu.c
++++ b/arch/arm64/mm/mmu.c
+@@ -117,6 +117,10 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
+ if ((old | new) & PTE_CONT)
+ return false;
+
++ /* Transitioning from Global to Non-Global is safe */
++ if (((old ^ new) == PTE_NG) && (new & PTE_NG))
++ return true;
++
+ return ((old ^ new) & ~mask) == 0;
+ }
+
+@@ -525,6 +529,37 @@ static int __init parse_rodata(char *arg)
+ }
+ early_param("rodata", parse_rodata);
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++static int __init map_entry_trampoline(void)
++{
++ extern char __entry_tramp_text_start[];
++
++ pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
++ phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
++
++ /* The trampoline is always mapped and can therefore be global */
++ pgprot_val(prot) &= ~PTE_NG;
++
++ /* Map only the text into the trampoline page table */
++ memset(tramp_pg_dir, 0, PGD_SIZE);
++ __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
++ prot, pgd_pgtable_alloc, 0);
++
++ /* Map both the text and data into the kernel page table */
++ __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
++ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
++ extern char __entry_tramp_data_start[];
++
++ __set_fixmap(FIX_ENTRY_TRAMP_DATA,
++ __pa_symbol(__entry_tramp_data_start),
++ PAGE_KERNEL_RO);
++ }
++
++ return 0;
++}
++core_initcall(map_entry_trampoline);
++#endif
++
+ /*
+ * Create fine-grained mappings for the kernel.
+ */
+diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
+index 877d42fb0df6..27058f3fd132 100644
+--- a/arch/arm64/mm/proc.S
++++ b/arch/arm64/mm/proc.S
+@@ -86,7 +86,7 @@ ENDPROC(cpu_do_suspend)
+ *
+ * x0: Address of context pointer
+ */
+- .pushsection ".idmap.text", "ax"
++ .pushsection ".idmap.text", "awx"
+ ENTRY(cpu_do_resume)
+ ldp x2, x3, [x0]
+ ldp x4, x5, [x0, #16]
+@@ -138,16 +138,30 @@ ENDPROC(cpu_do_resume)
+ * - pgd_phys - physical address of new TTB
+ */
+ ENTRY(cpu_do_switch_mm)
+- pre_ttbr0_update_workaround x0, x2, x3
++ mrs x2, ttbr1_el1
+ mmid x1, x1 // get mm->context.id
+- bfi x0, x1, #48, #16 // set the ASID
+- msr ttbr0_el1, x0 // set TTBR0
++#ifdef CONFIG_ARM64_SW_TTBR0_PAN
++ bfi x0, x1, #48, #16 // set the ASID field in TTBR0
++#endif
++ bfi x2, x1, #48, #16 // set the ASID
++ msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set)
+ isb
+- post_ttbr0_update_workaround
+- ret
++ msr ttbr0_el1, x0 // now update TTBR0
++ isb
++ b post_ttbr_update_workaround // Back to C code...
+ ENDPROC(cpu_do_switch_mm)
+
+- .pushsection ".idmap.text", "ax"
++ .pushsection ".idmap.text", "awx"
++
++.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
++ adrp \tmp1, empty_zero_page
++ msr ttbr1_el1, \tmp2
++ isb
++ tlbi vmalle1
++ dsb nsh
++ isb
++.endm
++
+ /*
+ * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd)
+ *
+@@ -158,13 +172,7 @@ ENTRY(idmap_cpu_replace_ttbr1)
+ mrs x2, daif
+ msr daifset, #0xf
+
+- adrp x1, empty_zero_page
+- msr ttbr1_el1, x1
+- isb
+-
+- tlbi vmalle1
+- dsb nsh
+- isb
++ __idmap_cpu_set_reserved_ttbr1 x1, x3
+
+ msr ttbr1_el1, x0
+ isb
+@@ -175,13 +183,196 @@ ENTRY(idmap_cpu_replace_ttbr1)
+ ENDPROC(idmap_cpu_replace_ttbr1)
+ .popsection
+
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ .pushsection ".idmap.text", "awx"
++
++ .macro __idmap_kpti_get_pgtable_ent, type
++ dc cvac, cur_\()\type\()p // Ensure any existing dirty
++ dmb sy // lines are written back before
++ ldr \type, [cur_\()\type\()p] // loading the entry
++ tbz \type, #0, next_\()\type // Skip invalid entries
++ .endm
++
++ .macro __idmap_kpti_put_pgtable_ent_ng, type
++ orr \type, \type, #PTE_NG // Same bit for blocks and pages
++ str \type, [cur_\()\type\()p] // Update the entry and ensure it
++ dc civac, cur_\()\type\()p // is visible to all CPUs.
++ .endm
++
++/*
++ * void __kpti_install_ng_mappings(int cpu, int num_cpus, phys_addr_t swapper)
++ *
++ * Called exactly once from stop_machine context by each CPU found during boot.
++ */
++__idmap_kpti_flag:
++ .long 1
++ENTRY(idmap_kpti_install_ng_mappings)
++ cpu .req w0
++ num_cpus .req w1
++ swapper_pa .req x2
++ swapper_ttb .req x3
++ flag_ptr .req x4
++ cur_pgdp .req x5
++ end_pgdp .req x6
++ pgd .req x7
++ cur_pudp .req x8
++ end_pudp .req x9
++ pud .req x10
++ cur_pmdp .req x11
++ end_pmdp .req x12
++ pmd .req x13
++ cur_ptep .req x14
++ end_ptep .req x15
++ pte .req x16
++
++ mrs swapper_ttb, ttbr1_el1
++ adr flag_ptr, __idmap_kpti_flag
++
++ cbnz cpu, __idmap_kpti_secondary
++
++ /* We're the boot CPU. Wait for the others to catch up */
++ sevl
++1: wfe
++ ldaxr w18, [flag_ptr]
++ eor w18, w18, num_cpus
++ cbnz w18, 1b
++
++ /* We need to walk swapper, so turn off the MMU. */
++ mrs x18, sctlr_el1
++ bic x18, x18, #SCTLR_ELx_M
++ msr sctlr_el1, x18
++ isb
++
++ /* Everybody is enjoying the idmap, so we can rewrite swapper. */
++ /* PGD */
++ mov cur_pgdp, swapper_pa
++ add end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8)
++do_pgd: __idmap_kpti_get_pgtable_ent pgd
++ tbnz pgd, #1, walk_puds
++ __idmap_kpti_put_pgtable_ent_ng pgd
++next_pgd:
++ add cur_pgdp, cur_pgdp, #8
++ cmp cur_pgdp, end_pgdp
++ b.ne do_pgd
++
++ /* Publish the updated tables and nuke all the TLBs */
++ dsb sy
++ tlbi vmalle1is
++ dsb ish
++ isb
++
++ /* We're done: fire up the MMU again */
++ mrs x18, sctlr_el1
++ orr x18, x18, #SCTLR_ELx_M
++ msr sctlr_el1, x18
++ isb
++
++ /* Set the flag to zero to indicate that we're all done */
++ str wzr, [flag_ptr]
++ ret
++
++ /* PUD */
++walk_puds:
++ .if CONFIG_PGTABLE_LEVELS > 3
++ pte_to_phys cur_pudp, pgd
++ add end_pudp, cur_pudp, #(PTRS_PER_PUD * 8)
++do_pud: __idmap_kpti_get_pgtable_ent pud
++ tbnz pud, #1, walk_pmds
++ __idmap_kpti_put_pgtable_ent_ng pud
++next_pud:
++ add cur_pudp, cur_pudp, 8
++ cmp cur_pudp, end_pudp
++ b.ne do_pud
++ b next_pgd
++ .else /* CONFIG_PGTABLE_LEVELS <= 3 */
++ mov pud, pgd
++ b walk_pmds
++next_pud:
++ b next_pgd
++ .endif
++
++ /* PMD */
++walk_pmds:
++ .if CONFIG_PGTABLE_LEVELS > 2
++ pte_to_phys cur_pmdp, pud
++ add end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8)
++do_pmd: __idmap_kpti_get_pgtable_ent pmd
++ tbnz pmd, #1, walk_ptes
++ __idmap_kpti_put_pgtable_ent_ng pmd
++next_pmd:
++ add cur_pmdp, cur_pmdp, #8
++ cmp cur_pmdp, end_pmdp
++ b.ne do_pmd
++ b next_pud
++ .else /* CONFIG_PGTABLE_LEVELS <= 2 */
++ mov pmd, pud
++ b walk_ptes
++next_pmd:
++ b next_pud
++ .endif
++
++ /* PTE */
++walk_ptes:
++ pte_to_phys cur_ptep, pmd
++ add end_ptep, cur_ptep, #(PTRS_PER_PTE * 8)
++do_pte: __idmap_kpti_get_pgtable_ent pte
++ __idmap_kpti_put_pgtable_ent_ng pte
++next_pte:
++ add cur_ptep, cur_ptep, #8
++ cmp cur_ptep, end_ptep
++ b.ne do_pte
++ b next_pmd
++
++ /* Secondary CPUs end up here */
++__idmap_kpti_secondary:
++ /* Uninstall swapper before surgery begins */
++ __idmap_cpu_set_reserved_ttbr1 x18, x17
++
++ /* Increment the flag to let the boot CPU we're ready */
++1: ldxr w18, [flag_ptr]
++ add w18, w18, #1
++ stxr w17, w18, [flag_ptr]
++ cbnz w17, 1b
++
++ /* Wait for the boot CPU to finish messing around with swapper */
++ sevl
++1: wfe
++ ldxr w18, [flag_ptr]
++ cbnz w18, 1b
++
++ /* All done, act like nothing happened */
++ msr ttbr1_el1, swapper_ttb
++ isb
++ ret
++
++ .unreq cpu
++ .unreq num_cpus
++ .unreq swapper_pa
++ .unreq swapper_ttb
++ .unreq flag_ptr
++ .unreq cur_pgdp
++ .unreq end_pgdp
++ .unreq pgd
++ .unreq cur_pudp
++ .unreq end_pudp
++ .unreq pud
++ .unreq cur_pmdp
++ .unreq end_pmdp
++ .unreq pmd
++ .unreq cur_ptep
++ .unreq end_ptep
++ .unreq pte
++ENDPROC(idmap_kpti_install_ng_mappings)
++ .popsection
++#endif
++
+ /*
+ * __cpu_setup
+ *
+ * Initialise the processor for turning the MMU on. Return in x0 the
+ * value of the SCTLR_EL1 register.
+ */
+- .pushsection ".idmap.text", "ax"
++ .pushsection ".idmap.text", "awx"
+ ENTRY(__cpu_setup)
+ tlbi vmalle1 // Invalidate local TLB
+ dsb nsh
+@@ -225,7 +416,7 @@ ENTRY(__cpu_setup)
+ * both user and kernel.
+ */
+ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
+- TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0
++ TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1
+ tcr_set_idmap_t0sz x10, x9
+
+ /*
+diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
+index 401ceb71540c..c5f05c4a4d00 100644
+--- a/arch/arm64/xen/hypercall.S
++++ b/arch/arm64/xen/hypercall.S
+@@ -101,12 +101,12 @@ ENTRY(privcmd_call)
+ * need the explicit uaccess_enable/disable if the TTBR0 PAN emulation
+ * is enabled (it implies that hardware UAO and PAN disabled).
+ */
+- uaccess_ttbr0_enable x6, x7
++ uaccess_ttbr0_enable x6, x7, x8
+ hvc XEN_IMM
+
+ /*
+ * Disable userspace access from kernel once the hyp call completed.
+ */
+- uaccess_ttbr0_disable x6
++ uaccess_ttbr0_disable x6, x7
+ ret
+ ENDPROC(privcmd_call);
+diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
+index b39a388825ae..8ace89617c1c 100644
+--- a/arch/mn10300/mm/misalignment.c
++++ b/arch/mn10300/mm/misalignment.c
+@@ -437,7 +437,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
+
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+- info.si_code = 0;
++ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void *) regs->pc;
+ force_sig_info(SIGSEGV, &info, current);
+ return;
+diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
+index 803e9e756f77..8d8437169b5e 100644
+--- a/arch/openrisc/kernel/traps.c
++++ b/arch/openrisc/kernel/traps.c
+@@ -306,12 +306,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
+ siginfo_t info;
+
+ if (user_mode(regs)) {
+- /* Send a SIGSEGV */
+- info.si_signo = SIGSEGV;
++ /* Send a SIGBUS */
++ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+- /* info.si_code has been set above */
+- info.si_addr = (void *)address;
+- force_sig_info(SIGSEGV, &info, current);
++ info.si_code = BUS_ADRALN;
++ info.si_addr = (void __user *)address;
++ force_sig_info(SIGBUS, &info, current);
+ } else {
+ printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
+ show_registers(regs);
+diff --git a/arch/powerpc/crypto/crc32c-vpmsum_glue.c b/arch/powerpc/crypto/crc32c-vpmsum_glue.c
+index f058e0c3e4d4..fd1d6c83f0c0 100644
+--- a/arch/powerpc/crypto/crc32c-vpmsum_glue.c
++++ b/arch/powerpc/crypto/crc32c-vpmsum_glue.c
+@@ -141,6 +141,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-vpmsum",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
+index f0461618bf7b..eca3f9c68907 100644
+--- a/arch/powerpc/include/asm/hvcall.h
++++ b/arch/powerpc/include/asm/hvcall.h
+@@ -353,6 +353,7 @@
+ #define PROC_TABLE_GTSE 0x01
+
+ #ifndef __ASSEMBLY__
++#include <linux/types.h>
+
+ /**
+ * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
+diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
+index b12b8eb39c29..648160334abf 100644
+--- a/arch/powerpc/kvm/Kconfig
++++ b/arch/powerpc/kvm/Kconfig
+@@ -68,7 +68,7 @@ config KVM_BOOK3S_64
+ select KVM_BOOK3S_64_HANDLER
+ select KVM
+ select KVM_BOOK3S_PR_POSSIBLE if !KVM_BOOK3S_HV_POSSIBLE
+- select SPAPR_TCE_IOMMU if IOMMU_SUPPORT && (PPC_SERIES || PPC_POWERNV)
++ select SPAPR_TCE_IOMMU if IOMMU_SUPPORT && (PPC_PSERIES || PPC_POWERNV)
+ ---help---
+ Support running unmodified book3s_64 and book3s_32 guest kernels
+ in virtual machines on book3s_64 host processors.
+diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
+index 8d43cf205d34..f48e3379a18a 100644
+--- a/arch/powerpc/kvm/book3s_hv.c
++++ b/arch/powerpc/kvm/book3s_hv.c
+@@ -999,8 +999,6 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu)
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_vcpu *tvcpu;
+
+- if (!cpu_has_feature(CPU_FTR_ARCH_300))
+- return EMULATE_FAIL;
+ if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst) != EMULATE_DONE)
+ return RESUME_GUEST;
+ if (get_op(inst) != 31)
+@@ -1050,6 +1048,7 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu)
+ return RESUME_GUEST;
+ }
+
++/* Called with vcpu->arch.vcore->lock held */
+ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ struct task_struct *tsk)
+ {
+@@ -1169,7 +1168,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ swab32(vcpu->arch.emul_inst) :
+ vcpu->arch.emul_inst;
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
++ /* Need vcore unlocked to call kvmppc_get_last_inst */
++ spin_unlock(&vcpu->arch.vcore->lock);
+ r = kvmppc_emulate_debug_inst(run, vcpu);
++ spin_lock(&vcpu->arch.vcore->lock);
+ } else {
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ r = RESUME_GUEST;
+@@ -1184,8 +1186,13 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ */
+ case BOOK3S_INTERRUPT_H_FAC_UNAVAIL:
+ r = EMULATE_FAIL;
+- if ((vcpu->arch.hfscr >> 56) == FSCR_MSGP_LG)
++ if (((vcpu->arch.hfscr >> 56) == FSCR_MSGP_LG) &&
++ cpu_has_feature(CPU_FTR_ARCH_300)) {
++ /* Need vcore unlocked to call kvmppc_get_last_inst */
++ spin_unlock(&vcpu->arch.vcore->lock);
+ r = kvmppc_emulate_doorbell_instr(vcpu);
++ spin_lock(&vcpu->arch.vcore->lock);
++ }
+ if (r == EMULATE_FAIL) {
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ r = RESUME_GUEST;
+@@ -2889,13 +2896,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
+ /* make sure updates to secondary vcpu structs are visible now */
+ smp_mb();
+
++ preempt_enable();
++
+ for (sub = 0; sub < core_info.n_subcores; ++sub) {
+ pvc = core_info.vc[sub];
+ post_guest_process(pvc, pvc == vc);
+ }
+
+ spin_lock(&vc->lock);
+- preempt_enable();
+
+ out:
+ vc->vcore_state = VCORE_INACTIVE;
+diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+index c85ac5c83bd4..2b3194b9608f 100644
+--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+@@ -1387,6 +1387,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
+ blt deliver_guest_interrupt
+
+ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
++ /* Save more register state */
++ mfdar r6
++ mfdsisr r7
++ std r6, VCPU_DAR(r9)
++ stw r7, VCPU_DSISR(r9)
++ /* don't overwrite fault_dar/fault_dsisr if HDSI */
++ cmpwi r12,BOOK3S_INTERRUPT_H_DATA_STORAGE
++ beq mc_cont
++ std r6, VCPU_FAULT_DAR(r9)
++ stw r7, VCPU_FAULT_DSISR(r9)
++
++ /* See if it is a machine check */
++ cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK
++ beq machine_check_realmode
++mc_cont:
++#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
++ addi r3, r9, VCPU_TB_RMEXIT
++ mr r4, r9
++ bl kvmhv_accumulate_time
++#endif
+ #ifdef CONFIG_KVM_XICS
+ /* We are exiting, pull the VP from the XIVE */
+ lwz r0, VCPU_XIVE_PUSHED(r9)
+@@ -1424,26 +1444,6 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
+ eieio
+ 1:
+ #endif /* CONFIG_KVM_XICS */
+- /* Save more register state */
+- mfdar r6
+- mfdsisr r7
+- std r6, VCPU_DAR(r9)
+- stw r7, VCPU_DSISR(r9)
+- /* don't overwrite fault_dar/fault_dsisr if HDSI */
+- cmpwi r12,BOOK3S_INTERRUPT_H_DATA_STORAGE
+- beq mc_cont
+- std r6, VCPU_FAULT_DAR(r9)
+- stw r7, VCPU_FAULT_DSISR(r9)
+-
+- /* See if it is a machine check */
+- cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK
+- beq machine_check_realmode
+-mc_cont:
+-#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
+- addi r3, r9, VCPU_TB_RMEXIT
+- mr r4, r9
+- bl kvmhv_accumulate_time
+-#endif
+
+ mr r3, r12
+ /* Increment exit count, poke other threads to exit */
+diff --git a/arch/s390/crypto/crc32-vx.c b/arch/s390/crypto/crc32-vx.c
+index 992e630c227b..6f4985f357c6 100644
+--- a/arch/s390/crypto/crc32-vx.c
++++ b/arch/s390/crypto/crc32-vx.c
+@@ -238,6 +238,7 @@ static struct shash_alg crc32_vx_algs[] = {
+ .cra_name = "crc32",
+ .cra_driver_name = "crc32-vx",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CRC32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crc_ctx),
+ .cra_module = THIS_MODULE,
+@@ -258,6 +259,7 @@ static struct shash_alg crc32_vx_algs[] = {
+ .cra_name = "crc32be",
+ .cra_driver_name = "crc32be-vx",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CRC32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crc_ctx),
+ .cra_module = THIS_MODULE,
+@@ -278,6 +280,7 @@ static struct shash_alg crc32_vx_algs[] = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-vx",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CRC32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crc_ctx),
+ .cra_module = THIS_MODULE,
+diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
+index 57cff00cad17..b3770bb26211 100644
+--- a/arch/sh/kernel/traps_32.c
++++ b/arch/sh/kernel/traps_32.c
+@@ -609,7 +609,8 @@ asmlinkage void do_divide_error(unsigned long r4)
+ break;
+ }
+
+- force_sig_info(SIGFPE, &info, current);
++ info.si_signo = SIGFPE;
++ force_sig_info(info.si_signo, &info, current);
+ }
+ #endif
+
+diff --git a/arch/sparc/crypto/crc32c_glue.c b/arch/sparc/crypto/crc32c_glue.c
+index d1064e46efe8..8aa664638c3c 100644
+--- a/arch/sparc/crypto/crc32c_glue.c
++++ b/arch/sparc/crypto/crc32c_glue.c
+@@ -133,6 +133,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-sparc64",
+ .cra_priority = SPARC_CR_OPCODE_PRIORITY,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_alignmask = 7,
+diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c
+index 27226df3f7d8..c8d9cdacbf10 100644
+--- a/arch/x86/crypto/crc32-pclmul_glue.c
++++ b/arch/x86/crypto/crc32-pclmul_glue.c
+@@ -162,6 +162,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32",
+ .cra_driver_name = "crc32-pclmul",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c
+index c194d5717ae5..5773e1161072 100644
+--- a/arch/x86/crypto/crc32c-intel_glue.c
++++ b/arch/x86/crypto/crc32c-intel_glue.c
+@@ -226,6 +226,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-intel",
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c
+index e32142bc071d..28c372003e44 100644
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -164,7 +164,6 @@ static struct shash_alg alg = {
+ .init = poly1305_simd_init,
+ .update = poly1305_simd_update,
+ .final = crypto_poly1305_final,
+- .setkey = crypto_poly1305_setkey,
+ .descsize = sizeof(struct poly1305_simd_desc_ctx),
+ .base = {
+ .cra_name = "poly1305",
+diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
+index 36870b26067a..d08805032f01 100644
+--- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
++++ b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c
+@@ -57,10 +57,12 @@ void sha512_mb_mgr_init_avx2(struct sha512_mb_mgr *state)
+ {
+ unsigned int j;
+
+- state->lens[0] = 0;
+- state->lens[1] = 1;
+- state->lens[2] = 2;
+- state->lens[3] = 3;
++ /* initially all lanes are unused */
++ state->lens[0] = 0xFFFFFFFF00000000;
++ state->lens[1] = 0xFFFFFFFF00000001;
++ state->lens[2] = 0xFFFFFFFF00000002;
++ state->lens[3] = 0xFFFFFFFF00000003;
++
+ state->unused_lanes = 0xFF03020100;
+ for (j = 0; j < 4; j++)
+ state->ldata[j].job_in_lane = NULL;
+diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
+index 0fce8d73403c..beb7f8795bc1 100644
+--- a/arch/x86/kvm/mmu.c
++++ b/arch/x86/kvm/mmu.c
+@@ -3784,7 +3784,8 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
+ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
+ {
+ if (unlikely(!lapic_in_kernel(vcpu) ||
+- kvm_event_needs_reinjection(vcpu)))
++ kvm_event_needs_reinjection(vcpu) ||
++ vcpu->arch.exception.pending))
+ return false;
+
+ if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
+diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
+index 0ae4b1a86168..0ea909ca45c2 100644
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -5322,14 +5322,15 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
+
+ if (is_guest_mode(vcpu) &&
+ vector == vmx->nested.posted_intr_nv) {
+- /* the PIR and ON have been set by L1. */
+- kvm_vcpu_trigger_posted_interrupt(vcpu, true);
+ /*
+ * If a posted intr is not recognized by hardware,
+ * we will accomplish it in the next vmentry.
+ */
+ vmx->nested.pi_pending = true;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
++ /* the PIR and ON have been set by L1. */
++ if (!kvm_vcpu_trigger_posted_interrupt(vcpu, true))
++ kvm_vcpu_kick(vcpu);
+ return 0;
+ }
+ return -1;
+@@ -11245,7 +11246,6 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
+ if (block_nested_events)
+ return -EBUSY;
+ nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
+- vcpu->arch.exception.pending = false;
+ return 0;
+ }
+
+diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
+index d0b95b7a90b4..6d112d8f799c 100644
+--- a/arch/x86/kvm/x86.h
++++ b/arch/x86/kvm/x86.h
+@@ -12,6 +12,7 @@
+
+ static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu)
+ {
++ vcpu->arch.exception.pending = false;
+ vcpu->arch.exception.injected = false;
+ }
+
+diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
+index eaaf1ebcc7a4..5bfbc1c401d4 100644
+--- a/arch/xtensa/include/asm/futex.h
++++ b/arch/xtensa/include/asm/futex.h
+@@ -92,7 +92,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+ {
+ int ret = 0;
+- u32 prev;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ return -EFAULT;
+@@ -103,26 +102,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+
+ __asm__ __volatile__ (
+ " # futex_atomic_cmpxchg_inatomic\n"
+- "1: l32i %1, %3, 0\n"
+- " mov %0, %5\n"
+- " wsr %1, scompare1\n"
+- "2: s32c1i %0, %3, 0\n"
+- "3:\n"
++ " wsr %5, scompare1\n"
++ "1: s32c1i %1, %4, 0\n"
++ " s32i %1, %6, 0\n"
++ "2:\n"
+ " .section .fixup,\"ax\"\n"
+ " .align 4\n"
+- "4: .long 3b\n"
+- "5: l32r %1, 4b\n"
+- " movi %0, %6\n"
++ "3: .long 2b\n"
++ "4: l32r %1, 3b\n"
++ " movi %0, %7\n"
+ " jx %1\n"
+ " .previous\n"
+ " .section __ex_table,\"a\"\n"
+- " .long 1b,5b,2b,5b\n"
++ " .long 1b,4b\n"
+ " .previous\n"
+- : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
+- : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
++ : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
++ : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
+ : "memory");
+
+- *uval = prev;
+ return ret;
+ }
+
+diff --git a/block/blk-core.c b/block/blk-core.c
+index 7b30bf10b1d4..f3750389e351 100644
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -660,6 +660,15 @@ void blk_cleanup_queue(struct request_queue *q)
+ queue_flag_set(QUEUE_FLAG_DEAD, q);
+ spin_unlock_irq(lock);
+
++ /*
++ * make sure all in-progress dispatch are completed because
++ * blk_freeze_queue() can only complete all requests, and
++ * dispatch may still be in-progress since we dispatch requests
++ * from more than one contexts
++ */
++ if (q->mq_ops)
++ blk_mq_quiesce_queue(q);
++
+ /* for synchronous bio-based driver finish in-flight integrity i/o */
+ blk_flush_integrity();
+
+diff --git a/crypto/ahash.c b/crypto/ahash.c
+index 5e8666e6ccae..f75b5c1f7152 100644
+--- a/crypto/ahash.c
++++ b/crypto/ahash.c
+@@ -193,11 +193,18 @@ int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+ {
+ unsigned long alignmask = crypto_ahash_alignmask(tfm);
++ int err;
+
+ if ((unsigned long)key & alignmask)
+- return ahash_setkey_unaligned(tfm, key, keylen);
++ err = ahash_setkey_unaligned(tfm, key, keylen);
++ else
++ err = tfm->setkey(tfm, key, keylen);
++
++ if (err)
++ return err;
+
+- return tfm->setkey(tfm, key, keylen);
++ crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
+
+@@ -370,7 +377,12 @@ EXPORT_SYMBOL_GPL(crypto_ahash_finup);
+
+ int crypto_ahash_digest(struct ahash_request *req)
+ {
+- return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++
++ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
++ return crypto_ahash_op(req, tfm->digest);
+ }
+ EXPORT_SYMBOL_GPL(crypto_ahash_digest);
+
+@@ -456,7 +468,6 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
+ struct ahash_alg *alg = crypto_ahash_alg(hash);
+
+ hash->setkey = ahash_nosetkey;
+- hash->has_setkey = false;
+ hash->export = ahash_no_export;
+ hash->import = ahash_no_import;
+
+@@ -471,7 +482,8 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
+
+ if (alg->setkey) {
+ hash->setkey = alg->setkey;
+- hash->has_setkey = true;
++ if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
++ crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
+ }
+ if (alg->export)
+ hash->export = alg->export;
+@@ -655,5 +667,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+ }
+ EXPORT_SYMBOL_GPL(ahash_attr_alg);
+
++bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
++{
++ struct crypto_alg *alg = &halg->base;
++
++ if (alg->cra_type != &crypto_ahash_type)
++ return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
++
++ return __crypto_ahash_alg(alg)->setkey != NULL;
++}
++EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
++
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
+diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
+index 5e92bd275ef3..39cebd3256bf 100644
+--- a/crypto/algif_hash.c
++++ b/crypto/algif_hash.c
+@@ -34,11 +34,6 @@ struct hash_ctx {
+ struct ahash_request req;
+ };
+
+-struct algif_hash_tfm {
+- struct crypto_ahash *hash;
+- bool has_key;
+-};
+-
+ static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
+ {
+ unsigned ds;
+@@ -309,7 +304,7 @@ static int hash_check_key(struct socket *sock)
+ int err = 0;
+ struct sock *psk;
+ struct alg_sock *pask;
+- struct algif_hash_tfm *tfm;
++ struct crypto_ahash *tfm;
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+
+@@ -323,7 +318,7 @@ static int hash_check_key(struct socket *sock)
+
+ err = -ENOKEY;
+ lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+- if (!tfm->has_key)
++ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ goto unlock;
+
+ if (!pask->refcnt++)
+@@ -414,41 +409,17 @@ static struct proto_ops algif_hash_ops_nokey = {
+
+ static void *hash_bind(const char *name, u32 type, u32 mask)
+ {
+- struct algif_hash_tfm *tfm;
+- struct crypto_ahash *hash;
+-
+- tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+- if (!tfm)
+- return ERR_PTR(-ENOMEM);
+-
+- hash = crypto_alloc_ahash(name, type, mask);
+- if (IS_ERR(hash)) {
+- kfree(tfm);
+- return ERR_CAST(hash);
+- }
+-
+- tfm->hash = hash;
+-
+- return tfm;
++ return crypto_alloc_ahash(name, type, mask);
+ }
+
+ static void hash_release(void *private)
+ {
+- struct algif_hash_tfm *tfm = private;
+-
+- crypto_free_ahash(tfm->hash);
+- kfree(tfm);
++ crypto_free_ahash(private);
+ }
+
+ static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
+ {
+- struct algif_hash_tfm *tfm = private;
+- int err;
+-
+- err = crypto_ahash_setkey(tfm->hash, key, keylen);
+- tfm->has_key = !err;
+-
+- return err;
++ return crypto_ahash_setkey(private, key, keylen);
+ }
+
+ static void hash_sock_destruct(struct sock *sk)
+@@ -463,11 +434,10 @@ static void hash_sock_destruct(struct sock *sk)
+
+ static int hash_accept_parent_nokey(void *private, struct sock *sk)
+ {
+- struct hash_ctx *ctx;
++ struct crypto_ahash *tfm = private;
+ struct alg_sock *ask = alg_sk(sk);
+- struct algif_hash_tfm *tfm = private;
+- struct crypto_ahash *hash = tfm->hash;
+- unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
++ struct hash_ctx *ctx;
++ unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
+
+ ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+ if (!ctx)
+@@ -480,7 +450,7 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk)
+
+ ask->private = ctx;
+
+- ahash_request_set_tfm(&ctx->req, hash);
++ ahash_request_set_tfm(&ctx->req, tfm);
+ ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ af_alg_complete, &ctx->completion);
+
+@@ -491,9 +461,9 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk)
+
+ static int hash_accept_parent(void *private, struct sock *sk)
+ {
+- struct algif_hash_tfm *tfm = private;
++ struct crypto_ahash *tfm = private;
+
+- if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
++ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+ return -ENOKEY;
+
+ return hash_accept_parent_nokey(private, sk);
+diff --git a/crypto/crc32_generic.c b/crypto/crc32_generic.c
+index aa2a25fc7482..718cbce8d169 100644
+--- a/crypto/crc32_generic.c
++++ b/crypto/crc32_generic.c
+@@ -133,6 +133,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32",
+ .cra_driver_name = "crc32-generic",
+ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c
+index 4c0a0e271876..372320399622 100644
+--- a/crypto/crc32c_generic.c
++++ b/crypto/crc32c_generic.c
+@@ -146,6 +146,7 @@ static struct shash_alg alg = {
+ .cra_name = "crc32c",
+ .cra_driver_name = "crc32c-generic",
+ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_alignmask = 3,
+ .cra_ctxsize = sizeof(struct chksum_ctx),
+diff --git a/crypto/cryptd.c b/crypto/cryptd.c
+index 0508c48a45c4..248f6ba41688 100644
+--- a/crypto/cryptd.c
++++ b/crypto/cryptd.c
+@@ -895,10 +895,9 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
+ if (err)
+ goto out_free_inst;
+
+- type = CRYPTO_ALG_ASYNC;
+- if (alg->cra_flags & CRYPTO_ALG_INTERNAL)
+- type |= CRYPTO_ALG_INTERNAL;
+- inst->alg.halg.base.cra_flags = type;
++ inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC |
++ (alg->cra_flags & (CRYPTO_ALG_INTERNAL |
++ CRYPTO_ALG_OPTIONAL_KEY));
+
+ inst->alg.halg.digestsize = salg->digestsize;
+ inst->alg.halg.statesize = salg->statesize;
+@@ -913,7 +912,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
+ inst->alg.finup = cryptd_hash_finup_enqueue;
+ inst->alg.export = cryptd_hash_export;
+ inst->alg.import = cryptd_hash_import;
+- inst->alg.setkey = cryptd_hash_setkey;
++ if (crypto_shash_alg_has_setkey(salg))
++ inst->alg.setkey = cryptd_hash_setkey;
+ inst->alg.digest = cryptd_hash_digest_enqueue;
+
+ err = ahash_register_instance(tmpl, inst);
+diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
+index eca04d3729b3..e0732d979e3b 100644
+--- a/crypto/mcryptd.c
++++ b/crypto/mcryptd.c
+@@ -517,10 +517,9 @@ static int mcryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
+ if (err)
+ goto out_free_inst;
+
+- type = CRYPTO_ALG_ASYNC;
+- if (alg->cra_flags & CRYPTO_ALG_INTERNAL)
+- type |= CRYPTO_ALG_INTERNAL;
+- inst->alg.halg.base.cra_flags = type;
++ inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC |
++ (alg->cra_flags & (CRYPTO_ALG_INTERNAL |
++ CRYPTO_ALG_OPTIONAL_KEY));
+
+ inst->alg.halg.digestsize = halg->digestsize;
+ inst->alg.halg.statesize = halg->statesize;
+@@ -535,7 +534,8 @@ static int mcryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
+ inst->alg.finup = mcryptd_hash_finup_enqueue;
+ inst->alg.export = mcryptd_hash_export;
+ inst->alg.import = mcryptd_hash_import;
+- inst->alg.setkey = mcryptd_hash_setkey;
++ if (crypto_hash_alg_has_setkey(halg))
++ inst->alg.setkey = mcryptd_hash_setkey;
+ inst->alg.digest = mcryptd_hash_digest_enqueue;
+
+ err = ahash_register_instance(tmpl, inst);
+diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
+index b1c2d57dc734..ba39eb308c79 100644
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -47,17 +47,6 @@ int crypto_poly1305_init(struct shash_desc *desc)
+ }
+ EXPORT_SYMBOL_GPL(crypto_poly1305_init);
+
+-int crypto_poly1305_setkey(struct crypto_shash *tfm,
+- const u8 *key, unsigned int keylen)
+-{
+- /* Poly1305 requires a unique key for each tag, which implies that
+- * we can't set it on the tfm that gets accessed by multiple users
+- * simultaneously. Instead we expect the key as the first 32 bytes in
+- * the update() call. */
+- return -ENOTSUPP;
+-}
+-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
+-
+ static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
+ {
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+@@ -76,6 +65,11 @@ static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
+ dctx->s[3] = get_unaligned_le32(key + 12);
+ }
+
++/*
++ * Poly1305 requires a unique key for each tag, which implies that we can't set
++ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
++ * expect the key as the first 32 bytes in the update() call.
++ */
+ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+ const u8 *src, unsigned int srclen)
+ {
+@@ -281,7 +275,6 @@ static struct shash_alg poly1305_alg = {
+ .init = crypto_poly1305_init,
+ .update = crypto_poly1305_update,
+ .final = crypto_poly1305_final,
+- .setkey = crypto_poly1305_setkey,
+ .descsize = sizeof(struct poly1305_desc_ctx),
+ .base = {
+ .cra_name = "poly1305",
+diff --git a/crypto/shash.c b/crypto/shash.c
+index e849d3ee2e27..5d732c6bb4b2 100644
+--- a/crypto/shash.c
++++ b/crypto/shash.c
+@@ -58,11 +58,18 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
+ {
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
++ int err;
+
+ if ((unsigned long)key & alignmask)
+- return shash_setkey_unaligned(tfm, key, keylen);
++ err = shash_setkey_unaligned(tfm, key, keylen);
++ else
++ err = shash->setkey(tfm, key, keylen);
++
++ if (err)
++ return err;
+
+- return shash->setkey(tfm, key, keylen);
++ crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(crypto_shash_setkey);
+
+@@ -181,6 +188,9 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
++ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
+ if (((unsigned long)data | (unsigned long)out) & alignmask)
+ return shash_digest_unaligned(desc, data, len, out);
+
+@@ -360,7 +370,8 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
+ crt->digest = shash_async_digest;
+ crt->setkey = shash_async_setkey;
+
+- crt->has_setkey = alg->setkey != shash_no_setkey;
++ crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) &
++ CRYPTO_TFM_NEED_KEY);
+
+ if (alg->export)
+ crt->export = shash_async_export;
+@@ -375,8 +386,14 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
+ static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
+ {
+ struct crypto_shash *hash = __crypto_shash_cast(tfm);
++ struct shash_alg *alg = crypto_shash_alg(hash);
++
++ hash->descsize = alg->descsize;
++
++ if (crypto_shash_alg_has_setkey(alg) &&
++ !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
++ crypto_shash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
+
+- hash->descsize = crypto_shash_alg(hash)->descsize;
+ return 0;
+ }
+
+diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
+index dea0fb3d6f64..f14b4326e855 100644
+--- a/drivers/acpi/nfit/core.c
++++ b/drivers/acpi/nfit/core.c
+@@ -1618,6 +1618,9 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
+ struct kernfs_node *nfit_kernfs;
+
+ nvdimm = nfit_mem->nvdimm;
++ if (!nvdimm)
++ continue;
++
+ nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
+ if (nfit_kernfs)
+ nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
+diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
+index 2fa8304171e0..7a3431018e0a 100644
+--- a/drivers/acpi/sbshc.c
++++ b/drivers/acpi/sbshc.c
+@@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
+ device->driver_data = hc;
+
+ acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
+- printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
+- hc->ec, hc->offset, hc->query_bit);
++ dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
++ hc->offset, hc->query_bit);
+
+ return 0;
+ }
+diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
+index 9f78bb03bb76..bc013f757d5d 100644
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -267,9 +267,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
+- { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
++ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+- { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
++ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
+ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
+@@ -292,9 +292,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
+ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+- { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
++ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+- { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
++ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */
+ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
+@@ -303,20 +303,20 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
+ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
+- { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
++ { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
+- { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
++ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */
+ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
+- { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
++ { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
+- { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
++ { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */
+ { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
+- { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
++ { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */
+ { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
+- { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
++ { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */
+ { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
+@@ -357,21 +357,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
+- { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
++ { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
+- { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
++ { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */
+ { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
+- { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
++ { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */
+ { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
+- { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
++ { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */
+ { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
+- { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
++ { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */
+ { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
+ { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
+- { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
++ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */
+ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
+@@ -385,6 +385,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
++ { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
++ { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
++ { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
++ { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
++ { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
+
+ /* JMicron 360/1/3/5/6, match class to avoid IDE function */
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
+index 67974796c350..531a0915066b 100644
+--- a/drivers/block/pktcdvd.c
++++ b/drivers/block/pktcdvd.c
+@@ -2579,14 +2579,14 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
+ bdev = bdget(dev);
+ if (!bdev)
+ return -ENOMEM;
++ ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
++ if (ret)
++ return ret;
+ if (!blk_queue_scsi_passthrough(bdev_get_queue(bdev))) {
+ WARN_ONCE(true, "Attempt to register a non-SCSI queue\n");
+- bdput(bdev);
++ blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
+ return -EINVAL;
+ }
+- ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
+- if (ret)
+- return ret;
+
+ /* This is safe, since we have a reference from open(). */
+ __module_get(THIS_MODULE);
+@@ -2745,7 +2745,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
+ pd->pkt_dev = MKDEV(pktdev_major, idx);
+ ret = pkt_new_dev(pd, dev);
+ if (ret)
+- goto out_new_dev;
++ goto out_mem2;
+
+ /* inherit events of the host device */
+ disk->events = pd->bdev->bd_disk->events;
+@@ -2763,8 +2763,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
+ mutex_unlock(&ctl_mutex);
+ return 0;
+
+-out_new_dev:
+- blk_cleanup_queue(disk->queue);
+ out_mem2:
+ put_disk(disk);
+ out_mem:
+diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
+index c8e945d19ffe..20142bc77554 100644
+--- a/drivers/bluetooth/btsdio.c
++++ b/drivers/bluetooth/btsdio.c
+@@ -31,6 +31,7 @@
+ #include <linux/errno.h>
+ #include <linux/skbuff.h>
+
++#include <linux/mmc/host.h>
+ #include <linux/mmc/sdio_ids.h>
+ #include <linux/mmc/sdio_func.h>
+
+@@ -292,6 +293,14 @@ static int btsdio_probe(struct sdio_func *func,
+ tuple = tuple->next;
+ }
+
++ /* BCM43341 devices soldered onto the PCB (non-removable) use an
++ * uart connection for bluetooth, ignore the BT SDIO interface.
++ */
++ if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
++ func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
++ !mmc_card_is_removable(func->card->host))
++ return -ENODEV;
++
+ data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index 513a7a59d421..d54c3f6f728c 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -23,6 +23,7 @@
+
+ #include <linux/module.h>
+ #include <linux/usb.h>
++#include <linux/usb/quirks.h>
+ #include <linux/firmware.h>
+ #include <linux/of_device.h>
+ #include <linux/of_irq.h>
+@@ -392,9 +393,8 @@ static const struct usb_device_id blacklist_table[] = {
+ #define BTUSB_FIRMWARE_LOADED 7
+ #define BTUSB_FIRMWARE_FAILED 8
+ #define BTUSB_BOOTING 9
+-#define BTUSB_RESET_RESUME 10
+-#define BTUSB_DIAG_RUNNING 11
+-#define BTUSB_OOB_WAKE_ENABLED 12
++#define BTUSB_DIAG_RUNNING 10
++#define BTUSB_OOB_WAKE_ENABLED 11
+
+ struct btusb_data {
+ struct hci_dev *hdev;
+@@ -3102,9 +3102,9 @@ static int btusb_probe(struct usb_interface *intf,
+
+ /* QCA Rome devices lose their updated firmware over suspend,
+ * but the USB hub doesn't notice any status change.
+- * Explicitly request a device reset on resume.
++ * explicitly request a device reset on resume.
+ */
+- set_bit(BTUSB_RESET_RESUME, &data->flags);
++ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
+ }
+
+ #ifdef CONFIG_BT_HCIBTUSB_RTL
+@@ -3115,7 +3115,7 @@ static int btusb_probe(struct usb_interface *intf,
+ * but the USB hub doesn't notice any status change.
+ * Explicitly request a device reset on resume.
+ */
+- set_bit(BTUSB_RESET_RESUME, &data->flags);
++ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
+ }
+ #endif
+
+@@ -3280,14 +3280,6 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
+ enable_irq(data->oob_wake_irq);
+ }
+
+- /* Optionally request a device reset on resume, but only when
+- * wakeups are disabled. If wakeups are enabled we assume the
+- * device will stay powered up throughout suspend.
+- */
+- if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
+- !device_may_wakeup(&data->udev->dev))
+- data->udev->reset_resume = 1;
+-
+ return 0;
+ }
+
+diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c
+index 2059f79d669a..c3a23ec3e76f 100644
+--- a/drivers/char/ipmi/ipmi_dmi.c
++++ b/drivers/char/ipmi/ipmi_dmi.c
+@@ -81,7 +81,10 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
+ pr_err("ipmi:dmi: Error allocation IPMI platform device");
+ return;
+ }
+- pdev->driver_override = override;
++ pdev->driver_override = kasprintf(GFP_KERNEL, "%s",
++ override);
++ if (!pdev->driver_override)
++ goto err;
+
+ if (type == IPMI_DMI_TYPE_SSIF)
+ goto add_properties;
+diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
+index 8f2423789ba9..4bfeb9929ab2 100644
+--- a/drivers/clocksource/timer-stm32.c
++++ b/drivers/clocksource/timer-stm32.c
+@@ -106,6 +106,10 @@ static int __init stm32_clockevent_init(struct device_node *np)
+ unsigned long rate, max_delta;
+ int irq, ret, bits, prescaler = 1;
+
++ data = kmemdup(&clock_event_ddata, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+@@ -156,8 +160,8 @@ static int __init stm32_clockevent_init(struct device_node *np)
+
+ writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+ writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+- writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+ writel_relaxed(0, data->base + TIM_SR);
++ writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+
+ data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+@@ -184,6 +188,7 @@ static int __init stm32_clockevent_init(struct device_node *np)
+ err_clk_enable:
+ clk_put(clk);
+ err_clk_get:
++ kfree(data);
+ return ret;
+ }
+
+diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
+index a753c50e9e41..9e0aa767bbbe 100644
+--- a/drivers/cpufreq/cpufreq-dt-platdev.c
++++ b/drivers/cpufreq/cpufreq-dt-platdev.c
+@@ -111,6 +111,14 @@ static const struct of_device_id blacklist[] __initconst = {
+
+ { .compatible = "marvell,armadaxp", },
+
++ { .compatible = "mediatek,mt2701", },
++ { .compatible = "mediatek,mt2712", },
++ { .compatible = "mediatek,mt7622", },
++ { .compatible = "mediatek,mt7623", },
++ { .compatible = "mediatek,mt817x", },
++ { .compatible = "mediatek,mt8173", },
++ { .compatible = "mediatek,mt8176", },
++
+ { .compatible = "nvidia,tegra124", },
+
+ { .compatible = "st,stih407", },
+diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
+index a118b9bed669..bfbf8bf77f03 100644
+--- a/drivers/crypto/bfin_crc.c
++++ b/drivers/crypto/bfin_crc.c
+@@ -494,7 +494,8 @@ static struct ahash_alg algs = {
+ .cra_driver_name = DRIVER_NAME,
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+- CRYPTO_ALG_ASYNC,
++ CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx),
+ .cra_alignmask = 3,
+diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
+index 027e121c6f70..e1d4ae1153c4 100644
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -228,12 +228,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
+ * without any error (HW optimizations for later
+ * CAAM eras), then try again.
+ */
++ if (ret)
++ break;
++
+ rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+ if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
+- !(rdsta_val & (1 << sh_idx)))
++ !(rdsta_val & (1 << sh_idx))) {
+ ret = -EAGAIN;
+- if (ret)
+ break;
++ }
++
+ dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
+ /* Clear the contents before recreating the descriptor */
+ memset(desc, 0x00, CAAM_CMD_SZ * 7);
+diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32_crc32.c
+index 090582baecfe..8f09b8430893 100644
+--- a/drivers/crypto/stm32/stm32_crc32.c
++++ b/drivers/crypto/stm32/stm32_crc32.c
+@@ -208,6 +208,7 @@ static struct shash_alg algs[] = {
+ .cra_name = "crc32",
+ .cra_driver_name = DRIVER_NAME,
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_alignmask = 3,
+ .cra_ctxsize = sizeof(struct stm32_crc_ctx),
+@@ -229,6 +230,7 @@ static struct shash_alg algs[] = {
+ .cra_name = "crc32c",
+ .cra_driver_name = DRIVER_NAME,
+ .cra_priority = 200,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_alignmask = 3,
+ .cra_ctxsize = sizeof(struct stm32_crc_ctx),
+diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
+index ec5f9d2bc820..80cc2be6483c 100644
+--- a/drivers/dma/dmatest.c
++++ b/drivers/dma/dmatest.c
+@@ -355,7 +355,7 @@ static void dmatest_callback(void *arg)
+ {
+ struct dmatest_done *done = arg;
+ struct dmatest_thread *thread =
+- container_of(arg, struct dmatest_thread, done_wait);
++ container_of(done, struct dmatest_thread, test_done);
+ if (!thread->done) {
+ done->done = true;
+ wake_up_all(done->wait);
+diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
+index 9c1ffe3e912b..aeb222ca3ed1 100644
+--- a/drivers/edac/octeon_edac-lmc.c
++++ b/drivers/edac/octeon_edac-lmc.c
+@@ -78,6 +78,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
+ if (!pvt->inject)
+ int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+ else {
++ int_reg.u64 = 0;
+ if (pvt->error_type == 1)
+ int_reg.s.sec_err = 1;
+ if (pvt->error_type == 2)
+diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
+index d687ca3d5049..c80ec1d03274 100644
+--- a/drivers/firmware/psci.c
++++ b/drivers/firmware/psci.c
+@@ -59,7 +59,10 @@ bool psci_tos_resident_on(int cpu)
+ return cpu == resident_cpu;
+ }
+
+-struct psci_operations psci_ops;
++struct psci_operations psci_ops = {
++ .conduit = PSCI_CONDUIT_NONE,
++ .smccc_version = SMCCC_VERSION_1_0,
++};
+
+ typedef unsigned long (psci_fn)(unsigned long, unsigned long,
+ unsigned long, unsigned long);
+@@ -210,6 +213,22 @@ static unsigned long psci_migrate_info_up_cpu(void)
+ 0, 0, 0);
+ }
+
++static void set_conduit(enum psci_conduit conduit)
++{
++ switch (conduit) {
++ case PSCI_CONDUIT_HVC:
++ invoke_psci_fn = __invoke_psci_fn_hvc;
++ break;
++ case PSCI_CONDUIT_SMC:
++ invoke_psci_fn = __invoke_psci_fn_smc;
++ break;
++ default:
++ WARN(1, "Unexpected PSCI conduit %d\n", conduit);
++ }
++
++ psci_ops.conduit = conduit;
++}
++
+ static int get_set_conduit_method(struct device_node *np)
+ {
+ const char *method;
+@@ -222,9 +241,9 @@ static int get_set_conduit_method(struct device_node *np)
+ }
+
+ if (!strcmp("hvc", method)) {
+- invoke_psci_fn = __invoke_psci_fn_hvc;
++ set_conduit(PSCI_CONDUIT_HVC);
+ } else if (!strcmp("smc", method)) {
+- invoke_psci_fn = __invoke_psci_fn_smc;
++ set_conduit(PSCI_CONDUIT_SMC);
+ } else {
+ pr_warn("invalid \"method\" property: %s\n", method);
+ return -EINVAL;
+@@ -493,9 +512,36 @@ static void __init psci_init_migrate(void)
+ pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
+ }
+
++static void __init psci_init_smccc(void)
++{
++ u32 ver = ARM_SMCCC_VERSION_1_0;
++ int feature;
++
++ feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
++
++ if (feature != PSCI_RET_NOT_SUPPORTED) {
++ u32 ret;
++ ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
++ if (ret == ARM_SMCCC_VERSION_1_1) {
++ psci_ops.smccc_version = SMCCC_VERSION_1_1;
++ ver = ret;
++ }
++ }
++
++ /*
++ * Conveniently, the SMCCC and PSCI versions are encoded the
++ * same way. No, this isn't accidental.
++ */
++ pr_info("SMC Calling Convention v%d.%d\n",
++ PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
++
++}
++
+ static void __init psci_0_2_set_functions(void)
+ {
+ pr_info("Using standard PSCI v0.2 function IDs\n");
++ psci_ops.get_version = psci_get_version;
++
+ psci_function_id[PSCI_FN_CPU_SUSPEND] =
+ PSCI_FN_NATIVE(0_2, CPU_SUSPEND);
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+@@ -539,6 +585,7 @@ static int __init psci_probe(void)
+ psci_init_migrate();
+
+ if (PSCI_VERSION_MAJOR(ver) >= 1) {
++ psci_init_smccc();
+ psci_init_cpu_suspend();
+ psci_init_system_suspend();
+ }
+@@ -652,9 +699,9 @@ int __init psci_acpi_init(void)
+ pr_info("probing for conduit method from ACPI.\n");
+
+ if (acpi_psci_use_hvc())
+- invoke_psci_fn = __invoke_psci_fn_hvc;
++ set_conduit(PSCI_CONDUIT_HVC);
+ else
+- invoke_psci_fn = __invoke_psci_fn_smc;
++ set_conduit(PSCI_CONDUIT_SMC);
+
+ return psci_probe();
+ }
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 095a2240af4f..46485692db48 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -1211,23 +1211,6 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe)
+ pipe_name(pipe));
+ }
+
+-static void assert_cursor(struct drm_i915_private *dev_priv,
+- enum pipe pipe, bool state)
+-{
+- bool cur_state;
+-
+- if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
+- cur_state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
+- else
+- cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+-
+- I915_STATE_WARN(cur_state != state,
+- "cursor on pipe %c assertion failure (expected %s, current %s)\n",
+- pipe_name(pipe), onoff(state), onoff(cur_state));
+-}
+-#define assert_cursor_enabled(d, p) assert_cursor(d, p, true)
+-#define assert_cursor_disabled(d, p) assert_cursor(d, p, false)
+-
+ void assert_pipe(struct drm_i915_private *dev_priv,
+ enum pipe pipe, bool state)
+ {
+@@ -1255,77 +1238,25 @@ void assert_pipe(struct drm_i915_private *dev_priv,
+ pipe_name(pipe), onoff(state), onoff(cur_state));
+ }
+
+-static void assert_plane(struct drm_i915_private *dev_priv,
+- enum plane plane, bool state)
++static void assert_plane(struct intel_plane *plane, bool state)
+ {
+- u32 val;
+- bool cur_state;
++ bool cur_state = plane->get_hw_state(plane);
+
+- val = I915_READ(DSPCNTR(plane));
+- cur_state = !!(val & DISPLAY_PLANE_ENABLE);
+ I915_STATE_WARN(cur_state != state,
+- "plane %c assertion failure (expected %s, current %s)\n",
+- plane_name(plane), onoff(state), onoff(cur_state));
++ "%s assertion failure (expected %s, current %s)\n",
++ plane->base.name, onoff(state), onoff(cur_state));
+ }
+
+-#define assert_plane_enabled(d, p) assert_plane(d, p, true)
+-#define assert_plane_disabled(d, p) assert_plane(d, p, false)
++#define assert_plane_enabled(p) assert_plane(p, true)
++#define assert_plane_disabled(p) assert_plane(p, false)
+
+-static void assert_planes_disabled(struct drm_i915_private *dev_priv,
+- enum pipe pipe)
++static void assert_planes_disabled(struct intel_crtc *crtc)
+ {
+- int i;
+-
+- /* Primary planes are fixed to pipes on gen4+ */
+- if (INTEL_GEN(dev_priv) >= 4) {
+- u32 val = I915_READ(DSPCNTR(pipe));
+- I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE,
+- "plane %c assertion failure, should be disabled but not\n",
+- plane_name(pipe));
+- return;
+- }
+-
+- /* Need to check both planes against the pipe */
+- for_each_pipe(dev_priv, i) {
+- u32 val = I915_READ(DSPCNTR(i));
+- enum pipe cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
+- DISPPLANE_SEL_PIPE_SHIFT;
+- I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
+- "plane %c assertion failure, should be off on pipe %c but is still active\n",
+- plane_name(i), pipe_name(pipe));
+- }
+-}
+-
+-static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
+- enum pipe pipe)
+-{
+- int sprite;
++ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
++ struct intel_plane *plane;
+
+- if (INTEL_GEN(dev_priv) >= 9) {
+- for_each_sprite(dev_priv, pipe, sprite) {
+- u32 val = I915_READ(PLANE_CTL(pipe, sprite));
+- I915_STATE_WARN(val & PLANE_CTL_ENABLE,
+- "plane %d assertion failure, should be off on pipe %c but is still active\n",
+- sprite, pipe_name(pipe));
+- }
+- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+- for_each_sprite(dev_priv, pipe, sprite) {
+- u32 val = I915_READ(SPCNTR(pipe, PLANE_SPRITE0 + sprite));
+- I915_STATE_WARN(val & SP_ENABLE,
+- "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+- sprite_name(pipe, sprite), pipe_name(pipe));
+- }
+- } else if (INTEL_GEN(dev_priv) >= 7) {
+- u32 val = I915_READ(SPRCTL(pipe));
+- I915_STATE_WARN(val & SPRITE_ENABLE,
+- "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+- plane_name(pipe), pipe_name(pipe));
+- } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
+- u32 val = I915_READ(DVSCNTR(pipe));
+- I915_STATE_WARN(val & DVS_ENABLE,
+- "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+- plane_name(pipe), pipe_name(pipe));
+- }
++ for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane)
++ assert_plane_disabled(plane);
+ }
+
+ static void assert_vblank_disabled(struct drm_crtc *crtc)
+@@ -1926,9 +1857,7 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
+
+ DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe));
+
+- assert_planes_disabled(dev_priv, pipe);
+- assert_cursor_disabled(dev_priv, pipe);
+- assert_sprites_disabled(dev_priv, pipe);
++ assert_planes_disabled(crtc);
+
+ /*
+ * A pipe without a PLL won't actually be able to drive bits from
+@@ -1997,9 +1926,7 @@ static void intel_disable_pipe(struct intel_crtc *crtc)
+ * Make sure planes won't keep trying to pump pixels to us,
+ * or we might hang the display.
+ */
+- assert_planes_disabled(dev_priv, pipe);
+- assert_cursor_disabled(dev_priv, pipe);
+- assert_sprites_disabled(dev_priv, pipe);
++ assert_planes_disabled(crtc);
+
+ reg = PIPECONF(cpu_transcoder);
+ val = I915_READ(reg);
+@@ -2829,6 +2756,23 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state,
+ crtc_state->active_planes);
+ }
+
++static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
++ struct intel_plane *plane)
++{
++ struct intel_crtc_state *crtc_state =
++ to_intel_crtc_state(crtc->base.state);
++ struct intel_plane_state *plane_state =
++ to_intel_plane_state(plane->base.state);
++
++ intel_set_plane_visible(crtc_state, plane_state, false);
++
++ if (plane->id == PLANE_PRIMARY)
++ intel_pre_disable_primary_noatomic(&crtc->base);
++
++ trace_intel_disable_plane(&plane->base, crtc);
++ plane->disable_plane(plane, crtc);
++}
++
+ static void
+ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
+ struct intel_initial_plane_config *plane_config)
+@@ -2886,12 +2830,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
+ * simplest solution is to just disable the primary plane now and
+ * pretend the BIOS never had it enabled.
+ */
+- intel_set_plane_visible(to_intel_crtc_state(crtc_state),
+- to_intel_plane_state(plane_state),
+- false);
+- intel_pre_disable_primary_noatomic(&intel_crtc->base);
+- trace_intel_disable_plane(primary, intel_crtc);
+- intel_plane->disable_plane(intel_plane, intel_crtc);
++ intel_plane_disable_noatomic(intel_crtc, intel_plane);
+
+ return;
+
+@@ -3397,6 +3336,31 @@ static void i9xx_disable_primary_plane(struct intel_plane *primary,
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
++static bool i9xx_plane_get_hw_state(struct intel_plane *primary)
++{
++
++ struct drm_i915_private *dev_priv = to_i915(primary->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum plane plane = primary->plane;
++ enum pipe pipe = primary->pipe;
++ bool ret;
++
++ /*
++ * Not 100% correct for planes that can move between pipes,
++ * but that's only the case for gen2-4 which don't have any
++ * display power wells.
++ */
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static u32
+ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int plane)
+ {
+@@ -4973,7 +4937,8 @@ void hsw_enable_ips(struct intel_crtc *crtc)
+ * a vblank wait.
+ */
+
+- assert_plane_enabled(dev_priv, crtc->plane);
++ assert_plane_enabled(to_intel_plane(crtc->base.primary));
++
+ if (IS_BROADWELL(dev_priv)) {
+ mutex_lock(&dev_priv->rps.hw_lock);
+ WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0xc0000000));
+@@ -5005,7 +4970,8 @@ void hsw_disable_ips(struct intel_crtc *crtc)
+ if (!crtc->config->ips_enabled)
+ return;
+
+- assert_plane_enabled(dev_priv, crtc->plane);
++ assert_plane_enabled(to_intel_plane(crtc->base.primary));
++
+ if (IS_BROADWELL(dev_priv)) {
+ mutex_lock(&dev_priv->rps.hw_lock);
+ WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
+@@ -6000,6 +5966,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+ enum intel_display_power_domain domain;
++ struct intel_plane *plane;
+ u64 domains;
+ struct drm_atomic_state *state;
+ struct intel_crtc_state *crtc_state;
+@@ -6008,11 +5975,12 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
+ if (!intel_crtc->active)
+ return;
+
+- if (crtc->primary->state->visible) {
+- intel_pre_disable_primary_noatomic(crtc);
++ for_each_intel_plane_on_crtc(&dev_priv->drm, intel_crtc, plane) {
++ const struct intel_plane_state *plane_state =
++ to_intel_plane_state(plane->base.state);
+
+- intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
+- crtc->primary->state->visible = false;
++ if (plane_state->base.visible)
++ intel_plane_disable_noatomic(intel_crtc, plane);
+ }
+
+ state = drm_atomic_state_alloc(crtc->dev);
+@@ -9577,6 +9545,23 @@ static void i845_disable_cursor(struct intel_plane *plane,
+ i845_update_cursor(plane, NULL, NULL);
+ }
+
++static bool i845_cursor_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ bool ret;
++
++ power_domain = POWER_DOMAIN_PIPE(PIPE_A);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+ {
+@@ -9770,6 +9755,28 @@ static void i9xx_disable_cursor(struct intel_plane *plane,
+ i9xx_update_cursor(plane, NULL, NULL);
+ }
+
++static bool i9xx_cursor_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum pipe pipe = plane->pipe;
++ bool ret;
++
++ /*
++ * Not 100% correct for planes that can move between pipes,
++ * but that's only the case for gen2-3 which don't have any
++ * display power wells.
++ */
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
+
+ /* VESA 640x480x72Hz mode to set on the pipe */
+ static struct drm_display_mode load_detect_mode = {
+@@ -13240,6 +13247,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+
+ primary->update_plane = skylake_update_primary_plane;
+ primary->disable_plane = skylake_disable_primary_plane;
++ primary->get_hw_state = skl_plane_get_hw_state;
+ } else if (INTEL_GEN(dev_priv) >= 9) {
+ intel_primary_formats = skl_primary_formats;
+ num_formats = ARRAY_SIZE(skl_primary_formats);
+@@ -13250,6 +13258,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+
+ primary->update_plane = skylake_update_primary_plane;
+ primary->disable_plane = skylake_disable_primary_plane;
++ primary->get_hw_state = skl_plane_get_hw_state;
+ } else if (INTEL_GEN(dev_priv) >= 4) {
+ intel_primary_formats = i965_primary_formats;
+ num_formats = ARRAY_SIZE(i965_primary_formats);
+@@ -13257,6 +13266,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+
+ primary->update_plane = i9xx_update_primary_plane;
+ primary->disable_plane = i9xx_disable_primary_plane;
++ primary->get_hw_state = i9xx_plane_get_hw_state;
+ } else {
+ intel_primary_formats = i8xx_primary_formats;
+ num_formats = ARRAY_SIZE(i8xx_primary_formats);
+@@ -13264,6 +13274,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+
+ primary->update_plane = i9xx_update_primary_plane;
+ primary->disable_plane = i9xx_disable_primary_plane;
++ primary->get_hw_state = i9xx_plane_get_hw_state;
+ }
+
+ if (INTEL_GEN(dev_priv) >= 9)
+@@ -13353,10 +13364,12 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+ if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+ cursor->update_plane = i845_update_cursor;
+ cursor->disable_plane = i845_disable_cursor;
++ cursor->get_hw_state = i845_cursor_get_hw_state;
+ cursor->check_plane = i845_check_cursor;
+ } else {
+ cursor->update_plane = i9xx_update_cursor;
+ cursor->disable_plane = i9xx_disable_cursor;
++ cursor->get_hw_state = i9xx_cursor_get_hw_state;
+ cursor->check_plane = i9xx_check_cursor;
+ }
+
+@@ -14704,8 +14717,11 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
+ DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n",
+ pipe_name(pipe));
+
+- assert_plane_disabled(dev_priv, PLANE_A);
+- assert_plane_disabled(dev_priv, PLANE_B);
++ WARN_ON(I915_READ(DSPCNTR(PLANE_A)) & DISPLAY_PLANE_ENABLE);
++ WARN_ON(I915_READ(DSPCNTR(PLANE_B)) & DISPLAY_PLANE_ENABLE);
++ WARN_ON(I915_READ(DSPCNTR(PLANE_C)) & DISPLAY_PLANE_ENABLE);
++ WARN_ON(I915_READ(CURCNTR(PIPE_A)) & CURSOR_MODE);
++ WARN_ON(I915_READ(CURCNTR(PIPE_B)) & CURSOR_MODE);
+
+ I915_WRITE(PIPECONF(pipe), 0);
+ POSTING_READ(PIPECONF(pipe));
+@@ -14716,22 +14732,36 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
+ POSTING_READ(DPLL(pipe));
+ }
+
+-static bool
+-intel_check_plane_mapping(struct intel_crtc *crtc)
++static bool intel_plane_mapping_ok(struct intel_crtc *crtc,
++ struct intel_plane *primary)
+ {
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+- u32 val;
++ enum plane plane = primary->plane;
++ u32 val = I915_READ(DSPCNTR(plane));
+
+- if (INTEL_INFO(dev_priv)->num_pipes == 1)
+- return true;
++ return (val & DISPLAY_PLANE_ENABLE) == 0 ||
++ (val & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE(crtc->pipe);
++}
+
+- val = I915_READ(DSPCNTR(!crtc->plane));
++static void
++intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
++{
++ struct intel_crtc *crtc;
+
+- if ((val & DISPLAY_PLANE_ENABLE) &&
+- (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
+- return false;
++ if (INTEL_GEN(dev_priv) >= 4)
++ return;
+
+- return true;
++ for_each_intel_crtc(&dev_priv->drm, crtc) {
++ struct intel_plane *plane =
++ to_intel_plane(crtc->base.primary);
++
++ if (intel_plane_mapping_ok(crtc, plane))
++ continue;
++
++ DRM_DEBUG_KMS("%s attached to the wrong pipe, disabling plane\n",
++ plane->base.name);
++ intel_plane_disable_noatomic(crtc, plane);
++ }
+ }
+
+ static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
+@@ -14787,33 +14817,15 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
+
+ /* Disable everything but the primary plane */
+ for_each_intel_plane_on_crtc(dev, crtc, plane) {
+- if (plane->base.type == DRM_PLANE_TYPE_PRIMARY)
+- continue;
++ const struct intel_plane_state *plane_state =
++ to_intel_plane_state(plane->base.state);
+
+- trace_intel_disable_plane(&plane->base, crtc);
+- plane->disable_plane(plane, crtc);
++ if (plane_state->base.visible &&
++ plane->base.type != DRM_PLANE_TYPE_PRIMARY)
++ intel_plane_disable_noatomic(crtc, plane);
+ }
+ }
+
+- /* We need to sanitize the plane -> pipe mapping first because this will
+- * disable the crtc (and hence change the state) if it is wrong. Note
+- * that gen4+ has a fixed plane -> pipe mapping. */
+- if (INTEL_GEN(dev_priv) < 4 && !intel_check_plane_mapping(crtc)) {
+- bool plane;
+-
+- DRM_DEBUG_KMS("[CRTC:%d:%s] wrong plane connection detected!\n",
+- crtc->base.base.id, crtc->base.name);
+-
+- /* Pipe has the wrong plane attached and the plane is active.
+- * Temporarily change the plane mapping and disable everything
+- * ... */
+- plane = crtc->plane;
+- crtc->base.primary->state->visible = true;
+- crtc->plane = !plane;
+- intel_crtc_disable_noatomic(&crtc->base, ctx);
+- crtc->plane = plane;
+- }
+-
+ /* Adjust the state of the output pipe according to whether we
+ * have active connectors/encoders. */
+ if (crtc->active && !intel_crtc_has_encoders(crtc))
+@@ -14918,24 +14930,21 @@ void i915_redisable_vga(struct drm_i915_private *dev_priv)
+ intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
+ }
+
+-static bool primary_get_hw_state(struct intel_plane *plane)
+-{
+- struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+-
+- return I915_READ(DSPCNTR(plane->plane)) & DISPLAY_PLANE_ENABLE;
+-}
+-
+ /* FIXME read out full plane state for all planes */
+ static void readout_plane_state(struct intel_crtc *crtc)
+ {
+- struct intel_plane *primary = to_intel_plane(crtc->base.primary);
+- bool visible;
++ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
++ struct intel_crtc_state *crtc_state =
++ to_intel_crtc_state(crtc->base.state);
++ struct intel_plane *plane;
+
+- visible = crtc->active && primary_get_hw_state(primary);
++ for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
++ struct intel_plane_state *plane_state =
++ to_intel_plane_state(plane->base.state);
++ bool visible = plane->get_hw_state(plane);
+
+- intel_set_plane_visible(to_intel_crtc_state(crtc->base.state),
+- to_intel_plane_state(primary->base.state),
+- visible);
++ intel_set_plane_visible(crtc_state, plane_state, visible);
++ }
+ }
+
+ static void intel_modeset_readout_hw_state(struct drm_device *dev)
+@@ -15137,6 +15146,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
+ /* HW state is read out, now we need to sanitize this mess. */
+ get_encoder_power_domains(dev_priv);
+
++ intel_sanitize_plane_mapping(dev_priv);
++
+ for_each_intel_encoder(dev, encoder) {
+ intel_sanitize_encoder(encoder);
+ }
+diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
+index 09f274419eea..76cf68745870 100644
+--- a/drivers/gpu/drm/i915/intel_dp.c
++++ b/drivers/gpu/drm/i915/intel_dp.c
+@@ -5340,6 +5340,12 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
+ */
+ final->t8 = 1;
+ final->t9 = 1;
++
++ /*
++ * HW has only a 100msec granularity for t11_t12 so round it up
++ * accordingly.
++ */
++ final->t11_t12 = roundup(final->t11_t12, 100 * 10);
+ }
+
+ static void
+diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
+index 79fbaf78f604..10ae9681f02d 100644
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -863,6 +863,7 @@ struct intel_plane {
+ const struct intel_plane_state *plane_state);
+ void (*disable_plane)(struct intel_plane *plane,
+ struct intel_crtc *crtc);
++ bool (*get_hw_state)(struct intel_plane *plane);
+ int (*check_plane)(struct intel_plane *plane,
+ struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *state);
+@@ -1885,6 +1886,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+ void intel_pipe_update_start(struct intel_crtc *crtc);
+ void intel_pipe_update_end(struct intel_crtc *crtc);
++bool skl_plane_get_hw_state(struct intel_plane *plane);
+
+ /* intel_tv.c */
+ void intel_tv_init(struct drm_i915_private *dev_priv);
+diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
+index 524933b01483..f8ebeb5ffb96 100644
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -324,6 +324,26 @@ skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
++bool
++skl_plane_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum plane_id plane_id = plane->id;
++ enum pipe pipe = plane->pipe;
++ bool ret;
++
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(PLANE_CTL(pipe, plane_id)) & PLANE_CTL_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static void
+ chv_update_csc(struct intel_plane *plane, uint32_t format)
+ {
+@@ -501,6 +521,26 @@ vlv_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
++static bool
++vlv_plane_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum plane_id plane_id = plane->id;
++ enum pipe pipe = plane->pipe;
++ bool ret;
++
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(SPCNTR(pipe, plane_id)) & SP_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+ {
+@@ -641,6 +681,25 @@ ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
++static bool
++ivb_plane_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum pipe pipe = plane->pipe;
++ bool ret;
++
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(SPRCTL(pipe)) & SPRITE_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
+ const struct intel_plane_state *plane_state)
+ {
+@@ -772,6 +831,25 @@ g4x_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc)
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ }
+
++static bool
++g4x_plane_get_hw_state(struct intel_plane *plane)
++{
++ struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
++ enum intel_display_power_domain power_domain;
++ enum pipe pipe = plane->pipe;
++ bool ret;
++
++ power_domain = POWER_DOMAIN_PIPE(pipe);
++ if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
++ return false;
++
++ ret = I915_READ(DVSCNTR(pipe)) & DVS_ENABLE;
++
++ intel_display_power_put(dev_priv, power_domain);
++
++ return ret;
++}
++
+ static int
+ intel_check_sprite_plane(struct intel_plane *plane,
+ struct intel_crtc_state *crtc_state,
+@@ -1227,6 +1305,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+
+ intel_plane->update_plane = skl_update_plane;
+ intel_plane->disable_plane = skl_disable_plane;
++ intel_plane->get_hw_state = skl_plane_get_hw_state;
+
+ plane_formats = skl_plane_formats;
+ num_plane_formats = ARRAY_SIZE(skl_plane_formats);
+@@ -1237,6 +1316,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+
+ intel_plane->update_plane = skl_update_plane;
+ intel_plane->disable_plane = skl_disable_plane;
++ intel_plane->get_hw_state = skl_plane_get_hw_state;
+
+ plane_formats = skl_plane_formats;
+ num_plane_formats = ARRAY_SIZE(skl_plane_formats);
+@@ -1247,6 +1327,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+
+ intel_plane->update_plane = vlv_update_plane;
+ intel_plane->disable_plane = vlv_disable_plane;
++ intel_plane->get_hw_state = vlv_plane_get_hw_state;
+
+ plane_formats = vlv_plane_formats;
+ num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
+@@ -1262,6 +1343,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+
+ intel_plane->update_plane = ivb_update_plane;
+ intel_plane->disable_plane = ivb_disable_plane;
++ intel_plane->get_hw_state = ivb_plane_get_hw_state;
+
+ plane_formats = snb_plane_formats;
+ num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+@@ -1272,6 +1354,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
+
+ intel_plane->update_plane = g4x_update_plane;
+ intel_plane->disable_plane = g4x_disable_plane;
++ intel_plane->get_hw_state = g4x_plane_get_hw_state;
+
+ modifiers = i9xx_plane_format_modifiers;
+ if (IS_GEN6(dev_priv)) {
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index 330ca983828b..5744eb729d24 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2638,7 +2638,6 @@ static const struct hid_device_id hid_ignore_list[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
+- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
+@@ -2908,6 +2907,17 @@ bool hid_ignore(struct hid_device *hdev)
+ strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
+ return true;
+ break;
++ case USB_VENDOR_ID_ELAN:
++ /*
++ * Many Elan devices have a product id of 0x0401 and are handled
++ * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
++ * is not (and cannot be) handled by that driver ->
++ * Ignore all 0x0401 devs except for the ELAN0800 dev.
++ */
++ if (hdev->product == 0x0401 &&
++ strncmp(hdev->name, "ELAN0800", 8) != 0)
++ return true;
++ break;
+ }
+
+ if (hdev->type == HID_TYPE_USBMOUSE &&
+diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c
+index 0ee0df53b91b..79d5d89bc95e 100644
+--- a/drivers/media/dvb-frontends/ascot2e.c
++++ b/drivers/media/dvb-frontends/ascot2e.c
+@@ -155,7 +155,9 @@ static int ascot2e_write_regs(struct ascot2e_priv *priv,
+
+ static int ascot2e_write_reg(struct ascot2e_priv *priv, u8 reg, u8 val)
+ {
+- return ascot2e_write_regs(priv, reg, &val, 1);
++ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return ascot2e_write_regs(priv, reg, &tmp, 1);
+ }
+
+ static int ascot2e_read_regs(struct ascot2e_priv *priv,
+diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
+index 48ee9bc00c06..ccbd84fd6428 100644
+--- a/drivers/media/dvb-frontends/cxd2841er.c
++++ b/drivers/media/dvb-frontends/cxd2841er.c
+@@ -257,7 +257,9 @@ static int cxd2841er_write_regs(struct cxd2841er_priv *priv,
+ static int cxd2841er_write_reg(struct cxd2841er_priv *priv,
+ u8 addr, u8 reg, u8 val)
+ {
+- return cxd2841er_write_regs(priv, addr, reg, &val, 1);
++ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return cxd2841er_write_regs(priv, addr, reg, &tmp, 1);
+ }
+
+ static int cxd2841er_read_regs(struct cxd2841er_priv *priv,
+diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c
+index 4bf5a551ba40..2ab8d83e5576 100644
+--- a/drivers/media/dvb-frontends/helene.c
++++ b/drivers/media/dvb-frontends/helene.c
+@@ -331,7 +331,9 @@ static int helene_write_regs(struct helene_priv *priv,
+
+ static int helene_write_reg(struct helene_priv *priv, u8 reg, u8 val)
+ {
+- return helene_write_regs(priv, reg, &val, 1);
++ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return helene_write_regs(priv, reg, &tmp, 1);
+ }
+
+ static int helene_read_regs(struct helene_priv *priv,
+diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c
+index 68d759c4c52e..5c8b405f2ddc 100644
+--- a/drivers/media/dvb-frontends/horus3a.c
++++ b/drivers/media/dvb-frontends/horus3a.c
+@@ -89,7 +89,9 @@ static int horus3a_write_regs(struct horus3a_priv *priv,
+
+ static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
+ {
+- return horus3a_write_regs(priv, reg, &val, 1);
++ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return horus3a_write_regs(priv, reg, &tmp, 1);
+ }
+
+ static int horus3a_enter_power_save(struct horus3a_priv *priv)
+diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c
+index 5bb1e73a10b4..ce7c443d3eac 100644
+--- a/drivers/media/dvb-frontends/itd1000.c
++++ b/drivers/media/dvb-frontends/itd1000.c
+@@ -95,8 +95,9 @@ static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
+
+ static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
+ {
+- int ret = itd1000_write_regs(state, r, &v, 1);
+- state->shadow[r] = v;
++ u8 tmp = v; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++ int ret = itd1000_write_regs(state, r, &tmp, 1);
++ state->shadow[r] = tmp;
+ return ret;
+ }
+
+diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
+index 961b9a2508e0..0b23cbc021b8 100644
+--- a/drivers/media/dvb-frontends/mt312.c
++++ b/drivers/media/dvb-frontends/mt312.c
+@@ -142,7 +142,10 @@ static inline int mt312_readreg(struct mt312_state *state,
+ static inline int mt312_writereg(struct mt312_state *state,
+ const enum mt312_reg_addr reg, const u8 val)
+ {
+- return mt312_write(state, reg, &val, 1);
++ u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++
++ return mt312_write(state, reg, &tmp, 1);
+ }
+
+ static inline u32 mt312_div(u32 a, u32 b)
+diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
+index 02347598277a..db5dde3215f0 100644
+--- a/drivers/media/dvb-frontends/stb0899_drv.c
++++ b/drivers/media/dvb-frontends/stb0899_drv.c
+@@ -539,7 +539,8 @@ int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data,
+
+ int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
+ {
+- return stb0899_write_regs(state, reg, &data, 1);
++ u8 tmp = data;
++ return stb0899_write_regs(state, reg, &tmp, 1);
+ }
+
+ /*
+diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
+index 17a955d0031b..75509bec66e4 100644
+--- a/drivers/media/dvb-frontends/stb6100.c
++++ b/drivers/media/dvb-frontends/stb6100.c
+@@ -226,12 +226,14 @@ static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int st
+
+ static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
+ {
++ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
+ if (unlikely(reg >= STB6100_NUMREGS)) {
+ dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
+ return -EREMOTEIO;
+ }
+- data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
+- return stb6100_write_reg_range(state, &data, reg, 1);
++ tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set;
++ return stb6100_write_reg_range(state, &tmp, reg, 1);
+ }
+
+
+diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
+index f3529df8211d..1a726196c126 100644
+--- a/drivers/media/dvb-frontends/stv0367.c
++++ b/drivers/media/dvb-frontends/stv0367.c
+@@ -166,7 +166,9 @@ int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len)
+
+ static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
+ {
+- return stv0367_writeregs(state, reg, &data, 1);
++ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return stv0367_writeregs(state, reg, &tmp, 1);
+ }
+
+ static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
+diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
+index 7ef469c0c866..2695e1eb6d9c 100644
+--- a/drivers/media/dvb-frontends/stv090x.c
++++ b/drivers/media/dvb-frontends/stv090x.c
+@@ -755,7 +755,9 @@ static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8
+
+ static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
+ {
+- return stv090x_write_regs(state, reg, &data, 1);
++ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return stv090x_write_regs(state, reg, &tmp, 1);
+ }
+
+ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
+diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
+index 66eba38f1014..7e8e01389c55 100644
+--- a/drivers/media/dvb-frontends/stv6110x.c
++++ b/drivers/media/dvb-frontends/stv6110x.c
+@@ -97,7 +97,9 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da
+
+ static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+ {
+- return stv6110x_write_regs(stv6110x, reg, &data, 1);
++ u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return stv6110x_write_regs(stv6110x, reg, &tmp, 1);
+ }
+
+ static int stv6110x_init(struct dvb_frontend *fe)
+diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
+index 931e5c98da8a..b879e1571469 100644
+--- a/drivers/media/dvb-frontends/ts2020.c
++++ b/drivers/media/dvb-frontends/ts2020.c
+@@ -368,7 +368,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
+ gain2 = clamp_t(long, gain2, 0, 13);
+ v_agc = clamp_t(long, v_agc, 400, 1100);
+
+- *_gain = -(gain1 * 2330 +
++ *_gain = -((__s64)gain1 * 2330 +
+ gain2 * 3500 +
+ v_agc * 24 / 10 * 10 +
+ 10000);
+@@ -386,7 +386,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
+ gain3 = clamp_t(long, gain3, 0, 6);
+ v_agc = clamp_t(long, v_agc, 600, 1600);
+
+- *_gain = -(gain1 * 2650 +
++ *_gain = -((__s64)gain1 * 2650 +
+ gain2 * 3380 +
+ gain3 * 2850 +
+ v_agc * 176 / 100 * 10 -
+diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
+index 623355fc2666..3208b866d1cb 100644
+--- a/drivers/media/dvb-frontends/zl10039.c
++++ b/drivers/media/dvb-frontends/zl10039.c
+@@ -134,7 +134,9 @@ static inline int zl10039_writereg(struct zl10039_state *state,
+ const enum zl10039_reg_addr reg,
+ const u8 val)
+ {
+- return zl10039_write(state, reg, &val, 1);
++ const u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
++
++ return zl10039_write(state, reg, &tmp, 1);
+ }
+
+ static int zl10039_init(struct dvb_frontend *fe)
+diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
+index 5e320fa4a795..be26c029546b 100644
+--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
++++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
+@@ -494,18 +494,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+
+ static int lme2510_return_status(struct dvb_usb_device *d)
+ {
+- int ret = 0;
++ int ret;
+ u8 *data;
+
+- data = kzalloc(10, GFP_KERNEL);
++ data = kzalloc(6, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+- ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+- 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+- info("Firmware Status: %x (%x)", ret , data[2]);
++ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
++ 0x06, 0x80, 0x0302, 0x00,
++ data, 0x6, 200);
++ if (ret != 6)
++ ret = -EINVAL;
++ else
++ ret = data[2];
++
++ info("Firmware Status: %6ph", data);
+
+- ret = (ret < 0) ? -ENODEV : data[2];
+ kfree(data);
+ return ret;
+ }
+@@ -1071,8 +1076,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+
+ if (adap->fe[0]) {
+ info("FE Found M88RS2000");
+- dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
+- &d->i2c_adap);
+ st->i2c_tuner_gate_w = 5;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0x60;
+@@ -1138,17 +1141,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
+ ret = st->tuner_config;
+ break;
+ case TUNER_RS2000:
+- ret = st->tuner_config;
++ if (dvb_attach(ts2020_attach, adap->fe[0],
++ &ts2020_config, &d->i2c_adap))
++ ret = st->tuner_config;
+ break;
+ default:
+ break;
+ }
+
+- if (ret)
++ if (ret) {
+ info("TUN Found %s tuner", tun_msg[ret]);
+- else {
+- info("TUN No tuner found --- resetting device");
+- lme_coldreset(d);
++ } else {
++ info("TUN No tuner found");
+ return -ENODEV;
+ }
+
+@@ -1189,6 +1193,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d)
+ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
+ {
+ struct lme2510_state *st = d->priv;
++ int status;
+
+ usb_reset_configuration(d->udev);
+
+@@ -1197,12 +1202,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
+
+ st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
+
+- if (lme2510_return_status(d) == 0x44) {
++ status = lme2510_return_status(d);
++ if (status == 0x44) {
+ *name = lme_firmware_switch(d, 0);
+ return COLD;
+ }
+
+- return 0;
++ if (status != 0x47)
++ return -EINVAL;
++
++ return WARM;
+ }
+
+ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
+index 37dea0adc695..cfe86b4864b3 100644
+--- a/drivers/media/usb/dvb-usb/cxusb.c
++++ b/drivers/media/usb/dvb-usb/cxusb.c
+@@ -677,6 +677,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component,
+ case XC2028_RESET_CLK:
+ deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
+ break;
++ case XC2028_I2C_FLUSH:
++ break;
+ default:
+ deb_info("%s: unknown command %d, arg %d\n", __func__,
+ command, arg);
+diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
+index 92098c1b78e5..9be1e658ef47 100644
+--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
++++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
+@@ -430,6 +430,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
+ state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ break;
+ case XC2028_RESET_CLK:
++ case XC2028_I2C_FLUSH:
+ break;
+ default:
+ err("%s: unknown command %d, arg %d\n", __func__,
+diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
+index dbe29c6c4d8b..1e8cbaf36896 100644
+--- a/drivers/media/usb/hdpvr/hdpvr-core.c
++++ b/drivers/media/usb/hdpvr/hdpvr-core.c
+@@ -292,7 +292,7 @@ static int hdpvr_probe(struct usb_interface *interface,
+ /* register v4l2_device early so it can be used for printks */
+ if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
+ dev_err(&interface->dev, "v4l2_device_register failed\n");
+- goto error;
++ goto error_free_dev;
+ }
+
+ mutex_init(&dev->io_mutex);
+@@ -301,7 +301,7 @@ static int hdpvr_probe(struct usb_interface *interface,
+ dev->usbc_buf = kmalloc(64, GFP_KERNEL);
+ if (!dev->usbc_buf) {
+ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
+- goto error;
++ goto error_v4l2_unregister;
+ }
+
+ init_waitqueue_head(&dev->wait_buffer);
+@@ -339,13 +339,13 @@ static int hdpvr_probe(struct usb_interface *interface,
+ }
+ if (!dev->bulk_in_endpointAddr) {
+ v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
+- goto error;
++ goto error_put_usb;
+ }
+
+ /* init the device */
+ if (hdpvr_device_init(dev)) {
+ v4l2_err(&dev->v4l2_dev, "device init failed\n");
+- goto error;
++ goto error_put_usb;
+ }
+
+ mutex_lock(&dev->io_mutex);
+@@ -353,7 +353,7 @@ static int hdpvr_probe(struct usb_interface *interface,
+ mutex_unlock(&dev->io_mutex);
+ v4l2_err(&dev->v4l2_dev,
+ "allocating transfer buffers failed\n");
+- goto error;
++ goto error_put_usb;
+ }
+ mutex_unlock(&dev->io_mutex);
+
+@@ -361,7 +361,7 @@ static int hdpvr_probe(struct usb_interface *interface,
+ retval = hdpvr_register_i2c_adapter(dev);
+ if (retval < 0) {
+ v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
+- goto error;
++ goto error_free_buffers;
+ }
+
+ client = hdpvr_register_ir_rx_i2c(dev);
+@@ -394,13 +394,17 @@ static int hdpvr_probe(struct usb_interface *interface,
+ reg_fail:
+ #if IS_ENABLED(CONFIG_I2C)
+ i2c_del_adapter(&dev->i2c_adapter);
++error_free_buffers:
+ #endif
++ hdpvr_free_buffers(dev);
++error_put_usb:
++ usb_put_dev(dev->udev);
++ kfree(dev->usbc_buf);
++error_v4l2_unregister:
++ v4l2_device_unregister(&dev->v4l2_dev);
++error_free_dev:
++ kfree(dev);
+ error:
+- if (dev) {
+- flush_work(&dev->worker);
+- /* this frees allocated memory */
+- hdpvr_delete(dev);
+- }
+ return retval;
+ }
+
+diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+index 821f2aa299ae..cbeea8343a5c 100644
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -18,8 +18,18 @@
+ #include <linux/videodev2.h>
+ #include <linux/v4l2-subdev.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-ioctl.h>
+
++/* Use the same argument order as copy_in_user */
++#define assign_in_user(to, from) \
++({ \
++ typeof(*from) __assign_tmp; \
++ \
++ get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \
++})
++
+ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ long ret = -ENOIOCTLCMD;
+@@ -46,135 +56,75 @@ struct v4l2_window32 {
+ __u8 global_alpha;
+ };
+
+-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+-{
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
+- copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+- get_user(kp->field, &up->field) ||
+- get_user(kp->chromakey, &up->chromakey) ||
+- get_user(kp->clipcount, &up->clipcount) ||
+- get_user(kp->global_alpha, &up->global_alpha))
+- return -EFAULT;
+- if (kp->clipcount > 2048)
+- return -EINVAL;
+- if (kp->clipcount) {
+- struct v4l2_clip32 __user *uclips;
+- struct v4l2_clip __user *kclips;
+- int n = kp->clipcount;
+- compat_caddr_t p;
+-
+- if (get_user(p, &up->clips))
+- return -EFAULT;
+- uclips = compat_ptr(p);
+- kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
+- kp->clips = kclips;
+- while (--n >= 0) {
+- if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+- return -EFAULT;
+- if (put_user(n ? kclips + 1 : NULL, &kclips->next))
+- return -EFAULT;
+- uclips += 1;
+- kclips += 1;
+- }
+- } else
+- kp->clips = NULL;
+- return 0;
+-}
+-
+-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+-{
+- if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+- put_user(kp->field, &up->field) ||
+- put_user(kp->chromakey, &up->chromakey) ||
+- put_user(kp->clipcount, &up->clipcount) ||
+- put_user(kp->global_alpha, &up->global_alpha))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+- struct v4l2_pix_format_mplane __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
++static int get_v4l2_window32(struct v4l2_window __user *kp,
++ struct v4l2_window32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+- struct v4l2_pix_format_mplane __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
++ struct v4l2_clip32 __user *uclips;
++ struct v4l2_clip __user *kclips;
++ compat_caddr_t p;
++ u32 clipcount;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
++ assign_in_user(&kp->field, &up->field) ||
++ assign_in_user(&kp->chromakey, &up->chromakey) ||
++ assign_in_user(&kp->global_alpha, &up->global_alpha) ||
++ get_user(clipcount, &up->clipcount) ||
++ put_user(clipcount, &kp->clipcount))
+ return -EFAULT;
+- return 0;
+-}
++ if (clipcount > 2048)
++ return -EINVAL;
++ if (!clipcount)
++ return put_user(NULL, &kp->clips);
+
+-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
++ if (get_user(p, &up->clips))
+ return -EFAULT;
+- return 0;
+-}
+-
+-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
++ uclips = compat_ptr(p);
++ if (aux_space < clipcount * sizeof(*kclips))
+ return -EFAULT;
+- return 0;
+-}
+-
+-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+- if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
++ kclips = aux_buf;
++ if (put_user(kclips, &kp->clips))
+ return -EFAULT;
+- return 0;
+-}
+
+-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+- return -EFAULT;
++ while (clipcount--) {
++ if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
++ return -EFAULT;
++ if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
++ return -EFAULT;
++ uclips++;
++ kclips++;
++ }
+ return 0;
+ }
+
+-static inline int get_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up)
++static int put_v4l2_window32(struct v4l2_window __user *kp,
++ struct v4l2_window32 __user *up)
+ {
+- if (copy_from_user(kp, up, sizeof(struct v4l2_meta_format)))
++ struct v4l2_clip __user *kclips = kp->clips;
++ struct v4l2_clip32 __user *uclips;
++ compat_caddr_t p;
++ u32 clipcount;
++
++ if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
++ assign_in_user(&up->field, &kp->field) ||
++ assign_in_user(&up->chromakey, &kp->chromakey) ||
++ assign_in_user(&up->global_alpha, &kp->global_alpha) ||
++ get_user(clipcount, &kp->clipcount) ||
++ put_user(clipcount, &up->clipcount))
+ return -EFAULT;
+- return 0;
+-}
++ if (!clipcount)
++ return 0;
+
+-static inline int put_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up)
+-{
+- if (copy_to_user(up, kp, sizeof(struct v4l2_meta_format)))
++ if (get_user(p, &up->clips))
+ return -EFAULT;
++ uclips = compat_ptr(p);
++ while (clipcount--) {
++ if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
++ return -EFAULT;
++ uclips++;
++ kclips++;
++ }
+ return 0;
+ }
+
+@@ -209,101 +159,164 @@ struct v4l2_create_buffers32 {
+ __u32 reserved[8];
+ };
+
+-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+ {
+- if (get_user(kp->type, &up->type))
++ u32 type;
++
++ if (get_user(type, &up->type))
+ return -EFAULT;
+
+- switch (kp->type) {
++ switch (type) {
++ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
++ u32 clipcount;
++
++ if (get_user(clipcount, &up->fmt.win.clipcount))
++ return -EFAULT;
++ if (clipcount > 2048)
++ return -EINVAL;
++ *size = clipcount * sizeof(struct v4l2_clip);
++ return 0;
++ }
++ default:
++ *size = 0;
++ return 0;
++ }
++}
++
++static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
++{
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
++ return -EFAULT;
++ return __bufsize_v4l2_format(up, size);
++}
++
++static int __get_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up,
++ void __user *aux_buf, u32 aux_space)
++{
++ u32 type;
++
++ if (get_user(type, &up->type) || put_user(type, &kp->type))
++ return -EFAULT;
++
++ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++ return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+- &up->fmt.pix_mp);
++ return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+- return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
++ return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
++ aux_buf, aux_space);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++ return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++ return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++ return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
++ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
++ return copy_in_user(&kp->fmt.meta, &up->fmt.meta,
++ sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+ default:
+- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+- kp->type);
+ return -EINVAL;
+ }
+ }
+
+-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int get_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up,
++ void __user *aux_buf, u32 aux_space)
++{
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
++ return -EFAULT;
++ return __get_v4l2_format32(kp, up, aux_buf, aux_space);
++}
++
++static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
++ u32 *size)
+ {
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+ return -EFAULT;
+- return __get_v4l2_format32(kp, up);
++ return __bufsize_v4l2_format(&up->format, size);
+ }
+
+-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
++ struct v4l2_create_buffers32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
+- copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ copy_in_user(kp, up,
++ offsetof(struct v4l2_create_buffers32, format)))
+ return -EFAULT;
+- return __get_v4l2_format32(&kp->format, &up->format);
++ return __get_v4l2_format32(&kp->format, &up->format,
++ aux_buf, aux_space);
+ }
+
+-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __put_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up)
+ {
+- if (put_user(kp->type, &up->type))
++ u32 type;
++
++ if (get_user(type, &kp->type))
+ return -EFAULT;
+
+- switch (kp->type) {
++ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++ return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
++ sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+- &up->fmt.pix_mp);
++ return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
++ sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++ return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
++ sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++ return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
++ sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++ return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
++ sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta);
++ return copy_in_user(&up->fmt.meta, &kp->fmt.meta,
++ sizeof(kp->fmt.meta)) ? -EFAULT : 0;
+ default:
+- pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+- kp->type);
+ return -EINVAL;
+ }
+ }
+
+-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int put_v4l2_format32(struct v4l2_format __user *kp,
++ struct v4l2_format32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+ return -EFAULT;
+ return __put_v4l2_format32(kp, up);
+ }
+
+-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
++ struct v4l2_create_buffers32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
+- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ copy_in_user(up, kp,
++ offsetof(struct v4l2_create_buffers32, format)) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+ return -EFAULT;
+ return __put_v4l2_format32(&kp->format, &up->format);
+ }
+@@ -317,25 +330,28 @@ struct v4l2_standard32 {
+ __u32 reserved[4];
+ };
+
+-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int get_v4l2_standard32(struct v4l2_standard __user *kp,
++ struct v4l2_standard32 __user *up)
+ {
+ /* other fields are not set by the user, nor used by the driver */
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
+- get_user(kp->index, &up->index))
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ assign_in_user(&kp->index, &up->index))
+ return -EFAULT;
+ return 0;
+ }
+
+-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int put_v4l2_standard32(struct v4l2_standard __user *kp,
++ struct v4l2_standard32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
+- put_user(kp->index, &up->index) ||
+- put_user(kp->id, &up->id) ||
+- copy_to_user(up->name, kp->name, 24) ||
+- copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+- put_user(kp->framelines, &up->framelines) ||
+- copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
+- return -EFAULT;
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ assign_in_user(&up->index, &kp->index) ||
++ assign_in_user(&up->id, &kp->id) ||
++ copy_in_user(up->name, kp->name, sizeof(up->name)) ||
++ copy_in_user(&up->frameperiod, &kp->frameperiod,
++ sizeof(up->frameperiod)) ||
++ assign_in_user(&up->framelines, &kp->framelines) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++ return -EFAULT;
+ return 0;
+ }
+
+@@ -374,136 +390,186 @@ struct v4l2_buffer32 {
+ __u32 reserved;
+ };
+
+-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+- enum v4l2_memory memory)
++static int get_v4l2_plane32(struct v4l2_plane __user *up,
++ struct v4l2_plane32 __user *up32,
++ enum v4l2_memory memory)
+ {
+- void __user *up_pln;
+- compat_long_t p;
++ compat_ulong_t p;
+
+ if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+- copy_in_user(&up->data_offset, &up32->data_offset,
+- sizeof(__u32)))
++ copy_in_user(&up->data_offset, &up32->data_offset,
++ sizeof(up->data_offset)))
+ return -EFAULT;
+
+- if (memory == V4L2_MEMORY_USERPTR) {
+- if (get_user(p, &up32->m.userptr))
+- return -EFAULT;
+- up_pln = compat_ptr(p);
+- if (put_user((unsigned long)up_pln, &up->m.userptr))
++ switch (memory) {
++ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
++ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
++ sizeof(up32->m.mem_offset)))
+ return -EFAULT;
+- } else if (memory == V4L2_MEMORY_DMABUF) {
+- if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
++ break;
++ case V4L2_MEMORY_USERPTR:
++ if (get_user(p, &up32->m.userptr) ||
++ put_user((unsigned long)compat_ptr(p), &up->m.userptr))
+ return -EFAULT;
+- } else {
+- if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+- sizeof(__u32)))
++ break;
++ case V4L2_MEMORY_DMABUF:
++ if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+ return -EFAULT;
++ break;
+ }
+
+ return 0;
+ }
+
+-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+- enum v4l2_memory memory)
++static int put_v4l2_plane32(struct v4l2_plane __user *up,
++ struct v4l2_plane32 __user *up32,
++ enum v4l2_memory memory)
+ {
++ unsigned long p;
++
+ if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+- copy_in_user(&up32->data_offset, &up->data_offset,
+- sizeof(__u32)))
++ copy_in_user(&up32->data_offset, &up->data_offset,
++ sizeof(up->data_offset)))
+ return -EFAULT;
+
+- /* For MMAP, driver might've set up the offset, so copy it back.
+- * USERPTR stays the same (was userspace-provided), so no copying. */
+- if (memory == V4L2_MEMORY_MMAP)
++ switch (memory) {
++ case V4L2_MEMORY_MMAP:
++ case V4L2_MEMORY_OVERLAY:
+ if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+- sizeof(__u32)))
++ sizeof(up->m.mem_offset)))
++ return -EFAULT;
++ break;
++ case V4L2_MEMORY_USERPTR:
++ if (get_user(p, &up->m.userptr) ||
++ put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
++ &up32->m.userptr))
+ return -EFAULT;
+- /* For DMABUF, driver might've set up the fd, so copy it back. */
+- if (memory == V4L2_MEMORY_DMABUF)
+- if (copy_in_user(&up32->m.fd, &up->m.fd,
+- sizeof(int)))
++ break;
++ case V4L2_MEMORY_DMABUF:
++ if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+ return -EFAULT;
++ break;
++ }
++
++ return 0;
++}
++
++static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
++{
++ u32 type;
++ u32 length;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ get_user(type, &up->type) ||
++ get_user(length, &up->length))
++ return -EFAULT;
+
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ if (length > VIDEO_MAX_PLANES)
++ return -EINVAL;
++
++ /*
++ * We don't really care if userspace decides to kill itself
++ * by passing a very big length value
++ */
++ *size = length * sizeof(struct v4l2_plane);
++ } else {
++ *size = 0;
++ }
+ return 0;
+ }
+
+-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
++ struct v4l2_buffer32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
++ u32 type;
++ u32 length;
++ enum v4l2_memory memory;
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+ int ret;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
+- get_user(kp->index, &up->index) ||
+- get_user(kp->type, &up->type) ||
+- get_user(kp->flags, &up->flags) ||
+- get_user(kp->memory, &up->memory) ||
+- get_user(kp->length, &up->length))
+- return -EFAULT;
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ assign_in_user(&kp->index, &up->index) ||
++ get_user(type, &up->type) ||
++ put_user(type, &kp->type) ||
++ assign_in_user(&kp->flags, &up->flags) ||
++ get_user(memory, &up->memory) ||
++ put_user(memory, &kp->memory) ||
++ get_user(length, &up->length) ||
++ put_user(length, &kp->length))
++ return -EFAULT;
+
+- if (V4L2_TYPE_IS_OUTPUT(kp->type))
+- if (get_user(kp->bytesused, &up->bytesused) ||
+- get_user(kp->field, &up->field) ||
+- get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- get_user(kp->timestamp.tv_usec,
+- &up->timestamp.tv_usec))
++ if (V4L2_TYPE_IS_OUTPUT(type))
++ if (assign_in_user(&kp->bytesused, &up->bytesused) ||
++ assign_in_user(&kp->field, &up->field) ||
++ assign_in_user(&kp->timestamp.tv_sec,
++ &up->timestamp.tv_sec) ||
++ assign_in_user(&kp->timestamp.tv_usec,
++ &up->timestamp.tv_usec))
+ return -EFAULT;
+
+- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+- unsigned int num_planes;
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ u32 num_planes = length;
+
+- if (kp->length == 0) {
+- kp->m.planes = NULL;
+- /* num_planes == 0 is legal, e.g. when userspace doesn't
+- * need planes array on DQBUF*/
+- return 0;
+- } else if (kp->length > VIDEO_MAX_PLANES) {
+- return -EINVAL;
++ if (num_planes == 0) {
++ /*
++ * num_planes == 0 is legal, e.g. when userspace doesn't
++ * need planes array on DQBUF
++ */
++ return put_user(NULL, &kp->m.planes);
+ }
++ if (num_planes > VIDEO_MAX_PLANES)
++ return -EINVAL;
+
+ if (get_user(p, &up->m.planes))
+ return -EFAULT;
+
+ uplane32 = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, uplane32,
+- kp->length * sizeof(struct v4l2_plane32)))
++ num_planes * sizeof(*uplane32)))
+ return -EFAULT;
+
+- /* We don't really care if userspace decides to kill itself
+- * by passing a very big num_planes value */
+- uplane = compat_alloc_user_space(kp->length *
+- sizeof(struct v4l2_plane));
+- kp->m.planes = (__force struct v4l2_plane *)uplane;
++ /*
++ * We don't really care if userspace decides to kill itself
++ * by passing a very big num_planes value
++ */
++ if (aux_space < num_planes * sizeof(*uplane))
++ return -EFAULT;
+
+- for (num_planes = 0; num_planes < kp->length; num_planes++) {
+- ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
++ uplane = aux_buf;
++ if (put_user((__force struct v4l2_plane *)uplane,
++ &kp->m.planes))
++ return -EFAULT;
++
++ while (num_planes--) {
++ ret = get_v4l2_plane32(uplane, uplane32, memory);
+ if (ret)
+ return ret;
+- ++uplane;
+- ++uplane32;
++ uplane++;
++ uplane32++;
+ }
+ } else {
+- switch (kp->memory) {
++ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+- if (get_user(kp->m.offset, &up->m.offset))
++ case V4L2_MEMORY_OVERLAY:
++ if (assign_in_user(&kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+- case V4L2_MEMORY_USERPTR:
+- {
+- compat_long_t tmp;
++ case V4L2_MEMORY_USERPTR: {
++ compat_ulong_t userptr;
+
+- if (get_user(tmp, &up->m.userptr))
+- return -EFAULT;
+-
+- kp->m.userptr = (unsigned long)compat_ptr(tmp);
+- }
+- break;
+- case V4L2_MEMORY_OVERLAY:
+- if (get_user(kp->m.offset, &up->m.offset))
++ if (get_user(userptr, &up->m.userptr) ||
++ put_user((unsigned long)compat_ptr(userptr),
++ &kp->m.userptr))
+ return -EFAULT;
+ break;
++ }
+ case V4L2_MEMORY_DMABUF:
+- if (get_user(kp->m.fd, &up->m.fd))
++ if (assign_in_user(&kp->m.fd, &up->m.fd))
+ return -EFAULT;
+ break;
+ }
+@@ -512,65 +578,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
+ return 0;
+ }
+
+-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
++ struct v4l2_buffer32 __user *up)
+ {
++ u32 type;
++ u32 length;
++ enum v4l2_memory memory;
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+- int num_planes;
+ int ret;
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
+- put_user(kp->index, &up->index) ||
+- put_user(kp->type, &up->type) ||
+- put_user(kp->flags, &up->flags) ||
+- put_user(kp->memory, &up->memory))
+- return -EFAULT;
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ assign_in_user(&up->index, &kp->index) ||
++ get_user(type, &kp->type) ||
++ put_user(type, &up->type) ||
++ assign_in_user(&up->flags, &kp->flags) ||
++ get_user(memory, &kp->memory) ||
++ put_user(memory, &up->memory))
++ return -EFAULT;
+
+- if (put_user(kp->bytesused, &up->bytesused) ||
+- put_user(kp->field, &up->field) ||
+- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+- copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
+- put_user(kp->sequence, &up->sequence) ||
+- put_user(kp->reserved2, &up->reserved2) ||
+- put_user(kp->reserved, &up->reserved) ||
+- put_user(kp->length, &up->length))
+- return -EFAULT;
++ if (assign_in_user(&up->bytesused, &kp->bytesused) ||
++ assign_in_user(&up->field, &kp->field) ||
++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++ assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
++ copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
++ assign_in_user(&up->sequence, &kp->sequence) ||
++ assign_in_user(&up->reserved2, &kp->reserved2) ||
++ assign_in_user(&up->reserved, &kp->reserved) ||
++ get_user(length, &kp->length) ||
++ put_user(length, &up->length))
++ return -EFAULT;
++
++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++ u32 num_planes = length;
+
+- if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+- num_planes = kp->length;
+ if (num_planes == 0)
+ return 0;
+
+- uplane = (__force struct v4l2_plane __user *)kp->m.planes;
++ if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
++ return -EFAULT;
+ if (get_user(p, &up->m.planes))
+ return -EFAULT;
+ uplane32 = compat_ptr(p);
+
+- while (--num_planes >= 0) {
+- ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
++ while (num_planes--) {
++ ret = put_v4l2_plane32(uplane, uplane32, memory);
+ if (ret)
+ return ret;
+ ++uplane;
+ ++uplane32;
+ }
+ } else {
+- switch (kp->memory) {
++ switch (memory) {
+ case V4L2_MEMORY_MMAP:
+- if (put_user(kp->m.offset, &up->m.offset))
++ case V4L2_MEMORY_OVERLAY:
++ if (assign_in_user(&up->m.offset, &kp->m.offset))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+- if (put_user(kp->m.userptr, &up->m.userptr))
+- return -EFAULT;
+- break;
+- case V4L2_MEMORY_OVERLAY:
+- if (put_user(kp->m.offset, &up->m.offset))
++ if (assign_in_user(&up->m.userptr, &kp->m.userptr))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_DMABUF:
+- if (put_user(kp->m.fd, &up->m.fd))
++ if (assign_in_user(&up->m.fd, &kp->m.fd))
+ return -EFAULT;
+ break;
+ }
+@@ -595,30 +666,33 @@ struct v4l2_framebuffer32 {
+ } fmt;
+ };
+
+-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++ struct v4l2_framebuffer32 __user *up)
+ {
+- u32 tmp;
+-
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
+- get_user(tmp, &up->base) ||
+- get_user(kp->capability, &up->capability) ||
+- get_user(kp->flags, &up->flags) ||
+- copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
+- return -EFAULT;
+- kp->base = (__force void *)compat_ptr(tmp);
++ compat_caddr_t tmp;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ get_user(tmp, &up->base) ||
++ put_user((__force void *)compat_ptr(tmp), &kp->base) ||
++ assign_in_user(&kp->capability, &up->capability) ||
++ assign_in_user(&kp->flags, &up->flags) ||
++ copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
++ return -EFAULT;
+ return 0;
+ }
+
+-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++ struct v4l2_framebuffer32 __user *up)
+ {
+- u32 tmp = (u32)((unsigned long)kp->base);
+-
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
+- put_user(tmp, &up->base) ||
+- put_user(kp->capability, &up->capability) ||
+- put_user(kp->flags, &up->flags) ||
+- copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
+- return -EFAULT;
++ void *base;
++
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ get_user(base, &kp->base) ||
++ put_user(ptr_to_compat(base), &up->base) ||
++ assign_in_user(&up->capability, &kp->capability) ||
++ assign_in_user(&up->flags, &kp->flags) ||
++ copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
++ return -EFAULT;
+ return 0;
+ }
+
+@@ -634,18 +708,22 @@ struct v4l2_input32 {
+ __u32 reserved[3];
+ };
+
+-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+- Otherwise it is identical to the 32-bit version. */
+-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++/*
++ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
++ * Otherwise it is identical to the 32-bit version.
++ */
++static inline int get_v4l2_input32(struct v4l2_input __user *kp,
++ struct v4l2_input32 __user *up)
+ {
+- if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
++ if (copy_in_user(kp, up, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+
+-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++static inline int put_v4l2_input32(struct v4l2_input __user *kp,
++ struct v4l2_input32 __user *up)
+ {
+- if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
++ if (copy_in_user(up, kp, sizeof(*up)))
+ return -EFAULT;
+ return 0;
+ }
+@@ -669,60 +747,95 @@ struct v4l2_ext_control32 {
+ };
+ } __attribute__ ((packed));
+
+-/* The following function really belong in v4l2-common, but that causes
+- a circular dependency between modules. We need to think about this, but
+- for now this will do. */
+-
+-/* Return non-zero if this control is a pointer type. Currently only
+- type STRING is a pointer type. */
+-static inline int ctrl_is_pointer(u32 id)
++/* Return true if this control is a pointer type. */
++static inline bool ctrl_is_pointer(struct file *file, u32 id)
+ {
+- switch (id) {
+- case V4L2_CID_RDS_TX_PS_NAME:
+- case V4L2_CID_RDS_TX_RADIO_TEXT:
+- return 1;
+- default:
+- return 0;
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_fh *fh = NULL;
++ struct v4l2_ctrl_handler *hdl = NULL;
++ struct v4l2_query_ext_ctrl qec = { id };
++ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
++
++ if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
++ fh = file->private_data;
++
++ if (fh && fh->ctrl_handler)
++ hdl = fh->ctrl_handler;
++ else if (vdev->ctrl_handler)
++ hdl = vdev->ctrl_handler;
++
++ if (hdl) {
++ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
++
++ return ctrl && ctrl->is_ptr;
+ }
++
++ if (!ops || !ops->vidioc_query_ext_ctrl)
++ return false;
++
++ return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
++ (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
++}
++
++static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
++ u32 *size)
++{
++ u32 count;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ get_user(count, &up->count))
++ return -EFAULT;
++ if (count > V4L2_CID_MAX_CTRLS)
++ return -EINVAL;
++ *size = count * sizeof(struct v4l2_ext_control);
++ return 0;
+ }
+
+-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int get_v4l2_ext_controls32(struct file *file,
++ struct v4l2_ext_controls __user *kp,
++ struct v4l2_ext_controls32 __user *up,
++ void __user *aux_buf, u32 aux_space)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+ struct v4l2_ext_control __user *kcontrols;
+- unsigned int n;
++ u32 count;
++ u32 n;
+ compat_caddr_t p;
+
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
+- get_user(kp->which, &up->which) ||
+- get_user(kp->count, &up->count) ||
+- get_user(kp->error_idx, &up->error_idx) ||
+- copy_from_user(kp->reserved, up->reserved,
+- sizeof(kp->reserved)))
+- return -EFAULT;
+- if (kp->count == 0) {
+- kp->controls = NULL;
+- return 0;
+- } else if (kp->count > V4L2_CID_MAX_CTRLS) {
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ assign_in_user(&kp->which, &up->which) ||
++ get_user(count, &up->count) ||
++ put_user(count, &kp->count) ||
++ assign_in_user(&kp->error_idx, &up->error_idx) ||
++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++ return -EFAULT;
++
++ if (count == 0)
++ return put_user(NULL, &kp->controls);
++ if (count > V4L2_CID_MAX_CTRLS)
+ return -EINVAL;
+- }
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_READ, ucontrols,
+- kp->count * sizeof(struct v4l2_ext_control32)))
++ if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
+ return -EFAULT;
+- kcontrols = compat_alloc_user_space(kp->count *
+- sizeof(struct v4l2_ext_control));
+- kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+- for (n = 0; n < kp->count; n++) {
++ if (aux_space < count * sizeof(*kcontrols))
++ return -EFAULT;
++ kcontrols = aux_buf;
++ if (put_user((__force struct v4l2_ext_control *)kcontrols,
++ &kp->controls))
++ return -EFAULT;
++
++ for (n = 0; n < count; n++) {
+ u32 id;
+
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
+ return -EFAULT;
++
+ if (get_user(id, &kcontrols->id))
+ return -EFAULT;
+- if (ctrl_is_pointer(id)) {
++
++ if (ctrl_is_pointer(file, id)) {
+ void __user *s;
+
+ if (get_user(p, &ucontrols->string))
+@@ -737,43 +850,55 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
+ return 0;
+ }
+
+-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int put_v4l2_ext_controls32(struct file *file,
++ struct v4l2_ext_controls __user *kp,
++ struct v4l2_ext_controls32 __user *up)
+ {
+ struct v4l2_ext_control32 __user *ucontrols;
+- struct v4l2_ext_control __user *kcontrols =
+- (__force struct v4l2_ext_control __user *)kp->controls;
+- int n = kp->count;
++ struct v4l2_ext_control __user *kcontrols;
++ u32 count;
++ u32 n;
+ compat_caddr_t p;
+
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
+- put_user(kp->which, &up->which) ||
+- put_user(kp->count, &up->count) ||
+- put_user(kp->error_idx, &up->error_idx) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+- return -EFAULT;
+- if (!kp->count)
+- return 0;
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ assign_in_user(&up->which, &kp->which) ||
++ get_user(count, &kp->count) ||
++ put_user(count, &up->count) ||
++ assign_in_user(&up->error_idx, &kp->error_idx) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
++ get_user(kcontrols, &kp->controls))
++ return -EFAULT;
+
++ if (!count)
++ return 0;
+ if (get_user(p, &up->controls))
+ return -EFAULT;
+ ucontrols = compat_ptr(p);
+- if (!access_ok(VERIFY_WRITE, ucontrols,
+- n * sizeof(struct v4l2_ext_control32)))
++ if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
+ return -EFAULT;
+
+- while (--n >= 0) {
+- unsigned size = sizeof(*ucontrols);
++ for (n = 0; n < count; n++) {
++ unsigned int size = sizeof(*ucontrols);
+ u32 id;
+
+- if (get_user(id, &kcontrols->id))
++ if (get_user(id, &kcontrols->id) ||
++ put_user(id, &ucontrols->id) ||
++ assign_in_user(&ucontrols->size, &kcontrols->size) ||
++ copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
++ sizeof(ucontrols->reserved2)))
+ return -EFAULT;
+- /* Do not modify the pointer when copying a pointer control.
+- The contents of the pointer was changed, not the pointer
+- itself. */
+- if (ctrl_is_pointer(id))
++
++ /*
++ * Do not modify the pointer when copying a pointer control.
++ * The contents of the pointer was changed, not the pointer
++ * itself.
++ */
++ if (ctrl_is_pointer(file, id))
+ size -= sizeof(ucontrols->value64);
++
+ if (copy_in_user(ucontrols, kcontrols, size))
+ return -EFAULT;
++
+ ucontrols++;
+ kcontrols++;
+ }
+@@ -793,18 +918,19 @@ struct v4l2_event32 {
+ __u32 reserved[8];
+ };
+
+-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
++static int put_v4l2_event32(struct v4l2_event __user *kp,
++ struct v4l2_event32 __user *up)
+ {
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
+- put_user(kp->type, &up->type) ||
+- copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+- put_user(kp->pending, &up->pending) ||
+- put_user(kp->sequence, &up->sequence) ||
+- put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+- put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+- put_user(kp->id, &up->id) ||
+- copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+- return -EFAULT;
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ assign_in_user(&up->type, &kp->type) ||
++ copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
++ assign_in_user(&up->pending, &kp->pending) ||
++ assign_in_user(&up->sequence, &kp->sequence) ||
++ assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++ assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
++ assign_in_user(&up->id, &kp->id) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++ return -EFAULT;
+ return 0;
+ }
+
+@@ -816,32 +942,35 @@ struct v4l2_edid32 {
+ compat_caddr_t edid;
+ };
+
+-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int get_v4l2_edid32(struct v4l2_edid __user *kp,
++ struct v4l2_edid32 __user *up)
+ {
+- u32 tmp;
+-
+- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
+- get_user(kp->pad, &up->pad) ||
+- get_user(kp->start_block, &up->start_block) ||
+- get_user(kp->blocks, &up->blocks) ||
+- get_user(tmp, &up->edid) ||
+- copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+- return -EFAULT;
+- kp->edid = (__force u8 *)compat_ptr(tmp);
++ compat_uptr_t tmp;
++
++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++ assign_in_user(&kp->pad, &up->pad) ||
++ assign_in_user(&kp->start_block, &up->start_block) ||
++ assign_in_user(&kp->blocks, &up->blocks) ||
++ get_user(tmp, &up->edid) ||
++ put_user(compat_ptr(tmp), &kp->edid) ||
++ copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++ return -EFAULT;
+ return 0;
+ }
+
+-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int put_v4l2_edid32(struct v4l2_edid __user *kp,
++ struct v4l2_edid32 __user *up)
+ {
+- u32 tmp = (u32)((unsigned long)kp->edid);
+-
+- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
+- put_user(kp->pad, &up->pad) ||
+- put_user(kp->start_block, &up->start_block) ||
+- put_user(kp->blocks, &up->blocks) ||
+- put_user(tmp, &up->edid) ||
+- copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+- return -EFAULT;
++ void *edid;
++
++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
++ assign_in_user(&up->pad, &kp->pad) ||
++ assign_in_user(&up->start_block, &kp->start_block) ||
++ assign_in_user(&up->blocks, &kp->blocks) ||
++ get_user(edid, &kp->edid) ||
++ put_user(ptr_to_compat(edid), &up->edid) ||
++ copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++ return -EFAULT;
+ return 0;
+ }
+
+@@ -873,22 +1002,23 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+ #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
+ #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
+
++static int alloc_userspace(unsigned int size, u32 aux_space,
++ void __user **up_native)
++{
++ *up_native = compat_alloc_user_space(size + aux_space);
++ if (!*up_native)
++ return -ENOMEM;
++ if (clear_user(*up_native, size))
++ return -EFAULT;
++ return 0;
++}
++
+ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+- union {
+- struct v4l2_format v2f;
+- struct v4l2_buffer v2b;
+- struct v4l2_framebuffer v2fb;
+- struct v4l2_input v2i;
+- struct v4l2_standard v2s;
+- struct v4l2_ext_controls v2ecs;
+- struct v4l2_event v2ev;
+- struct v4l2_create_buffers v2crt;
+- struct v4l2_edid v2edid;
+- unsigned long vx;
+- int vi;
+- } karg;
+ void __user *up = compat_ptr(arg);
++ void __user *up_native = NULL;
++ void __user *aux_buf;
++ u32 aux_space;
+ int compatible_arg = 1;
+ long err = 0;
+
+@@ -927,30 +1057,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
+ case VIDIOC_STREAMOFF:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+- err = get_user(karg.vi, (s32 __user *)up);
++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
++ if (!err && assign_in_user((unsigned int __user *)up_native,
++ (compat_uint_t __user *)up))
++ err = -EFAULT;
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
++ err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_EDID:
+ case VIDIOC_S_EDID:
+- err = get_v4l2_edid32(&karg.v2edid, up);
++ err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
++ if (!err)
++ err = get_v4l2_edid32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+- err = get_v4l2_format32(&karg.v2f, up);
++ err = bufsize_v4l2_format(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_format),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_format);
++ err = get_v4l2_format32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_CREATE_BUFS:
+- err = get_v4l2_create32(&karg.v2crt, up);
++ err = bufsize_v4l2_create(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_create_buffers),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_create_buffers);
++ err = get_v4l2_create32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+@@ -958,36 +1110,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+- err = get_v4l2_buffer32(&karg.v2b, up);
++ err = bufsize_v4l2_buffer(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_buffer),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_buffer);
++ err = get_v4l2_buffer32(up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_S_FBUF:
+- err = get_v4l2_framebuffer32(&karg.v2fb, up);
++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++ &up_native);
++ if (!err)
++ err = get_v4l2_framebuffer32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_FBUF:
++ err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++ &up_native);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_ENUMSTD:
+- err = get_v4l2_standard32(&karg.v2s, up);
++ err = alloc_userspace(sizeof(struct v4l2_standard), 0,
++ &up_native);
++ if (!err)
++ err = get_v4l2_standard32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_ENUMINPUT:
+- err = get_v4l2_input32(&karg.v2i, up);
++ err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
++ if (!err)
++ err = get_v4l2_input32(up_native, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- err = get_v4l2_ext_controls32(&karg.v2ecs, up);
++ err = bufsize_v4l2_ext_controls(up, &aux_space);
++ if (!err)
++ err = alloc_userspace(sizeof(struct v4l2_ext_controls),
++ aux_space, &up_native);
++ if (!err) {
++ aux_buf = up_native + sizeof(struct v4l2_ext_controls);
++ err = get_v4l2_ext_controls32(file, up_native, up,
++ aux_buf, aux_space);
++ }
+ compatible_arg = 0;
+ break;
+ case VIDIOC_DQEVENT:
++ err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
+ compatible_arg = 0;
+ break;
+ }
+@@ -996,26 +1175,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
+
+ if (compatible_arg)
+ err = native_ioctl(file, cmd, (unsigned long)up);
+- else {
+- mm_segment_t old_fs = get_fs();
++ else
++ err = native_ioctl(file, cmd, (unsigned long)up_native);
+
+- set_fs(KERNEL_DS);
+- err = native_ioctl(file, cmd, (unsigned long)&karg);
+- set_fs(old_fs);
+- }
++ if (err == -ENOTTY)
++ return err;
+
+- /* Special case: even after an error we need to put the
+- results back for these ioctls since the error_idx will
+- contain information on which control failed. */
++ /*
++ * Special case: even after an error we need to put the
++ * results back for these ioctls since the error_idx will
++ * contain information on which control failed.
++ */
+ switch (cmd) {
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+- if (put_v4l2_ext_controls32(&karg.v2ecs, up))
++ if (put_v4l2_ext_controls32(file, up_native, up))
+ err = -EFAULT;
+ break;
+ case VIDIOC_S_EDID:
+- if (put_v4l2_edid32(&karg.v2edid, up))
++ if (put_v4l2_edid32(up_native, up))
+ err = -EFAULT;
+ break;
+ }
+@@ -1027,43 +1206,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_G_OUTPUT:
+- err = put_user(((s32)karg.vi), (s32 __user *)up);
++ if (assign_in_user((compat_uint_t __user *)up,
++ ((unsigned int __user *)up_native)))
++ err = -EFAULT;
+ break;
+
+ case VIDIOC_G_FBUF:
+- err = put_v4l2_framebuffer32(&karg.v2fb, up);
++ err = put_v4l2_framebuffer32(up_native, up);
+ break;
+
+ case VIDIOC_DQEVENT:
+- err = put_v4l2_event32(&karg.v2ev, up);
++ err = put_v4l2_event32(up_native, up);
+ break;
+
+ case VIDIOC_G_EDID:
+- err = put_v4l2_edid32(&karg.v2edid, up);
++ err = put_v4l2_edid32(up_native, up);
+ break;
+
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+- err = put_v4l2_format32(&karg.v2f, up);
++ err = put_v4l2_format32(up_native, up);
+ break;
+
+ case VIDIOC_CREATE_BUFS:
+- err = put_v4l2_create32(&karg.v2crt, up);
++ err = put_v4l2_create32(up_native, up);
+ break;
+
++ case VIDIOC_PREPARE_BUF:
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+- err = put_v4l2_buffer32(&karg.v2b, up);
++ err = put_v4l2_buffer32(up_native, up);
+ break;
+
+ case VIDIOC_ENUMSTD:
+- err = put_v4l2_standard32(&karg.v2s, up);
++ err = put_v4l2_standard32(up_native, up);
+ break;
+
+ case VIDIOC_ENUMINPUT:
+- err = put_v4l2_input32(&karg.v2i, up);
++ err = put_v4l2_input32(up_native, up);
+ break;
+ }
+ return err;
+diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
+index b60a6b0841d1..d06941cc6a55 100644
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -1308,52 +1308,50 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+ {
+ struct v4l2_fmtdesc *p = arg;
+- struct video_device *vfd = video_devdata(file);
+- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+- bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+- bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+- int ret = -EINVAL;
++ int ret = check_fmt(file, p->type);
++
++ if (ret)
++ return ret;
++ ret = -EINVAL;
+
+ switch (p->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_enum_fmt_vid_cap))
++ if (unlikely(!ops->vidioc_enum_fmt_vid_cap))
+ break;
+ ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap_mplane))
++ if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane))
+ break;
+ ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_overlay))
++ if (unlikely(!ops->vidioc_enum_fmt_vid_overlay))
+ break;
+ ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out))
++ if (unlikely(!ops->vidioc_enum_fmt_vid_out))
+ break;
+ ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_enum_fmt_vid_out_mplane))
++ if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane))
+ break;
+ ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_enum_fmt_sdr_cap))
++ if (unlikely(!ops->vidioc_enum_fmt_sdr_cap))
+ break;
+ ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_enum_fmt_sdr_out))
++ if (unlikely(!ops->vidioc_enum_fmt_sdr_out))
+ break;
+ ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg);
+ break;
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_meta_cap))
++ if (unlikely(!ops->vidioc_enum_fmt_meta_cap))
+ break;
+ ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg);
+ break;
+@@ -1367,13 +1365,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+ {
+ struct v4l2_format *p = arg;
+- struct video_device *vfd = video_devdata(file);
+- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+- bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+- bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+- int ret;
++ int ret = check_fmt(file, p->type);
++
++ if (ret)
++ return ret;
+
+ /*
+ * fmt can't be cleared for these overlay types due to the 'clips'
+@@ -1401,7 +1396,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
+
+ switch (p->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_g_fmt_vid_cap))
++ if (unlikely(!ops->vidioc_g_fmt_vid_cap))
+ break;
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
+@@ -1409,23 +1404,15 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane))
+- break;
+ return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay))
+- break;
+ return ops->vidioc_g_fmt_vid_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_vbi_cap))
+- break;
+ return ops->vidioc_g_fmt_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_cap))
+- break;
+ return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out))
++ if (unlikely(!ops->vidioc_g_fmt_vid_out))
+ break;
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ ret = ops->vidioc_g_fmt_vid_out(file, fh, arg);
+@@ -1433,32 +1420,18 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane))
+- break;
+ return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay))
+- break;
+ return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_vbi_out))
+- break;
+ return ops->vidioc_g_fmt_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out))
+- break;
+ return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap))
+- break;
+ return ops->vidioc_g_fmt_sdr_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out))
+- break;
+ return ops->vidioc_g_fmt_sdr_out(file, fh, arg);
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_meta_cap))
+- break;
+ return ops->vidioc_g_fmt_meta_cap(file, fh, arg);
+ }
+ return -EINVAL;
+@@ -1484,12 +1457,10 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
+ {
+ struct v4l2_format *p = arg;
+ struct video_device *vfd = video_devdata(file);
+- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+- bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+- bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+- int ret;
++ int ret = check_fmt(file, p->type);
++
++ if (ret)
++ return ret;
+
+ ret = v4l_enable_media_source(vfd);
+ if (ret)
+@@ -1498,37 +1469,37 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
+
+ switch (p->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_s_fmt_vid_cap))
++ if (unlikely(!ops->vidioc_s_fmt_vid_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix);
+ ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
+ /* just in case the driver zeroed it again */
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+- if (is_tch)
++ if (vfd->vfl_type == VFL_TYPE_TOUCH)
+ v4l_pix_format_touch(&p->fmt.pix);
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane))
++ if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay))
++ if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.win);
+ return ops->vidioc_s_fmt_vid_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_vbi_cap))
++ if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.vbi);
+ return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_cap))
++ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sliced);
+ return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out))
++ if (unlikely(!ops->vidioc_s_fmt_vid_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix);
+ ret = ops->vidioc_s_fmt_vid_out(file, fh, arg);
+@@ -1536,37 +1507,37 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane))
++ if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay))
++ if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.win);
+ return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_vbi_out))
++ if (unlikely(!ops->vidioc_s_fmt_vbi_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.vbi);
+ return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_s_fmt_sliced_vbi_out))
++ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sliced);
+ return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap))
++ if (unlikely(!ops->vidioc_s_fmt_sdr_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_s_fmt_sdr_out))
++ if (unlikely(!ops->vidioc_s_fmt_sdr_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_meta_cap))
++ if (unlikely(!ops->vidioc_s_fmt_meta_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.meta);
+ return ops->vidioc_s_fmt_meta_cap(file, fh, arg);
+@@ -1578,19 +1549,16 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+ {
+ struct v4l2_format *p = arg;
+- struct video_device *vfd = video_devdata(file);
+- bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
+- bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
+- bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
+- bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
+- bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
+- int ret;
++ int ret = check_fmt(file, p->type);
++
++ if (ret)
++ return ret;
+
+ v4l_sanitize_format(p);
+
+ switch (p->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+- if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_try_fmt_vid_cap))
++ if (unlikely(!ops->vidioc_try_fmt_vid_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix);
+ ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg);
+@@ -1598,27 +1566,27 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap_mplane))
++ if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_overlay))
++ if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.win);
+ return ops->vidioc_try_fmt_vid_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_vbi_cap))
++ if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.vbi);
+ return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+- if (unlikely(!is_rx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_cap))
++ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sliced);
+ return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out))
++ if (unlikely(!ops->vidioc_try_fmt_vid_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix);
+ ret = ops->vidioc_try_fmt_vid_out(file, fh, arg);
+@@ -1626,37 +1594,37 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
+ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ return ret;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_mplane))
++ if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func);
+ return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+- if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_overlay))
++ if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.win);
+ return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg);
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_vbi_out))
++ if (unlikely(!ops->vidioc_try_fmt_vbi_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.vbi);
+ return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+- if (unlikely(!is_tx || is_vid || !ops->vidioc_try_fmt_sliced_vbi_out))
++ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sliced);
+ return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+- if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap))
++ if (unlikely(!ops->vidioc_try_fmt_sdr_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+- if (unlikely(!is_tx || !is_sdr || !ops->vidioc_try_fmt_sdr_out))
++ if (unlikely(!ops->vidioc_try_fmt_sdr_out))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.sdr);
+ return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
+ case V4L2_BUF_TYPE_META_CAPTURE:
+- if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_meta_cap))
++ if (unlikely(!ops->vidioc_try_fmt_meta_cap))
+ break;
+ CLEAR_AFTER_FIELD(p, fmt.meta);
+ return ops->vidioc_try_fmt_meta_cap(file, fh, arg);
+@@ -2924,8 +2892,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+
+ /* Handles IOCTL */
+ err = func(file, cmd, parg);
+- if (err == -ENOIOCTLCMD)
++ if (err == -ENOTTY || err == -ENOIOCTLCMD) {
+ err = -ENOTTY;
++ goto out;
++ }
++
+ if (err == 0) {
+ if (cmd == VIDIOC_DQBUF)
+ trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
+diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
+index e0eb51d8c012..edf24c148fa6 100644
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -2193,16 +2193,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
+ if (ctrl->nand_version >= 0x0702)
+ tmp |= ACC_CONTROL_RD_ERASED;
+ tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
+- if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
+- /*
+- * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
+- * errors
+- */
+- if (has_flash_dma(ctrl))
+- tmp &= ~ACC_CONTROL_PREFETCH;
+- else
+- tmp |= ACC_CONTROL_PREFETCH;
+- }
++ if (ctrl->features & BRCMNAND_HAS_PREFETCH)
++ tmp &= ~ACC_CONTROL_PREFETCH;
++
+ nand_writereg(ctrl, offs, tmp);
+
+ return 0;
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 3f1d806e590a..a0b0302aea14 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -2201,6 +2201,7 @@ EXPORT_SYMBOL(nand_write_oob_syndrome);
+ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+ {
++ unsigned int max_bitflips = 0;
+ int page, realpage, chipnr;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_ecc_stats stats;
+@@ -2258,6 +2259,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+ nand_wait_ready(mtd);
+ }
+
++ max_bitflips = max_t(unsigned int, max_bitflips, ret);
++
+ readlen -= len;
+ if (!readlen)
+ break;
+@@ -2283,7 +2286,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+ if (mtd->ecc_stats.failed - stats.failed)
+ return -EBADMSG;
+
+- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
++ return max_bitflips;
+ }
+
+ /**
+diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
+index 82244be3e766..958974821582 100644
+--- a/drivers/mtd/nand/sunxi_nand.c
++++ b/drivers/mtd/nand/sunxi_nand.c
+@@ -1853,8 +1853,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
+
+ /* Add ECC info retrieval from DT */
+ for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+- if (ecc->strength <= strengths[i])
++ if (ecc->strength <= strengths[i]) {
++ /*
++ * Update ecc->strength value with the actual strength
++ * that will be used by the ECC engine.
++ */
++ ecc->strength = strengths[i];
+ break;
++ }
+ }
+
+ if (i >= ARRAY_SIZE(strengths)) {
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index b210fdb31c98..b1fc28f63882 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -99,6 +99,8 @@ struct ubiblock {
+
+ /* Linked list of all ubiblock instances */
+ static LIST_HEAD(ubiblock_devices);
++static DEFINE_IDR(ubiblock_minor_idr);
++/* Protects ubiblock_devices and ubiblock_minor_idr */
+ static DEFINE_MUTEX(devices_mutex);
+ static int ubiblock_major;
+
+@@ -351,8 +353,6 @@ static const struct blk_mq_ops ubiblock_mq_ops = {
+ .init_request = ubiblock_init_request,
+ };
+
+-static DEFINE_IDR(ubiblock_minor_idr);
+-
+ int ubiblock_create(struct ubi_volume_info *vi)
+ {
+ struct ubiblock *dev;
+@@ -365,14 +365,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
+ /* Check that the volume isn't already handled */
+ mutex_lock(&devices_mutex);
+ if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
+- mutex_unlock(&devices_mutex);
+- return -EEXIST;
++ ret = -EEXIST;
++ goto out_unlock;
+ }
+- mutex_unlock(&devices_mutex);
+
+ dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
+- if (!dev)
+- return -ENOMEM;
++ if (!dev) {
++ ret = -ENOMEM;
++ goto out_unlock;
++ }
+
+ mutex_init(&dev->dev_mutex);
+
+@@ -437,14 +438,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
+ goto out_free_queue;
+ }
+
+- mutex_lock(&devices_mutex);
+ list_add_tail(&dev->list, &ubiblock_devices);
+- mutex_unlock(&devices_mutex);
+
+ /* Must be the last step: anyone can call file ops from now on */
+ add_disk(dev->gd);
+ dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
+ dev->ubi_num, dev->vol_id, vi->name);
++ mutex_unlock(&devices_mutex);
+ return 0;
+
+ out_free_queue:
+@@ -457,6 +457,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
+ put_disk(dev->gd);
+ out_free_dev:
+ kfree(dev);
++out_unlock:
++ mutex_unlock(&devices_mutex);
+
+ return ret;
+ }
+@@ -478,30 +480,36 @@ static void ubiblock_cleanup(struct ubiblock *dev)
+ int ubiblock_remove(struct ubi_volume_info *vi)
+ {
+ struct ubiblock *dev;
++ int ret;
+
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+- mutex_unlock(&devices_mutex);
+- return -ENODEV;
++ ret = -ENODEV;
++ goto out_unlock;
+ }
+
+ /* Found a device, let's lock it so we can check if it's busy */
+ mutex_lock(&dev->dev_mutex);
+ if (dev->refcnt > 0) {
+- mutex_unlock(&dev->dev_mutex);
+- mutex_unlock(&devices_mutex);
+- return -EBUSY;
++ ret = -EBUSY;
++ goto out_unlock_dev;
+ }
+
+ /* Remove from device list */
+ list_del(&dev->list);
+- mutex_unlock(&devices_mutex);
+-
+ ubiblock_cleanup(dev);
+ mutex_unlock(&dev->dev_mutex);
++ mutex_unlock(&devices_mutex);
++
+ kfree(dev);
+ return 0;
++
++out_unlock_dev:
++ mutex_unlock(&dev->dev_mutex);
++out_unlock:
++ mutex_unlock(&devices_mutex);
++ return ret;
+ }
+
+ static int ubiblock_resize(struct ubi_volume_info *vi)
+@@ -630,6 +638,7 @@ static void ubiblock_remove_all(void)
+ struct ubiblock *next;
+ struct ubiblock *dev;
+
++ mutex_lock(&devices_mutex);
+ list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
+ /* The module is being forcefully removed */
+ WARN_ON(dev->desc);
+@@ -638,6 +647,7 @@ static void ubiblock_remove_all(void)
+ ubiblock_cleanup(dev);
+ kfree(dev);
+ }
++ mutex_unlock(&devices_mutex);
+ }
+
+ int __init ubiblock_init(void)
+diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
+index 85237cf661f9..3fd8d7ff7a02 100644
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -270,6 +270,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+ vol->last_eb_bytes = vol->usable_leb_size;
+ }
+
++ /* Make volume "available" before it becomes accessible via sysfs */
++ spin_lock(&ubi->volumes_lock);
++ ubi->volumes[vol_id] = vol;
++ ubi->vol_count += 1;
++ spin_unlock(&ubi->volumes_lock);
++
+ /* Register character device for the volume */
+ cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
+ vol->cdev.owner = THIS_MODULE;
+@@ -298,11 +304,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+ if (err)
+ goto out_sysfs;
+
+- spin_lock(&ubi->volumes_lock);
+- ubi->volumes[vol_id] = vol;
+- ubi->vol_count += 1;
+- spin_unlock(&ubi->volumes_lock);
+-
+ ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
+ self_check_volumes(ubi);
+ return err;
+@@ -315,6 +316,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+ */
+ cdev_device_del(&vol->cdev, &vol->dev);
+ out_mapping:
++ spin_lock(&ubi->volumes_lock);
++ ubi->volumes[vol_id] = NULL;
++ ubi->vol_count -= 1;
++ spin_unlock(&ubi->volumes_lock);
+ ubi_eba_destroy_table(eba_tbl);
+ out_acc:
+ spin_lock(&ubi->volumes_lock);
+diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
+index b5b8cd6f481c..668b46202507 100644
+--- a/drivers/mtd/ubi/wl.c
++++ b/drivers/mtd/ubi/wl.c
+@@ -1528,6 +1528,46 @@ static void shutdown_work(struct ubi_device *ubi)
+ }
+ }
+
++/**
++ * erase_aeb - erase a PEB given in UBI attach info PEB
++ * @ubi: UBI device description object
++ * @aeb: UBI attach info PEB
++ * @sync: If true, erase synchronously. Otherwise schedule for erasure
++ */
++static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
++{
++ struct ubi_wl_entry *e;
++ int err;
++
++ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
++ if (!e)
++ return -ENOMEM;
++
++ e->pnum = aeb->pnum;
++ e->ec = aeb->ec;
++ ubi->lookuptbl[e->pnum] = e;
++
++ if (sync) {
++ err = sync_erase(ubi, e, false);
++ if (err)
++ goto out_free;
++
++ wl_tree_add(e, &ubi->free);
++ ubi->free_count++;
++ } else {
++ err = schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false);
++ if (err)
++ goto out_free;
++ }
++
++ return 0;
++
++out_free:
++ wl_entry_destroy(ubi, e);
++
++ return err;
++}
++
+ /**
+ * ubi_wl_init - initialize the WL sub-system using attaching information.
+ * @ubi: UBI device description object
+@@ -1566,18 +1606,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
+ list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
+ cond_resched();
+
+- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+- if (!e)
++ err = erase_aeb(ubi, aeb, false);
++ if (err)
+ goto out_free;
+
+- e->pnum = aeb->pnum;
+- e->ec = aeb->ec;
+- ubi->lookuptbl[e->pnum] = e;
+- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
+- wl_entry_destroy(ubi, e);
+- goto out_free;
+- }
+-
+ found_pebs++;
+ }
+
+@@ -1635,6 +1667,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
+ ubi_assert(!ubi->lookuptbl[e->pnum]);
+ ubi->lookuptbl[e->pnum] = e;
+ } else {
++ bool sync = false;
++
+ /*
+ * Usually old Fastmap PEBs are scheduled for erasure
+ * and we don't have to care about them but if we face
+@@ -1644,18 +1678,21 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
+ if (ubi->lookuptbl[aeb->pnum])
+ continue;
+
+- e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+- if (!e)
+- goto out_free;
++ /*
++ * The fastmap update code might not find a free PEB for
++ * writing the fastmap anchor to and then reuses the
++ * current fastmap anchor PEB. When this PEB gets erased
++ * and a power cut happens before it is written again we
++ * must make sure that the fastmap attach code doesn't
++ * find any outdated fastmap anchors, hence we erase the
++ * outdated fastmap anchor PEBs synchronously here.
++ */
++ if (aeb->vol_id == UBI_FM_SB_VOLUME_ID)
++ sync = true;
+
+- e->pnum = aeb->pnum;
+- e->ec = aeb->ec;
+- ubi_assert(!ubi->lookuptbl[e->pnum]);
+- ubi->lookuptbl[e->pnum] = e;
+- if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, false)) {
+- wl_entry_destroy(ubi, e);
++ err = erase_aeb(ubi, aeb, sync);
++ if (err)
+ goto out_free;
+- }
+ }
+
+ found_pebs++;
+diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
+index 71df0f70b61f..72b4527d690f 100644
+--- a/drivers/pinctrl/intel/pinctrl-intel.c
++++ b/drivers/pinctrl/intel/pinctrl-intel.c
+@@ -427,6 +427,18 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
+ writel(value, padcfg0);
+ }
+
++static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
++{
++ u32 value;
++
++ /* Put the pad into GPIO mode */
++ value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
++ /* Disable SCI/SMI/NMI generation */
++ value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
++ value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
++ writel(value, padcfg0);
++}
++
+ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned pin)
+@@ -434,7 +446,6 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ void __iomem *padcfg0;
+ unsigned long flags;
+- u32 value;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+@@ -444,13 +455,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
+ }
+
+ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
+- /* Put the pad into GPIO mode */
+- value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
+- /* Disable SCI/SMI/NMI generation */
+- value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
+- value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
+- writel(value, padcfg0);
+-
++ intel_gpio_set_gpio_mode(padcfg0);
+ /* Disable TX buffer and enable RX (this will be input) */
+ __intel_gpio_set_direction(padcfg0, true);
+
+@@ -935,6 +940,8 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
++ intel_gpio_set_gpio_mode(reg);
++
+ value = readl(reg);
+
+ value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
+diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
+index 9c950bbf07ba..447763aad815 100644
+--- a/drivers/pinctrl/pinctrl-mcp23s08.c
++++ b/drivers/pinctrl/pinctrl-mcp23s08.c
+@@ -891,16 +891,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
+ goto fail;
+ }
+
+- ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
+- if (ret < 0)
+- goto fail;
+-
+ if (mcp->irq && mcp->irq_controller) {
+ ret = mcp23s08_irq_setup(mcp);
+ if (ret)
+ goto fail;
+ }
+
++ ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
++ if (ret < 0)
++ goto fail;
++
+ mcp->pinctrl_desc.name = "mcp23xxx-pinctrl";
+ mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops;
+ mcp->pinctrl_desc.confops = &mcp_pinconf_ops;
+diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c
+index 7450f5118445..70a0228f4e7f 100644
+--- a/drivers/pinctrl/pinctrl-sx150x.c
++++ b/drivers/pinctrl/pinctrl-sx150x.c
+@@ -1144,6 +1144,27 @@ static int sx150x_probe(struct i2c_client *client,
+ if (ret)
+ return ret;
+
++ /* Pinctrl_desc */
++ pctl->pinctrl_desc.name = "sx150x-pinctrl";
++ pctl->pinctrl_desc.pctlops = &sx150x_pinctrl_ops;
++ pctl->pinctrl_desc.confops = &sx150x_pinconf_ops;
++ pctl->pinctrl_desc.pins = pctl->data->pins;
++ pctl->pinctrl_desc.npins = pctl->data->npins;
++ pctl->pinctrl_desc.owner = THIS_MODULE;
++
++ ret = devm_pinctrl_register_and_init(dev, &pctl->pinctrl_desc,
++ pctl, &pctl->pctldev);
++ if (ret) {
++ dev_err(dev, "Failed to register pinctrl device\n");
++ return ret;
++ }
++
++ ret = pinctrl_enable(pctl->pctldev);
++ if (ret) {
++ dev_err(dev, "Failed to enable pinctrl device\n");
++ return ret;
++ }
++
+ /* Register GPIO controller */
+ pctl->gpio.label = devm_kstrdup(dev, client->name, GFP_KERNEL);
+ pctl->gpio.base = -1;
+@@ -1172,6 +1193,11 @@ static int sx150x_probe(struct i2c_client *client,
+ if (ret)
+ return ret;
+
++ ret = gpiochip_add_pin_range(&pctl->gpio, dev_name(dev),
++ 0, 0, pctl->data->npins);
++ if (ret)
++ return ret;
++
+ /* Add Interrupt support if an irq is specified */
+ if (client->irq > 0) {
+ pctl->irq_chip.name = devm_kstrdup(dev, client->name,
+@@ -1217,20 +1243,6 @@ static int sx150x_probe(struct i2c_client *client,
+ client->irq);
+ }
+
+- /* Pinctrl_desc */
+- pctl->pinctrl_desc.name = "sx150x-pinctrl";
+- pctl->pinctrl_desc.pctlops = &sx150x_pinctrl_ops;
+- pctl->pinctrl_desc.confops = &sx150x_pinconf_ops;
+- pctl->pinctrl_desc.pins = pctl->data->pins;
+- pctl->pinctrl_desc.npins = pctl->data->npins;
+- pctl->pinctrl_desc.owner = THIS_MODULE;
+-
+- pctl->pctldev = pinctrl_register(&pctl->pinctrl_desc, dev, pctl);
+- if (IS_ERR(pctl->pctldev)) {
+- dev_err(dev, "Failed to register pinctrl device\n");
+- return PTR_ERR(pctl->pctldev);
+- }
+-
+ return 0;
+ }
+
+diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
+index 76b8b7eed0c0..0b6467206f8e 100644
+--- a/drivers/scsi/cxlflash/main.c
++++ b/drivers/scsi/cxlflash/main.c
+@@ -620,6 +620,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
+ cmd->parent = afu;
+ cmd->hwq_index = hwq_index;
+
++ cmd->sa.ioasc = 0;
+ cmd->rcb.ctx_id = hwq->ctx_hndl;
+ cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
+ cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel);
+diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
+index fe3a0da3ec97..57bf43e34863 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -318,6 +318,9 @@ static void scsi_host_dev_release(struct device *dev)
+
+ scsi_proc_hostdir_rm(shost->hostt);
+
++ /* Wait for functions invoked through call_rcu(&shost->rcu, ...) */
++ rcu_barrier();
++
+ if (shost->tmf_work_q)
+ destroy_workqueue(shost->tmf_work_q);
+ if (shost->ehandler)
+@@ -325,6 +328,8 @@ static void scsi_host_dev_release(struct device *dev)
+ if (shost->work_q)
+ destroy_workqueue(shost->work_q);
+
++ destroy_rcu_head(&shost->rcu);
++
+ if (shost->shost_state == SHOST_CREATED) {
+ /*
+ * Free the shost_dev device name here if scsi_host_alloc()
+@@ -399,6 +404,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
+ INIT_LIST_HEAD(&shost->starved_list);
+ init_waitqueue_head(&shost->host_wait);
+ mutex_init(&shost->scan_mutex);
++ init_rcu_head(&shost->rcu);
+
+ index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
+ if (index < 0)
+diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
+index 6acf1bb1d320..25612ccf6ff2 100644
+--- a/drivers/scsi/lpfc/lpfc_init.c
++++ b/drivers/scsi/lpfc/lpfc_init.c
+@@ -9413,44 +9413,62 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
+ lpfc_sli4_bar0_register_memmap(phba, if_type);
+ }
+
+- if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) &&
+- (pci_resource_start(pdev, PCI_64BIT_BAR2))) {
+- /*
+- * Map SLI4 if type 0 HBA Control Register base to a kernel
+- * virtual address and setup the registers.
+- */
+- phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
+- bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
+- phba->sli4_hba.ctrl_regs_memmap_p =
+- ioremap(phba->pci_bar1_map, bar1map_len);
+- if (!phba->sli4_hba.ctrl_regs_memmap_p) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "ioremap failed for SLI4 HBA control registers.\n");
++ if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
++ if (pci_resource_start(pdev, PCI_64BIT_BAR2)) {
++ /*
++ * Map SLI4 if type 0 HBA Control Register base to a
++ * kernel virtual address and setup the registers.
++ */
++ phba->pci_bar1_map = pci_resource_start(pdev,
++ PCI_64BIT_BAR2);
++ bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
++ phba->sli4_hba.ctrl_regs_memmap_p =
++ ioremap(phba->pci_bar1_map,
++ bar1map_len);
++ if (!phba->sli4_hba.ctrl_regs_memmap_p) {
++ dev_err(&pdev->dev,
++ "ioremap failed for SLI4 HBA "
++ "control registers.\n");
++ error = -ENOMEM;
++ goto out_iounmap_conf;
++ }
++ phba->pci_bar2_memmap_p =
++ phba->sli4_hba.ctrl_regs_memmap_p;
++ lpfc_sli4_bar1_register_memmap(phba);
++ } else {
++ error = -ENOMEM;
+ goto out_iounmap_conf;
+ }
+- phba->pci_bar2_memmap_p = phba->sli4_hba.ctrl_regs_memmap_p;
+- lpfc_sli4_bar1_register_memmap(phba);
+ }
+
+- if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) &&
+- (pci_resource_start(pdev, PCI_64BIT_BAR4))) {
+- /*
+- * Map SLI4 if type 0 HBA Doorbell Register base to a kernel
+- * virtual address and setup the registers.
+- */
+- phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
+- bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
+- phba->sli4_hba.drbl_regs_memmap_p =
+- ioremap(phba->pci_bar2_map, bar2map_len);
+- if (!phba->sli4_hba.drbl_regs_memmap_p) {
+- dev_printk(KERN_ERR, &pdev->dev,
+- "ioremap failed for SLI4 HBA doorbell registers.\n");
+- goto out_iounmap_ctrl;
+- }
+- phba->pci_bar4_memmap_p = phba->sli4_hba.drbl_regs_memmap_p;
+- error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
+- if (error)
++ if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
++ if (pci_resource_start(pdev, PCI_64BIT_BAR4)) {
++ /*
++ * Map SLI4 if type 0 HBA Doorbell Register base to
++ * a kernel virtual address and setup the registers.
++ */
++ phba->pci_bar2_map = pci_resource_start(pdev,
++ PCI_64BIT_BAR4);
++ bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
++ phba->sli4_hba.drbl_regs_memmap_p =
++ ioremap(phba->pci_bar2_map,
++ bar2map_len);
++ if (!phba->sli4_hba.drbl_regs_memmap_p) {
++ dev_err(&pdev->dev,
++ "ioremap failed for SLI4 HBA"
++ " doorbell registers.\n");
++ error = -ENOMEM;
++ goto out_iounmap_ctrl;
++ }
++ phba->pci_bar4_memmap_p =
++ phba->sli4_hba.drbl_regs_memmap_p;
++ error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
++ if (error)
++ goto out_iounmap_all;
++ } else {
++ error = -ENOMEM;
+ goto out_iounmap_all;
++ }
+ }
+
+ return 0;
+diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
+index dab876c65473..fa504ba83ade 100644
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -220,6 +220,17 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd)
+ }
+ }
+
++static void scsi_eh_inc_host_failed(struct rcu_head *head)
++{
++ struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu);
++ unsigned long flags;
++
++ spin_lock_irqsave(shost->host_lock, flags);
++ shost->host_failed++;
++ scsi_eh_wakeup(shost);
++ spin_unlock_irqrestore(shost->host_lock, flags);
++}
++
+ /**
+ * scsi_eh_scmd_add - add scsi cmd to error handling.
+ * @scmd: scmd to run eh on.
+@@ -242,9 +253,12 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
+
+ scsi_eh_reset(scmd);
+ list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
+- shost->host_failed++;
+- scsi_eh_wakeup(shost);
+ spin_unlock_irqrestore(shost->host_lock, flags);
++ /*
++ * Ensure that all tasks observe the host state change before the
++ * host_failed change.
++ */
++ call_rcu(&shost->rcu, scsi_eh_inc_host_failed);
+ }
+
+ /**
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index 635cfa1f2ace..0d3696e9dddd 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -318,22 +318,39 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+ cmd->cmd_len = scsi_command_size(cmd->cmnd);
+ }
+
+-void scsi_device_unbusy(struct scsi_device *sdev)
++/*
++ * Decrement the host_busy counter and wake up the error handler if necessary.
++ * Avoid as follows that the error handler is not woken up if shost->host_busy
++ * == shost->host_failed: use call_rcu() in scsi_eh_scmd_add() in combination
++ * with an RCU read lock in this function to ensure that this function in its
++ * entirety either finishes before scsi_eh_scmd_add() increases the
++ * host_failed counter or that it notices the shost state change made by
++ * scsi_eh_scmd_add().
++ */
++static void scsi_dec_host_busy(struct Scsi_Host *shost)
+ {
+- struct Scsi_Host *shost = sdev->host;
+- struct scsi_target *starget = scsi_target(sdev);
+ unsigned long flags;
+
++ rcu_read_lock();
+ atomic_dec(&shost->host_busy);
+- if (starget->can_queue > 0)
+- atomic_dec(&starget->target_busy);
+-
+- if (unlikely(scsi_host_in_recovery(shost) &&
+- (shost->host_failed || shost->host_eh_scheduled))) {
++ if (unlikely(scsi_host_in_recovery(shost))) {
+ spin_lock_irqsave(shost->host_lock, flags);
+- scsi_eh_wakeup(shost);
++ if (shost->host_failed || shost->host_eh_scheduled)
++ scsi_eh_wakeup(shost);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ }
++ rcu_read_unlock();
++}
++
++void scsi_device_unbusy(struct scsi_device *sdev)
++{
++ struct Scsi_Host *shost = sdev->host;
++ struct scsi_target *starget = scsi_target(sdev);
++
++ scsi_dec_host_busy(shost);
++
++ if (starget->can_queue > 0)
++ atomic_dec(&starget->target_busy);
+
+ atomic_dec(&sdev->device_busy);
+ }
+@@ -1532,7 +1549,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
+ list_add_tail(&sdev->starved_entry, &shost->starved_list);
+ spin_unlock_irq(shost->host_lock);
+ out_dec:
+- atomic_dec(&shost->host_busy);
++ scsi_dec_host_busy(shost);
+ return 0;
+ }
+
+@@ -1993,7 +2010,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
+ return BLK_STS_OK;
+
+ out_dec_host_busy:
+- atomic_dec(&shost->host_busy);
++ scsi_dec_host_busy(shost);
+ out_dec_target_busy:
+ if (scsi_target(sdev)->can_queue > 0)
+ atomic_dec(&scsi_target(sdev)->target_busy);
+diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
+index db0572733712..ab30a0f5129c 100644
+--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
++++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto-adler.c
+@@ -119,6 +119,7 @@ static struct shash_alg alg = {
+ .cra_name = "adler32",
+ .cra_driver_name = "adler32-zlib",
+ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index c722cbfdc7e6..3ece1335ba84 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1451,7 +1451,7 @@ config RC32434_WDT
+
+ config INDYDOG
+ tristate "Indy/I2 Hardware Watchdog"
+- depends on SGI_HAS_INDYDOG || (MIPS && COMPILE_TEST)
++ depends on SGI_HAS_INDYDOG
+ help
+ Hardware driver for the Indy's/I2's watchdog. This is a
+ watchdog timer that will reboot the machine after a 60 second
+diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
+index cb66c2f99ff1..7a6279daa8b9 100644
+--- a/drivers/watchdog/gpio_wdt.c
++++ b/drivers/watchdog/gpio_wdt.c
+@@ -80,7 +80,8 @@ static int gpio_wdt_stop(struct watchdog_device *wdd)
+
+ if (!priv->always_running) {
+ gpio_wdt_disable(priv);
+- clear_bit(WDOG_HW_RUNNING, &wdd->status);
++ } else {
++ set_bit(WDOG_HW_RUNNING, &wdd->status);
+ }
+
+ return 0;
+diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
+index 4874b0f18650..518dfa1047cb 100644
+--- a/drivers/watchdog/imx2_wdt.c
++++ b/drivers/watchdog/imx2_wdt.c
+@@ -169,15 +169,21 @@ static int imx2_wdt_ping(struct watchdog_device *wdog)
+ return 0;
+ }
+
+-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+- unsigned int new_timeout)
++static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
++ unsigned int new_timeout)
+ {
+ struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+- wdog->timeout = new_timeout;
+-
+ regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
+ WDOG_SEC_TO_COUNT(new_timeout));
++}
++
++static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
++ unsigned int new_timeout)
++{
++ __imx2_wdt_set_timeout(wdog, new_timeout);
++
++ wdog->timeout = new_timeout;
+ return 0;
+ }
+
+@@ -371,7 +377,11 @@ static int imx2_wdt_suspend(struct device *dev)
+
+ /* The watchdog IP block is running */
+ if (imx2_wdt_is_running(wdev)) {
+- imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
++ /*
++ * Don't update wdog->timeout, we'll restore the current value
++ * during resume.
++ */
++ __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+ imx2_wdt_ping(wdog);
+ }
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index c71afd424900..5eaedff28a32 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -2101,8 +2101,15 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
+ goto out;
+ }
+
+- btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state,
+- 0);
++ ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
++ &cached_state, 0);
++ if (ret) {
++ mapping_set_error(page->mapping, ret);
++ end_extent_writepage(page, ret, page_start, page_end);
++ ClearPageChecked(page);
++ goto out;
++ }
++
+ ClearPageChecked(page);
+ set_page_dirty(page);
+ out:
+diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
+index 24a62224b24b..6154825c30e1 100644
+--- a/fs/btrfs/raid56.c
++++ b/fs/btrfs/raid56.c
+@@ -1432,14 +1432,13 @@ static int fail_bio_stripe(struct btrfs_raid_bio *rbio,
+ */
+ static void set_bio_pages_uptodate(struct bio *bio)
+ {
+- struct bio_vec bvec;
+- struct bvec_iter iter;
++ struct bio_vec *bvec;
++ int i;
+
+- if (bio_flagged(bio, BIO_CLONED))
+- bio->bi_iter = btrfs_io_bio(bio)->iter;
++ ASSERT(!bio_flagged(bio, BIO_CLONED));
+
+- bio_for_each_segment(bvec, bio, iter)
+- SetPageUptodate(bvec.bv_page);
++ bio_for_each_segment_all(bvec, bio, i)
++ SetPageUptodate(bvec->bv_page);
+ }
+
+ /*
+diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
+index 68abbb0db608..f2b0a7f124da 100644
+--- a/fs/cifs/cifsencrypt.c
++++ b/fs/cifs/cifsencrypt.c
+@@ -325,9 +325,8 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
+ {
+ int i;
+ int rc;
+- char password_with_pad[CIFS_ENCPWD_SIZE];
++ char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
+
+- memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+ if (password)
+ strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
+
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 0bfc2280436d..f7db2fedfa8c 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -1707,7 +1707,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
+ tmp_end++;
+ if (!(tmp_end < end && tmp_end[1] == delim)) {
+ /* No it is not. Set the password to NULL */
+- kfree(vol->password);
++ kzfree(vol->password);
+ vol->password = NULL;
+ break;
+ }
+@@ -1745,7 +1745,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
+ options = end;
+ }
+
+- kfree(vol->password);
++ kzfree(vol->password);
+ /* Now build new password string */
+ temp_len = strlen(value);
+ vol->password = kzalloc(temp_len+1, GFP_KERNEL);
+@@ -4235,7 +4235,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
+ reset_cifs_unix_caps(0, tcon, NULL, vol_info);
+ out:
+ kfree(vol_info->username);
+- kfree(vol_info->password);
++ kzfree(vol_info->password);
+ kfree(vol_info);
+
+ return tcon;
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index 92fdf9c35de2..7d6539a04fac 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -3488,20 +3488,18 @@ static const struct vm_operations_struct cifs_file_vm_ops = {
+
+ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+- int rc, xid;
++ int xid, rc = 0;
+ struct inode *inode = file_inode(file);
+
+ xid = get_xid();
+
+- if (!CIFS_CACHE_READ(CIFS_I(inode))) {
++ if (!CIFS_CACHE_READ(CIFS_I(inode)))
+ rc = cifs_zap_mapping(inode);
+- if (rc)
+- return rc;
+- }
+-
+- rc = generic_file_mmap(file, vma);
+- if (rc == 0)
++ if (!rc)
++ rc = generic_file_mmap(file, vma);
++ if (!rc)
+ vma->vm_ops = &cifs_file_vm_ops;
++
+ free_xid(xid);
+ return rc;
+ }
+@@ -3511,16 +3509,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
+ int rc, xid;
+
+ xid = get_xid();
++
+ rc = cifs_revalidate_file(file);
+- if (rc) {
++ if (rc)
+ cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
+ rc);
+- free_xid(xid);
+- return rc;
+- }
+- rc = generic_file_mmap(file, vma);
+- if (rc == 0)
++ if (!rc)
++ rc = generic_file_mmap(file, vma);
++ if (!rc)
+ vma->vm_ops = &cifs_file_vm_ops;
++
+ free_xid(xid);
+ return rc;
+ }
+diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
+index eea93ac15ef0..a0dbced4a45c 100644
+--- a/fs/cifs/misc.c
++++ b/fs/cifs/misc.c
+@@ -98,14 +98,11 @@ sesInfoFree(struct cifs_ses *buf_to_free)
+ kfree(buf_to_free->serverOS);
+ kfree(buf_to_free->serverDomain);
+ kfree(buf_to_free->serverNOS);
+- if (buf_to_free->password) {
+- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+- kfree(buf_to_free->password);
+- }
++ kzfree(buf_to_free->password);
+ kfree(buf_to_free->user_name);
+ kfree(buf_to_free->domainName);
+- kfree(buf_to_free->auth_key.response);
+- kfree(buf_to_free);
++ kzfree(buf_to_free->auth_key.response);
++ kzfree(buf_to_free);
+ }
+
+ struct cifs_tcon *
+@@ -136,10 +133,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
+ }
+ atomic_dec(&tconInfoAllocCount);
+ kfree(buf_to_free->nativeFileSystem);
+- if (buf_to_free->password) {
+- memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+- kfree(buf_to_free->password);
+- }
++ kzfree(buf_to_free->password);
+ kfree(buf_to_free);
+ }
+
+diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
+index 01346b8b6edb..66af1f8a13cc 100644
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -733,8 +733,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
+ }
+
+ /* check validate negotiate info response matches what we got earlier */
+- if (pneg_rsp->Dialect !=
+- cpu_to_le16(tcon->ses->server->vals->protocol_id))
++ if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
+ goto vneg_out;
+
+ if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
+diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
+index 7eae33ffa3fc..e31d6ed3ec32 100644
+--- a/fs/devpts/inode.c
++++ b/fs/devpts/inode.c
+@@ -168,11 +168,11 @@ struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi)
+ dput(path.dentry);
+ if (err) {
+ mntput(path.mnt);
+- path.mnt = ERR_PTR(err);
++ return ERR_PTR(err);
+ }
+ if (DEVPTS_SB(path.mnt->mnt_sb) != fsi) {
+ mntput(path.mnt);
+- path.mnt = ERR_PTR(-ENODEV);
++ return ERR_PTR(-ENODEV);
+ }
+ return path.mnt;
+ }
+diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
+index 9698e51656b1..d8f49c412f50 100644
+--- a/fs/kernfs/file.c
++++ b/fs/kernfs/file.c
+@@ -275,7 +275,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
+ {
+ struct kernfs_open_file *of = kernfs_of(file);
+ const struct kernfs_ops *ops;
+- size_t len;
++ ssize_t len;
+ char *buf;
+
+ if (of->atomic_write_len) {
+diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
+index d2972d537469..8c10b0562e75 100644
+--- a/fs/nfs/direct.c
++++ b/fs/nfs/direct.c
+@@ -775,10 +775,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
+
+ spin_lock(&dreq->lock);
+
+- if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
+- dreq->flags = 0;
++ if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
+ dreq->error = hdr->error;
+- }
+ if (dreq->error == 0) {
+ nfs_direct_good_bytes(dreq, hdr);
+ if (nfs_write_need_commit(hdr)) {
+diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c
+index 508126eb49f9..3db2b7464748 100644
+--- a/fs/nfs/filelayout/filelayout.c
++++ b/fs/nfs/filelayout/filelayout.c
+@@ -895,9 +895,7 @@ fl_pnfs_update_layout(struct inode *ino,
+
+ lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
+ gfp_flags);
+- if (!lseg)
+- lseg = ERR_PTR(-ENOMEM);
+- if (IS_ERR(lseg))
++ if (IS_ERR_OR_NULL(lseg))
+ goto out;
+
+ lo = NFS_I(ino)->layout;
+diff --git a/fs/nfs/io.c b/fs/nfs/io.c
+index 20fef85d2bb1..9034b4926909 100644
+--- a/fs/nfs/io.c
++++ b/fs/nfs/io.c
+@@ -99,7 +99,7 @@ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode)
+ {
+ if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
+ set_bit(NFS_INO_ODIRECT, &nfsi->flags);
+- nfs_wb_all(inode);
++ nfs_sync_mapping(inode->i_mapping);
+ }
+ }
+
+diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
+index 30426c1a1bbd..22dc30a679a0 100644
+--- a/fs/nfs/nfs4idmap.c
++++ b/fs/nfs/nfs4idmap.c
+@@ -568,9 +568,13 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
+ struct idmap_msg *im;
+ struct idmap *idmap = (struct idmap *)aux;
+ struct key *key = cons->key;
+- int ret = -ENOMEM;
++ int ret = -ENOKEY;
++
++ if (!aux)
++ goto out1;
+
+ /* msg and im are freed in idmap_pipe_destroy_msg */
++ ret = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out1;
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 14ed9791ec9c..549c916d2859 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -7668,6 +7668,22 @@ nfs4_stat_to_errno(int stat)
+ .p_name = #proc, \
+ }
+
++#if defined(CONFIG_NFS_V4_1)
++#define PROC41(proc, argtype, restype) \
++ PROC(proc, argtype, restype)
++#else
++#define PROC41(proc, argtype, restype) \
++ STUB(proc)
++#endif
++
++#if defined(CONFIG_NFS_V4_2)
++#define PROC42(proc, argtype, restype) \
++ PROC(proc, argtype, restype)
++#else
++#define PROC42(proc, argtype, restype) \
++ STUB(proc)
++#endif
++
+ const struct rpc_procinfo nfs4_procedures[] = {
+ PROC(READ, enc_read, dec_read),
+ PROC(WRITE, enc_write, dec_write),
+@@ -7688,7 +7704,6 @@ const struct rpc_procinfo nfs4_procedures[] = {
+ PROC(ACCESS, enc_access, dec_access),
+ PROC(GETATTR, enc_getattr, dec_getattr),
+ PROC(LOOKUP, enc_lookup, dec_lookup),
+- PROC(LOOKUPP, enc_lookupp, dec_lookupp),
+ PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
+ PROC(REMOVE, enc_remove, dec_remove),
+ PROC(RENAME, enc_rename, dec_rename),
+@@ -7707,33 +7722,30 @@ const struct rpc_procinfo nfs4_procedures[] = {
+ PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner),
+ PROC(SECINFO, enc_secinfo, dec_secinfo),
+ PROC(FSID_PRESENT, enc_fsid_present, dec_fsid_present),
+-#if defined(CONFIG_NFS_V4_1)
+- PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id),
+- PROC(CREATE_SESSION, enc_create_session, dec_create_session),
+- PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session),
+- PROC(SEQUENCE, enc_sequence, dec_sequence),
+- PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time),
+- PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete),
+- PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
+- PROC(LAYOUTGET, enc_layoutget, dec_layoutget),
+- PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit),
+- PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn),
+- PROC(SECINFO_NO_NAME, enc_secinfo_no_name, dec_secinfo_no_name),
+- PROC(TEST_STATEID, enc_test_stateid, dec_test_stateid),
+- PROC(FREE_STATEID, enc_free_stateid, dec_free_stateid),
++ PROC41(EXCHANGE_ID, enc_exchange_id, dec_exchange_id),
++ PROC41(CREATE_SESSION, enc_create_session, dec_create_session),
++ PROC41(DESTROY_SESSION, enc_destroy_session, dec_destroy_session),
++ PROC41(SEQUENCE, enc_sequence, dec_sequence),
++ PROC41(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time),
++ PROC41(RECLAIM_COMPLETE,enc_reclaim_complete, dec_reclaim_complete),
++ PROC41(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
++ PROC41(LAYOUTGET, enc_layoutget, dec_layoutget),
++ PROC41(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit),
++ PROC41(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn),
++ PROC41(SECINFO_NO_NAME, enc_secinfo_no_name, dec_secinfo_no_name),
++ PROC41(TEST_STATEID, enc_test_stateid, dec_test_stateid),
++ PROC41(FREE_STATEID, enc_free_stateid, dec_free_stateid),
+ STUB(GETDEVICELIST),
+- PROC(BIND_CONN_TO_SESSION,
++ PROC41(BIND_CONN_TO_SESSION,
+ enc_bind_conn_to_session, dec_bind_conn_to_session),
+- PROC(DESTROY_CLIENTID, enc_destroy_clientid, dec_destroy_clientid),
+-#endif /* CONFIG_NFS_V4_1 */
+-#ifdef CONFIG_NFS_V4_2
+- PROC(SEEK, enc_seek, dec_seek),
+- PROC(ALLOCATE, enc_allocate, dec_allocate),
+- PROC(DEALLOCATE, enc_deallocate, dec_deallocate),
+- PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats),
+- PROC(CLONE, enc_clone, dec_clone),
+- PROC(COPY, enc_copy, dec_copy),
+-#endif /* CONFIG_NFS_V4_2 */
++ PROC41(DESTROY_CLIENTID,enc_destroy_clientid, dec_destroy_clientid),
++ PROC42(SEEK, enc_seek, dec_seek),
++ PROC42(ALLOCATE, enc_allocate, dec_allocate),
++ PROC42(DEALLOCATE, enc_deallocate, dec_deallocate),
++ PROC42(LAYOUTSTATS, enc_layoutstats, dec_layoutstats),
++ PROC42(CLONE, enc_clone, dec_clone),
++ PROC42(COPY, enc_copy, dec_copy),
++ PROC(LOOKUPP, enc_lookupp, dec_lookupp),
+ };
+
+ static unsigned int nfs_version4_counts[ARRAY_SIZE(nfs4_procedures)];
+diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
+index 3bcd669a3152..5f2f852ef506 100644
+--- a/fs/nfs/pnfs.c
++++ b/fs/nfs/pnfs.c
+@@ -2237,7 +2237,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
+ nfs_pageio_reset_write_mds(desc);
+ mirror->pg_recoalesce = 1;
+ }
+- hdr->release(hdr);
++ hdr->completion_ops->completion(hdr);
+ }
+
+ static enum pnfs_try_status
+@@ -2360,7 +2360,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
+ nfs_pageio_reset_read_mds(desc);
+ mirror->pg_recoalesce = 1;
+ }
+- hdr->release(hdr);
++ hdr->completion_ops->completion(hdr);
+ }
+
+ /*
+diff --git a/fs/nfs/write.c b/fs/nfs/write.c
+index de325804941d..76da415be39a 100644
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -1836,6 +1836,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
+ set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
+ next:
+ nfs_unlock_and_release_request(req);
++ /* Latency breaker */
++ cond_resched();
+ }
+ nfss = NFS_SERVER(data->inode);
+ if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
+diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
+index d94a51dc4e32..7fa7d68baa6d 100644
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -575,8 +575,15 @@ static struct ovl_dir_cache *ovl_cache_get_impure(struct path *path)
+ return ERR_PTR(res);
+ }
+ if (list_empty(&cache->entries)) {
+- /* Good oportunity to get rid of an unnecessary "impure" flag */
+- ovl_do_removexattr(ovl_dentry_upper(dentry), OVL_XATTR_IMPURE);
++ /*
++ * A good opportunity to get rid of an unneeded "impure" flag.
++ * Removing the "impure" xattr is best effort.
++ */
++ if (!ovl_want_write(dentry)) {
++ ovl_do_removexattr(ovl_dentry_upper(dentry),
++ OVL_XATTR_IMPURE);
++ ovl_drop_write(dentry);
++ }
+ ovl_clear_flag(OVL_IMPURE, d_inode(dentry));
+ kfree(cache);
+ return NULL;
+@@ -751,10 +758,14 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
+ struct dentry *dentry = file->f_path.dentry;
+ struct file *realfile = od->realfile;
+
++ /* Nothing to sync for lower */
++ if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
++ return 0;
++
+ /*
+ * Need to check if we started out being a lower dir, but got copied up
+ */
+- if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
++ if (!od->is_upper) {
+ struct inode *inode = file_inode(file);
+
+ realfile = READ_ONCE(od->upperfile);
+diff --git a/fs/pipe.c b/fs/pipe.c
+index f0f4ab36c444..8ef7d7bef775 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -610,12 +610,17 @@ static unsigned long account_pipe_buffers(struct user_struct *user,
+
+ static bool too_many_pipe_buffers_soft(unsigned long user_bufs)
+ {
+- return pipe_user_pages_soft && user_bufs >= pipe_user_pages_soft;
++ return pipe_user_pages_soft && user_bufs > pipe_user_pages_soft;
+ }
+
+ static bool too_many_pipe_buffers_hard(unsigned long user_bufs)
+ {
+- return pipe_user_pages_hard && user_bufs >= pipe_user_pages_hard;
++ return pipe_user_pages_hard && user_bufs > pipe_user_pages_hard;
++}
++
++static bool is_unprivileged_user(void)
++{
++ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
+ }
+
+ struct pipe_inode_info *alloc_pipe_info(void)
+@@ -634,12 +639,12 @@ struct pipe_inode_info *alloc_pipe_info(void)
+
+ user_bufs = account_pipe_buffers(user, 0, pipe_bufs);
+
+- if (too_many_pipe_buffers_soft(user_bufs)) {
++ if (too_many_pipe_buffers_soft(user_bufs) && is_unprivileged_user()) {
+ user_bufs = account_pipe_buffers(user, pipe_bufs, 1);
+ pipe_bufs = 1;
+ }
+
+- if (too_many_pipe_buffers_hard(user_bufs))
++ if (too_many_pipe_buffers_hard(user_bufs) && is_unprivileged_user())
+ goto out_revert_acct;
+
+ pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer),
+@@ -1069,7 +1074,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
+ if (nr_pages > pipe->buffers &&
+ (too_many_pipe_buffers_hard(user_bufs) ||
+ too_many_pipe_buffers_soft(user_bufs)) &&
+- !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
++ is_unprivileged_user()) {
+ ret = -EPERM;
+ goto out_revert_acct;
+ }
+diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
+index 4bc85cb8be6a..e8a93bc8285d 100644
+--- a/fs/proc/kcore.c
++++ b/fs/proc/kcore.c
+@@ -512,23 +512,15 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
+ return -EFAULT;
+ } else {
+ if (kern_addr_valid(start)) {
+- unsigned long n;
+-
+ /*
+ * Using bounce buffer to bypass the
+ * hardened user copy kernel text checks.
+ */
+- memcpy(buf, (char *) start, tsz);
+- n = copy_to_user(buffer, buf, tsz);
+- /*
+- * We cannot distinguish between fault on source
+- * and fault on destination. When this happens
+- * we clear too and hope it will trigger the
+- * EFAULT again.
+- */
+- if (n) {
+- if (clear_user(buffer + tsz - n,
+- n))
++ if (probe_kernel_read(buf, (void *) start, tsz)) {
++ if (clear_user(buffer, tsz))
++ return -EFAULT;
++ } else {
++ if (copy_to_user(buffer, buf, tsz))
+ return -EFAULT;
+ }
+ } else {
+diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
+index 417fe0b29f23..ef820f803176 100644
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -1216,10 +1216,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
+ ostr.len = disk_link.len;
+
+ err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+- if (err) {
+- kfree(sd);
++ if (err)
+ goto out_inode;
+- }
+
+ sd->len = cpu_to_le16(ostr.len);
+ disk_link.name = (char *)sd;
+@@ -1251,11 +1249,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
+ goto out_cancel;
+ mutex_unlock(&dir_ui->ui_mutex);
+
+- ubifs_release_budget(c, &req);
+ insert_inode_hash(inode);
+ d_instantiate(dentry, inode);
+- fscrypt_free_filename(&nm);
+- return 0;
++ err = 0;
++ goto out_fname;
+
+ out_cancel:
+ dir->i_size -= sz_change;
+@@ -1268,6 +1265,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
+ fscrypt_free_filename(&nm);
+ out_budg:
+ ubifs_release_budget(c, &req);
++ kfree(sd);
+ return err;
+ }
+
+diff --git a/include/crypto/hash.h b/include/crypto/hash.h
+index b5727bcd2336..74827781593c 100644
+--- a/include/crypto/hash.h
++++ b/include/crypto/hash.h
+@@ -205,7 +205,6 @@ struct crypto_ahash {
+ unsigned int keylen);
+
+ unsigned int reqsize;
+- bool has_setkey;
+ struct crypto_tfm base;
+ };
+
+@@ -405,11 +404,6 @@ static inline void *ahash_request_ctx(struct ahash_request *req)
+ int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen);
+
+-static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm)
+-{
+- return tfm->has_setkey;
+-}
+-
+ /**
+ * crypto_ahash_finup() - update and finalize message digest
+ * @req: reference to the ahash_request handle that holds all information
+@@ -481,7 +475,12 @@ static inline int crypto_ahash_export(struct ahash_request *req, void *out)
+ */
+ static inline int crypto_ahash_import(struct ahash_request *req, const void *in)
+ {
+- return crypto_ahash_reqtfm(req)->import(req, in);
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++
++ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
++ return tfm->import(req, in);
+ }
+
+ /**
+@@ -498,7 +497,12 @@ static inline int crypto_ahash_import(struct ahash_request *req, const void *in)
+ */
+ static inline int crypto_ahash_init(struct ahash_request *req)
+ {
+- return crypto_ahash_reqtfm(req)->init(req);
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++
++ if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
++ return tfm->init(req);
+ }
+
+ /**
+@@ -851,7 +855,12 @@ static inline int crypto_shash_export(struct shash_desc *desc, void *out)
+ */
+ static inline int crypto_shash_import(struct shash_desc *desc, const void *in)
+ {
+- return crypto_shash_alg(desc->tfm)->import(desc, in);
++ struct crypto_shash *tfm = desc->tfm;
++
++ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
++ return crypto_shash_alg(tfm)->import(desc, in);
+ }
+
+ /**
+@@ -867,7 +876,12 @@ static inline int crypto_shash_import(struct shash_desc *desc, const void *in)
+ */
+ static inline int crypto_shash_init(struct shash_desc *desc)
+ {
+- return crypto_shash_alg(desc->tfm)->init(desc);
++ struct crypto_shash *tfm = desc->tfm;
++
++ if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
++ return -ENOKEY;
++
++ return crypto_shash_alg(tfm)->init(desc);
+ }
+
+ /**
+diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
+index c2bae8da642c..27040a46d50a 100644
+--- a/include/crypto/internal/hash.h
++++ b/include/crypto/internal/hash.h
+@@ -90,6 +90,8 @@ static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+ return alg->setkey != shash_no_setkey;
+ }
+
++bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
++
+ int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
+ struct hash_alg_common *alg,
+ struct crypto_instance *inst);
+diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h
+index c65567d01e8e..f718a19da82f 100644
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -31,8 +31,6 @@ struct poly1305_desc_ctx {
+ };
+
+ int crypto_poly1305_init(struct shash_desc *desc);
+-int crypto_poly1305_setkey(struct crypto_shash *tfm,
+- const u8 *key, unsigned int keylen);
+ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+ const u8 *src, unsigned int srclen);
+ int crypto_poly1305_update(struct shash_desc *desc,
+diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
+new file mode 100644
+index 000000000000..e518e4e3dfb5
+--- /dev/null
++++ b/include/kvm/arm_psci.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2012,2013 - ARM Ltd
++ * Author: Marc Zyngier <marc.zyngier@arm.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __KVM_ARM_PSCI_H__
++#define __KVM_ARM_PSCI_H__
++
++#include <linux/kvm_host.h>
++#include <uapi/linux/psci.h>
++
++#define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1)
++#define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2)
++#define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0)
++
++#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_0
++
++/*
++ * We need the KVM pointer independently from the vcpu as we can call
++ * this from HYP, and need to apply kern_hyp_va on it...
++ */
++static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
++{
++ /*
++ * Our PSCI implementation stays the same across versions from
++ * v0.2 onward, only adding the few mandatory functions (such
++ * as FEATURES with 1.0) that are required by newer
++ * revisions. It is thus safe to return the latest.
++ */
++ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
++ return KVM_ARM_PSCI_LATEST;
++
++ return KVM_ARM_PSCI_0_1;
++}
++
++
++int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
++
++#endif /* __KVM_ARM_PSCI_H__ */
+diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
+index 4c5bca38c653..a031897fca76 100644
+--- a/include/linux/arm-smccc.h
++++ b/include/linux/arm-smccc.h
+@@ -14,14 +14,16 @@
+ #ifndef __LINUX_ARM_SMCCC_H
+ #define __LINUX_ARM_SMCCC_H
+
++#include <uapi/linux/const.h>
++
+ /*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+-#define ARM_SMCCC_STD_CALL 0
+-#define ARM_SMCCC_FAST_CALL 1
++#define ARM_SMCCC_STD_CALL _AC(0,U)
++#define ARM_SMCCC_FAST_CALL _AC(1,U)
+ #define ARM_SMCCC_TYPE_SHIFT 31
+
+ #define ARM_SMCCC_SMC_32 0
+@@ -60,6 +62,24 @@
+ #define ARM_SMCCC_QUIRK_NONE 0
+ #define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */
+
++#define ARM_SMCCC_VERSION_1_0 0x10000
++#define ARM_SMCCC_VERSION_1_1 0x10001
++
++#define ARM_SMCCC_VERSION_FUNC_ID \
++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
++ ARM_SMCCC_SMC_32, \
++ 0, 0)
++
++#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID \
++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
++ ARM_SMCCC_SMC_32, \
++ 0, 1)
++
++#define ARM_SMCCC_ARCH_WORKAROUND_1 \
++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
++ ARM_SMCCC_SMC_32, \
++ 0, 0x8000)
++
+ #ifndef __ASSEMBLY__
+
+ #include <linux/linkage.h>
+@@ -130,5 +150,146 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
+
+ #define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
+
++/* SMCCC v1.1 implementation madness follows */
++#ifdef CONFIG_ARM64
++
++#define SMCCC_SMC_INST "smc #0"
++#define SMCCC_HVC_INST "hvc #0"
++
++#elif defined(CONFIG_ARM)
++#include <asm/opcodes-sec.h>
++#include <asm/opcodes-virt.h>
++
++#define SMCCC_SMC_INST __SMC(0)
++#define SMCCC_HVC_INST __HVC(0)
++
++#endif
++
++#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
++
++#define __count_args(...) \
++ ___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
++
++#define __constraint_write_0 \
++ "+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3)
++#define __constraint_write_1 \
++ "+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3)
++#define __constraint_write_2 \
++ "+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3)
++#define __constraint_write_3 \
++ "+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
++#define __constraint_write_4 __constraint_write_3
++#define __constraint_write_5 __constraint_write_4
++#define __constraint_write_6 __constraint_write_5
++#define __constraint_write_7 __constraint_write_6
++
++#define __constraint_read_0
++#define __constraint_read_1
++#define __constraint_read_2
++#define __constraint_read_3
++#define __constraint_read_4 "r" (r4)
++#define __constraint_read_5 __constraint_read_4, "r" (r5)
++#define __constraint_read_6 __constraint_read_5, "r" (r6)
++#define __constraint_read_7 __constraint_read_6, "r" (r7)
++
++#define __declare_arg_0(a0, res) \
++ struct arm_smccc_res *___res = res; \
++ register u32 r0 asm("r0") = a0; \
++ register unsigned long r1 asm("r1"); \
++ register unsigned long r2 asm("r2"); \
++ register unsigned long r3 asm("r3")
++
++#define __declare_arg_1(a0, a1, res) \
++ struct arm_smccc_res *___res = res; \
++ register u32 r0 asm("r0") = a0; \
++ register typeof(a1) r1 asm("r1") = a1; \
++ register unsigned long r2 asm("r2"); \
++ register unsigned long r3 asm("r3")
++
++#define __declare_arg_2(a0, a1, a2, res) \
++ struct arm_smccc_res *___res = res; \
++ register u32 r0 asm("r0") = a0; \
++ register typeof(a1) r1 asm("r1") = a1; \
++ register typeof(a2) r2 asm("r2") = a2; \
++ register unsigned long r3 asm("r3")
++
++#define __declare_arg_3(a0, a1, a2, a3, res) \
++ struct arm_smccc_res *___res = res; \
++ register u32 r0 asm("r0") = a0; \
++ register typeof(a1) r1 asm("r1") = a1; \
++ register typeof(a2) r2 asm("r2") = a2; \
++ register typeof(a3) r3 asm("r3") = a3
++
++#define __declare_arg_4(a0, a1, a2, a3, a4, res) \
++ __declare_arg_3(a0, a1, a2, a3, res); \
++ register typeof(a4) r4 asm("r4") = a4
++
++#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res) \
++ __declare_arg_4(a0, a1, a2, a3, a4, res); \
++ register typeof(a5) r5 asm("r5") = a5
++
++#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res) \
++ __declare_arg_5(a0, a1, a2, a3, a4, a5, res); \
++ register typeof(a6) r6 asm("r6") = a6
++
++#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res) \
++ __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res); \
++ register typeof(a7) r7 asm("r7") = a7
++
++#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__)
++#define __declare_args(count, ...) ___declare_args(count, __VA_ARGS__)
++
++#define ___constraints(count) \
++ : __constraint_write_ ## count \
++ : __constraint_read_ ## count \
++ : "memory"
++#define __constraints(count) ___constraints(count)
++
++/*
++ * We have an output list that is not necessarily used, and GCC feels
++ * entitled to optimise the whole sequence away. "volatile" is what
++ * makes it stick.
++ */
++#define __arm_smccc_1_1(inst, ...) \
++ do { \
++ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \
++ asm volatile(inst "\n" \
++ __constraints(__count_args(__VA_ARGS__))); \
++ if (___res) \
++ *___res = (typeof(*___res)){r0, r1, r2, r3}; \
++ } while (0)
++
++/*
++ * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call
++ *
++ * This is a variadic macro taking one to eight source arguments, and
++ * an optional return structure.
++ *
++ * @a0-a7: arguments passed in registers 0 to 7
++ * @res: result values from registers 0 to 3
++ *
++ * This macro is used to make SMC calls following SMC Calling Convention v1.1.
++ * The content of the supplied param are copied to registers 0 to 7 prior
++ * to the SMC instruction. The return values are updated with the content
++ * from register 0 to 3 on return from the SMC instruction if not NULL.
++ */
++#define arm_smccc_1_1_smc(...) __arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)
++
++/*
++ * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call
++ *
++ * This is a variadic macro taking one to eight source arguments, and
++ * an optional return structure.
++ *
++ * @a0-a7: arguments passed in registers 0 to 7
++ * @res: result values from registers 0 to 3
++ *
++ * This macro is used to make HVC calls following SMC Calling Convention v1.1.
++ * The content of the supplied param are copied to registers 0 to 7 prior
++ * to the HVC instruction. The return values are updated with the content
++ * from register 0 to 3 on return from the HVC instruction if not NULL.
++ */
++#define arm_smccc_1_1_hvc(...) __arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)
++
+ #endif /*__ASSEMBLY__*/
+ #endif /*__LINUX_ARM_SMCCC_H*/
+diff --git a/include/linux/crypto.h b/include/linux/crypto.h
+index 84da9978e951..cc36484d29e1 100644
+--- a/include/linux/crypto.h
++++ b/include/linux/crypto.h
+@@ -105,9 +105,17 @@
+ */
+ #define CRYPTO_ALG_INTERNAL 0x00002000
+
++/*
++ * Set if the algorithm has a ->setkey() method but can be used without
++ * calling it first, i.e. there is a default key.
++ */
++#define CRYPTO_ALG_OPTIONAL_KEY 0x00004000
++
+ /*
+ * Transform masks and values (for crt_flags).
+ */
++#define CRYPTO_TFM_NEED_KEY 0x00000001
++
+ #define CRYPTO_TFM_REQ_MASK 0x000fff00
+ #define CRYPTO_TFM_RES_MASK 0xfff00000
+
+diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
+index 3aa56e3104bb..b5b43f94f311 100644
+--- a/include/linux/mtd/map.h
++++ b/include/linux/mtd/map.h
+@@ -270,75 +270,67 @@ void map_destroy(struct mtd_info *mtd);
+ #define INVALIDATE_CACHED_RANGE(map, from, size) \
+ do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
+
+-
+-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
+-{
+- int i;
+-
+- for (i = 0; i < map_words(map); i++) {
+- if (val1.x[i] != val2.x[i])
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
+-{
+- map_word r;
+- int i;
+-
+- for (i = 0; i < map_words(map); i++)
+- r.x[i] = val1.x[i] & val2.x[i];
+-
+- return r;
+-}
+-
+-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
+-{
+- map_word r;
+- int i;
+-
+- for (i = 0; i < map_words(map); i++)
+- r.x[i] = val1.x[i] & ~val2.x[i];
+-
+- return r;
+-}
+-
+-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
+-{
+- map_word r;
+- int i;
+-
+- for (i = 0; i < map_words(map); i++)
+- r.x[i] = val1.x[i] | val2.x[i];
+-
+- return r;
+-}
+-
+-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
+-{
+- int i;
+-
+- for (i = 0; i < map_words(map); i++) {
+- if ((val1.x[i] & val2.x[i]) != val3.x[i])
+- return 0;
+- }
+-
+- return 1;
+-}
+-
+-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
+-{
+- int i;
+-
+- for (i = 0; i < map_words(map); i++) {
+- if (val1.x[i] & val2.x[i])
+- return 1;
+- }
+-
+- return 0;
+-}
++#define map_word_equal(map, val1, val2) \
++({ \
++ int i, ret = 1; \
++ for (i = 0; i < map_words(map); i++) \
++ if ((val1).x[i] != (val2).x[i]) { \
++ ret = 0; \
++ break; \
++ } \
++ ret; \
++})
++
++#define map_word_and(map, val1, val2) \
++({ \
++ map_word r; \
++ int i; \
++ for (i = 0; i < map_words(map); i++) \
++ r.x[i] = (val1).x[i] & (val2).x[i]; \
++ r; \
++})
++
++#define map_word_clr(map, val1, val2) \
++({ \
++ map_word r; \
++ int i; \
++ for (i = 0; i < map_words(map); i++) \
++ r.x[i] = (val1).x[i] & ~(val2).x[i]; \
++ r; \
++})
++
++#define map_word_or(map, val1, val2) \
++({ \
++ map_word r; \
++ int i; \
++ for (i = 0; i < map_words(map); i++) \
++ r.x[i] = (val1).x[i] | (val2).x[i]; \
++ r; \
++})
++
++#define map_word_andequal(map, val1, val2, val3) \
++({ \
++ int i, ret = 1; \
++ for (i = 0; i < map_words(map); i++) { \
++ if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) { \
++ ret = 0; \
++ break; \
++ } \
++ } \
++ ret; \
++})
++
++#define map_word_bitsset(map, val1, val2) \
++({ \
++ int i, ret = 0; \
++ for (i = 0; i < map_words(map); i++) { \
++ if ((val1).x[i] & (val2).x[i]) { \
++ ret = 1; \
++ break; \
++ } \
++ } \
++ ret; \
++})
+
+ static inline map_word map_word_load(struct map_info *map, const void *ptr)
+ {
+diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
+index 47adac640191..57ffaa20d564 100644
+--- a/include/linux/nfs4.h
++++ b/include/linux/nfs4.h
+@@ -457,7 +457,12 @@ enum lock_type4 {
+
+ #define NFS4_DEBUG 1
+
+-/* Index of predefined Linux client operations */
++/*
++ * Index of predefined Linux client operations
++ *
++ * To ensure that /proc/net/rpc/nfs remains correctly ordered, please
++ * append only to this enum when adding new client operations.
++ */
+
+ enum {
+ NFSPROC4_CLNT_NULL = 0, /* Unused */
+@@ -480,7 +485,6 @@ enum {
+ NFSPROC4_CLNT_ACCESS,
+ NFSPROC4_CLNT_GETATTR,
+ NFSPROC4_CLNT_LOOKUP,
+- NFSPROC4_CLNT_LOOKUPP,
+ NFSPROC4_CLNT_LOOKUP_ROOT,
+ NFSPROC4_CLNT_REMOVE,
+ NFSPROC4_CLNT_RENAME,
+@@ -500,7 +504,6 @@ enum {
+ NFSPROC4_CLNT_SECINFO,
+ NFSPROC4_CLNT_FSID_PRESENT,
+
+- /* nfs41 */
+ NFSPROC4_CLNT_EXCHANGE_ID,
+ NFSPROC4_CLNT_CREATE_SESSION,
+ NFSPROC4_CLNT_DESTROY_SESSION,
+@@ -518,13 +521,14 @@ enum {
+ NFSPROC4_CLNT_BIND_CONN_TO_SESSION,
+ NFSPROC4_CLNT_DESTROY_CLIENTID,
+
+- /* nfs42 */
+ NFSPROC4_CLNT_SEEK,
+ NFSPROC4_CLNT_ALLOCATE,
+ NFSPROC4_CLNT_DEALLOCATE,
+ NFSPROC4_CLNT_LAYOUTSTATS,
+ NFSPROC4_CLNT_CLONE,
+ NFSPROC4_CLNT_COPY,
++
++ NFSPROC4_CLNT_LOOKUPP,
+ };
+
+ /* nfs41 types */
+diff --git a/include/linux/psci.h b/include/linux/psci.h
+index bdea1cb5e1db..347077cf19c6 100644
+--- a/include/linux/psci.h
++++ b/include/linux/psci.h
+@@ -25,7 +25,19 @@ bool psci_tos_resident_on(int cpu);
+ int psci_cpu_init_idle(unsigned int cpu);
+ int psci_cpu_suspend_enter(unsigned long index);
+
++enum psci_conduit {
++ PSCI_CONDUIT_NONE,
++ PSCI_CONDUIT_SMC,
++ PSCI_CONDUIT_HVC,
++};
++
++enum smccc_version {
++ SMCCC_VERSION_1_0,
++ SMCCC_VERSION_1_1,
++};
++
+ struct psci_operations {
++ u32 (*get_version)(void);
+ int (*cpu_suspend)(u32 state, unsigned long entry_point);
+ int (*cpu_off)(u32 state);
+ int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
+@@ -33,6 +45,8 @@ struct psci_operations {
+ int (*affinity_info)(unsigned long target_affinity,
+ unsigned long lowest_affinity_level);
+ int (*migrate_info_type)(void);
++ enum psci_conduit conduit;
++ enum smccc_version smccc_version;
+ };
+
+ extern struct psci_operations psci_ops;
+diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
+index a8b7bf879ced..1a1df0d21ee3 100644
+--- a/include/scsi/scsi_host.h
++++ b/include/scsi/scsi_host.h
+@@ -571,6 +571,8 @@ struct Scsi_Host {
+ struct blk_mq_tag_set tag_set;
+ };
+
++ struct rcu_head rcu;
++
+ atomic_t host_busy; /* commands actually active on low-level */
+ atomic_t host_blocked;
+
+diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
+index 760e52a9640f..b3bcabe380da 100644
+--- a/include/uapi/linux/psci.h
++++ b/include/uapi/linux/psci.h
+@@ -88,6 +88,9 @@
+ (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
+ #define PSCI_VERSION_MINOR(ver) \
+ ((ver) & PSCI_VERSION_MINOR_MASK)
++#define PSCI_VERSION(maj, min) \
++ ((((maj) << PSCI_VERSION_MAJOR_SHIFT) & PSCI_VERSION_MAJOR_MASK) | \
++ ((min) & PSCI_VERSION_MINOR_MASK))
+
+ /* PSCI features decoding (>=1.0) */
+ #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1
+diff --git a/kernel/async.c b/kernel/async.c
+index 2cbd3dd5940d..a893d6170944 100644
+--- a/kernel/async.c
++++ b/kernel/async.c
+@@ -84,20 +84,24 @@ static atomic_t entry_count;
+
+ static async_cookie_t lowest_in_progress(struct async_domain *domain)
+ {
+- struct list_head *pending;
++ struct async_entry *first = NULL;
+ async_cookie_t ret = ASYNC_COOKIE_MAX;
+ unsigned long flags;
+
+ spin_lock_irqsave(&async_lock, flags);
+
+- if (domain)
+- pending = &domain->pending;
+- else
+- pending = &async_global_pending;
++ if (domain) {
++ if (!list_empty(&domain->pending))
++ first = list_first_entry(&domain->pending,
++ struct async_entry, domain_list);
++ } else {
++ if (!list_empty(&async_global_pending))
++ first = list_first_entry(&async_global_pending,
++ struct async_entry, global_list);
++ }
+
+- if (!list_empty(pending))
+- ret = list_first_entry(pending, struct async_entry,
+- domain_list)->cookie;
++ if (first)
++ ret = first->cookie;
+
+ spin_unlock_irqrestore(&async_lock, flags);
+ return ret;
+diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
+index 5033b66d2753..7a577bd989a4 100644
+--- a/kernel/rcu/update.c
++++ b/kernel/rcu/update.c
+@@ -421,11 +421,13 @@ void init_rcu_head(struct rcu_head *head)
+ {
+ debug_object_init(head, &rcuhead_debug_descr);
+ }
++EXPORT_SYMBOL_GPL(init_rcu_head);
+
+ void destroy_rcu_head(struct rcu_head *head)
+ {
+ debug_object_free(head, &rcuhead_debug_descr);
+ }
++EXPORT_SYMBOL_GPL(destroy_rcu_head);
+
+ static bool rcuhead_is_static_object(void *addr)
+ {
+diff --git a/kernel/relay.c b/kernel/relay.c
+index 39a9dfc69486..55da824f4adc 100644
+--- a/kernel/relay.c
++++ b/kernel/relay.c
+@@ -611,7 +611,6 @@ struct rchan *relay_open(const char *base_filename,
+
+ kref_put(&chan->kref, relay_destroy_channel);
+ mutex_unlock(&relay_channels_mutex);
+- kfree(chan);
+ return NULL;
+ }
+ EXPORT_SYMBOL_GPL(relay_open);
+diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
+index 7464c5c4de46..298f62b8662d 100644
+--- a/kernel/sched/rt.c
++++ b/kernel/sched/rt.c
+@@ -1907,9 +1907,8 @@ static void push_rt_tasks(struct rq *rq)
+ * the rt_loop_next will cause the iterator to perform another scan.
+ *
+ */
+-static int rto_next_cpu(struct rq *rq)
++static int rto_next_cpu(struct root_domain *rd)
+ {
+- struct root_domain *rd = rq->rd;
+ int next;
+ int cpu;
+
+@@ -1985,19 +1984,24 @@ static void tell_cpu_to_push(struct rq *rq)
+ * Otherwise it is finishing up and an ipi needs to be sent.
+ */
+ if (rq->rd->rto_cpu < 0)
+- cpu = rto_next_cpu(rq);
++ cpu = rto_next_cpu(rq->rd);
+
+ raw_spin_unlock(&rq->rd->rto_lock);
+
+ rto_start_unlock(&rq->rd->rto_loop_start);
+
+- if (cpu >= 0)
++ if (cpu >= 0) {
++ /* Make sure the rd does not get freed while pushing */
++ sched_get_rd(rq->rd);
+ irq_work_queue_on(&rq->rd->rto_push_work, cpu);
++ }
+ }
+
+ /* Called from hardirq context */
+ void rto_push_irq_work_func(struct irq_work *work)
+ {
++ struct root_domain *rd =
++ container_of(work, struct root_domain, rto_push_work);
+ struct rq *rq;
+ int cpu;
+
+@@ -2013,18 +2017,20 @@ void rto_push_irq_work_func(struct irq_work *work)
+ raw_spin_unlock(&rq->lock);
+ }
+
+- raw_spin_lock(&rq->rd->rto_lock);
++ raw_spin_lock(&rd->rto_lock);
+
+ /* Pass the IPI to the next rt overloaded queue */
+- cpu = rto_next_cpu(rq);
++ cpu = rto_next_cpu(rd);
+
+- raw_spin_unlock(&rq->rd->rto_lock);
++ raw_spin_unlock(&rd->rto_lock);
+
+- if (cpu < 0)
++ if (cpu < 0) {
++ sched_put_rd(rd);
+ return;
++ }
+
+ /* Try the next RT overloaded CPU */
+- irq_work_queue_on(&rq->rd->rto_push_work, cpu);
++ irq_work_queue_on(&rd->rto_push_work, cpu);
+ }
+ #endif /* HAVE_RT_PUSH_IPI */
+
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index b732e779fe7d..307c35d33660 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -661,6 +661,8 @@ extern struct mutex sched_domains_mutex;
+ extern void init_defrootdomain(void);
+ extern int sched_init_domains(const struct cpumask *cpu_map);
+ extern void rq_attach_root(struct rq *rq, struct root_domain *rd);
++extern void sched_get_rd(struct root_domain *rd);
++extern void sched_put_rd(struct root_domain *rd);
+
+ #ifdef HAVE_RT_PUSH_IPI
+ extern void rto_push_irq_work_func(struct irq_work *work);
+diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
+index 093f2ceba2e2..659e075ef70b 100644
+--- a/kernel/sched/topology.c
++++ b/kernel/sched/topology.c
+@@ -258,6 +258,19 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)
+ call_rcu_sched(&old_rd->rcu, free_rootdomain);
+ }
+
++void sched_get_rd(struct root_domain *rd)
++{
++ atomic_inc(&rd->refcount);
++}
++
++void sched_put_rd(struct root_domain *rd)
++{
++ if (!atomic_dec_and_test(&rd->refcount))
++ return;
++
++ call_rcu_sched(&rd->rcu, free_rootdomain);
++}
++
+ static int init_rootdomain(struct root_domain *rd)
+ {
+ if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL))
+diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
+index 98feab7933c7..929ecb7d6b78 100644
+--- a/kernel/sched/wait.c
++++ b/kernel/sched/wait.c
+@@ -27,7 +27,7 @@ void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq
+
+ wq_entry->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&wq_head->lock, flags);
+- __add_wait_queue_entry_tail(wq_head, wq_entry);
++ __add_wait_queue(wq_head, wq_entry);
+ spin_unlock_irqrestore(&wq_head->lock, flags);
+ }
+ EXPORT_SYMBOL(add_wait_queue);
+diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
+index 8319e09e15b9..7379bcf3baa0 100644
+--- a/kernel/trace/ftrace.c
++++ b/kernel/trace/ftrace.c
+@@ -4488,7 +4488,6 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
+ func_g.type = filter_parse_regex(glob, strlen(glob),
+ &func_g.search, &not);
+ func_g.len = strlen(func_g.search);
+- func_g.search = glob;
+
+ /* we do not support '!' for function probes */
+ if (WARN_ON(not))
+diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
+index ff21b4dbb392..00cb02daeddd 100644
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -217,7 +217,7 @@ config ENABLE_MUST_CHECK
+ config FRAME_WARN
+ int "Warn for stack frames larger than (needs gcc 4.4)"
+ range 0 8192
+- default 0 if KASAN
++ default 3072 if KASAN_EXTRA
+ default 2048 if GCC_PLUGIN_LATENT_ENTROPY
+ default 1280 if (!64BIT && PARISC)
+ default 1024 if (!64BIT && !PARISC)
+diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
+index bd38aab05929..3d35d062970d 100644
+--- a/lib/Kconfig.kasan
++++ b/lib/Kconfig.kasan
+@@ -20,6 +20,17 @@ config KASAN
+ Currently CONFIG_KASAN doesn't work with CONFIG_DEBUG_SLAB
+ (the resulting kernel does not boot).
+
++config KASAN_EXTRA
++ bool "KAsan: extra checks"
++ depends on KASAN && DEBUG_KERNEL && !COMPILE_TEST
++ help
++ This enables further checks in the kernel address sanitizer, for now
++ it only includes the address-use-after-scope check that can lead
++ to excessive kernel stack usage, frame size warnings and longer
++ compile time.
++ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 has more
++
++
+ choice
+ prompt "Instrumentation type"
+ depends on KASAN
+diff --git a/lib/ubsan.c b/lib/ubsan.c
+index fb0409df1bcf..50d1d5c25deb 100644
+--- a/lib/ubsan.c
++++ b/lib/ubsan.c
+@@ -265,14 +265,14 @@ void __ubsan_handle_divrem_overflow(struct overflow_data *data,
+ }
+ EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
+
+-static void handle_null_ptr_deref(struct type_mismatch_data *data)
++static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
+ {
+ unsigned long flags;
+
+- if (suppress_report(&data->location))
++ if (suppress_report(data->location))
+ return;
+
+- ubsan_prologue(&data->location, &flags);
++ ubsan_prologue(data->location, &flags);
+
+ pr_err("%s null pointer of type %s\n",
+ type_check_kinds[data->type_check_kind],
+@@ -281,15 +281,15 @@ static void handle_null_ptr_deref(struct type_mismatch_data *data)
+ ubsan_epilogue(&flags);
+ }
+
+-static void handle_missaligned_access(struct type_mismatch_data *data,
++static void handle_misaligned_access(struct type_mismatch_data_common *data,
+ unsigned long ptr)
+ {
+ unsigned long flags;
+
+- if (suppress_report(&data->location))
++ if (suppress_report(data->location))
+ return;
+
+- ubsan_prologue(&data->location, &flags);
++ ubsan_prologue(data->location, &flags);
+
+ pr_err("%s misaligned address %p for type %s\n",
+ type_check_kinds[data->type_check_kind],
+@@ -299,15 +299,15 @@ static void handle_missaligned_access(struct type_mismatch_data *data,
+ ubsan_epilogue(&flags);
+ }
+
+-static void handle_object_size_mismatch(struct type_mismatch_data *data,
++static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
+ unsigned long ptr)
+ {
+ unsigned long flags;
+
+- if (suppress_report(&data->location))
++ if (suppress_report(data->location))
+ return;
+
+- ubsan_prologue(&data->location, &flags);
++ ubsan_prologue(data->location, &flags);
+ pr_err("%s address %p with insufficient space\n",
+ type_check_kinds[data->type_check_kind],
+ (void *) ptr);
+@@ -315,19 +315,47 @@ static void handle_object_size_mismatch(struct type_mismatch_data *data,
+ ubsan_epilogue(&flags);
+ }
+
+-void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
++static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
+ unsigned long ptr)
+ {
+
+ if (!ptr)
+ handle_null_ptr_deref(data);
+ else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
+- handle_missaligned_access(data, ptr);
++ handle_misaligned_access(data, ptr);
+ else
+ handle_object_size_mismatch(data, ptr);
+ }
++
++void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
++ unsigned long ptr)
++{
++ struct type_mismatch_data_common common_data = {
++ .location = &data->location,
++ .type = data->type,
++ .alignment = data->alignment,
++ .type_check_kind = data->type_check_kind
++ };
++
++ ubsan_type_mismatch_common(&common_data, ptr);
++}
+ EXPORT_SYMBOL(__ubsan_handle_type_mismatch);
+
++void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
++ unsigned long ptr)
++{
++
++ struct type_mismatch_data_common common_data = {
++ .location = &data->location,
++ .type = data->type,
++ .alignment = 1UL << data->log_alignment,
++ .type_check_kind = data->type_check_kind
++ };
++
++ ubsan_type_mismatch_common(&common_data, ptr);
++}
++EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
++
+ void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
+ {
+ unsigned long flags;
+diff --git a/lib/ubsan.h b/lib/ubsan.h
+index 88f23557edbe..7e30b26497e0 100644
+--- a/lib/ubsan.h
++++ b/lib/ubsan.h
+@@ -37,6 +37,20 @@ struct type_mismatch_data {
+ unsigned char type_check_kind;
+ };
+
++struct type_mismatch_data_v1 {
++ struct source_location location;
++ struct type_descriptor *type;
++ unsigned char log_alignment;
++ unsigned char type_check_kind;
++};
++
++struct type_mismatch_data_common {
++ struct source_location *location;
++ struct type_descriptor *type;
++ unsigned long alignment;
++ unsigned char type_check_kind;
++};
++
+ struct nonnull_arg_data {
+ struct source_location location;
+ struct source_location attr_location;
+diff --git a/net/dccp/proto.c b/net/dccp/proto.c
+index b68168fcc06a..9d43c1f40274 100644
+--- a/net/dccp/proto.c
++++ b/net/dccp/proto.c
+@@ -259,6 +259,7 @@ int dccp_disconnect(struct sock *sk, int flags)
+ {
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct inet_sock *inet = inet_sk(sk);
++ struct dccp_sock *dp = dccp_sk(sk);
+ int err = 0;
+ const int old_state = sk->sk_state;
+
+@@ -278,6 +279,10 @@ int dccp_disconnect(struct sock *sk, int flags)
+ sk->sk_err = ECONNRESET;
+
+ dccp_clear_xmit_timers(sk);
++ ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
++ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
++ dp->dccps_hc_rx_ccid = NULL;
++ dp->dccps_hc_tx_ccid = NULL;
+
+ __skb_queue_purge(&sk->sk_receive_queue);
+ __skb_queue_purge(&sk->sk_write_queue);
+diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
+index 1ce7115aa499..97a56c0b565a 100644
+--- a/scripts/Makefile.kasan
++++ b/scripts/Makefile.kasan
+@@ -30,5 +30,10 @@ else
+ endif
+ endif
+
++ifdef CONFIG_KASAN_EXTRA
+ CFLAGS_KASAN += $(call cc-option, -fsanitize-address-use-after-scope)
+ endif
++
++CFLAGS_KASAN_NOSANITIZE := -fno-builtin
++
++endif
+diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
+index 04b5633df1cf..0b46136a91a8 100644
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -128,7 +128,7 @@ endif
+ ifeq ($(CONFIG_KASAN),y)
+ _c_flags += $(if $(patsubst n%,, \
+ $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
+- $(CFLAGS_KASAN))
++ $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))
+ endif
+
+ ifeq ($(CONFIG_UBSAN),y)
+diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
+index e7d766d56c8e..55859c5b456f 100644
+--- a/sound/soc/intel/skylake/skl-nhlt.c
++++ b/sound/soc/intel/skylake/skl-nhlt.c
+@@ -41,7 +41,8 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
+ obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL);
+ if (obj && obj->type == ACPI_TYPE_BUFFER) {
+ nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
+- nhlt_table = (struct nhlt_acpi_table *)
++ if (nhlt_ptr->length)
++ nhlt_table = (struct nhlt_acpi_table *)
+ memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
+ MEMREMAP_WB);
+ ACPI_FREE(obj);
+diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
+index b6590467fd14..66fc13a2396a 100644
+--- a/sound/soc/rockchip/rockchip_i2s.c
++++ b/sound/soc/rockchip/rockchip_i2s.c
+@@ -504,6 +504,7 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
+ case I2S_INTCR:
+ case I2S_XFER:
+ case I2S_CLR:
++ case I2S_TXDR:
+ case I2S_RXDR:
+ case I2S_FIFOLR:
+ case I2S_INTSR:
+@@ -518,6 +519,9 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
+ switch (reg) {
+ case I2S_INTSR:
+ case I2S_CLR:
++ case I2S_FIFOLR:
++ case I2S_TXDR:
++ case I2S_RXDR:
+ return true;
+ default:
+ return false;
+@@ -527,6 +531,8 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
+ static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
+ {
+ switch (reg) {
++ case I2S_RXDR:
++ return true;
+ default:
+ return false;
+ }
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 9cd028aa1509..2e458eb45586 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -851,8 +851,14 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func,
+ * This is a fairly uncommon pattern which is new for GCC 6. As of this
+ * writing, there are 11 occurrences of it in the allmodconfig kernel.
+ *
++ * As of GCC 7 there are quite a few more of these and the 'in between' code
++ * is significant. Esp. with KASAN enabled some of the code between the mov
++ * and jmpq uses .rodata itself, which can confuse things.
++ *
+ * TODO: Once we have DWARF CFI and smarter instruction decoding logic,
+ * ensure the same register is used in the mov and jump instructions.
++ *
++ * NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ */
+ static struct rela *find_switch_table(struct objtool_file *file,
+ struct symbol *func,
+@@ -874,12 +880,25 @@ static struct rela *find_switch_table(struct objtool_file *file,
+ text_rela->addend + 4);
+ if (!rodata_rela)
+ return NULL;
++
+ file->ignore_unreachables = true;
+ return rodata_rela;
+ }
+
+ /* case 3 */
+- func_for_each_insn_continue_reverse(file, func, insn) {
++ /*
++ * Backward search using the @first_jump_src links, these help avoid
++ * much of the 'in between' code. Which avoids us getting confused by
++ * it.
++ */
++ for (insn = list_prev_entry(insn, list);
++
++ &insn->list != &file->insn_list &&
++ insn->sec == func->sec &&
++ insn->offset >= func->offset;
++
++ insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
++
+ if (insn->type == INSN_JUMP_DYNAMIC)
+ break;
+
+@@ -909,14 +928,32 @@ static struct rela *find_switch_table(struct objtool_file *file,
+ return NULL;
+ }
+
++
+ static int add_func_switch_tables(struct objtool_file *file,
+ struct symbol *func)
+ {
+- struct instruction *insn, *prev_jump = NULL;
++ struct instruction *insn, *last = NULL, *prev_jump = NULL;
+ struct rela *rela, *prev_rela = NULL;
+ int ret;
+
+ func_for_each_insn(file, func, insn) {
++ if (!last)
++ last = insn;
++
++ /*
++ * Store back-pointers for unconditional forward jumps such
++ * that find_switch_table() can back-track using those and
++ * avoid some potentially confusing code.
++ */
++ if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
++ insn->offset > last->offset &&
++ insn->jump_dest->offset > insn->offset &&
++ !insn->jump_dest->first_jump_src) {
++
++ insn->jump_dest->first_jump_src = insn;
++ last = insn->jump_dest;
++ }
++
+ if (insn->type != INSN_JUMP_DYNAMIC)
+ continue;
+
+diff --git a/tools/objtool/check.h b/tools/objtool/check.h
+index dbadb304a410..23a1d065cae1 100644
+--- a/tools/objtool/check.h
++++ b/tools/objtool/check.h
+@@ -47,6 +47,7 @@ struct instruction {
+ bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts;
+ struct symbol *call_dest;
+ struct instruction *jump_dest;
++ struct instruction *first_jump_src;
+ struct list_head alts;
+ struct symbol *func;
+ struct stack_op stack_op;
+diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
+index 9a07ee94a230..8b6c42dc1aa9 100644
+--- a/virt/kvm/arm/arm.c
++++ b/virt/kvm/arm/arm.c
+@@ -29,6 +29,7 @@
+ #include <linux/kvm.h>
+ #include <trace/events/kvm.h>
+ #include <kvm/arm_pmu.h>
++#include <kvm/arm_psci.h>
+
+ #define CREATE_TRACE_POINTS
+ #include "trace.h"
+@@ -44,7 +45,6 @@
+ #include <asm/kvm_mmu.h>
+ #include <asm/kvm_emulate.h>
+ #include <asm/kvm_coproc.h>
+-#include <asm/kvm_psci.h>
+ #include <asm/sections.h>
+
+ #ifdef REQUIRES_VIRT
+@@ -1139,7 +1139,7 @@ static void cpu_init_hyp_mode(void *dummy)
+ pgd_ptr = kvm_mmu_get_httbr();
+ stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
+ hyp_stack_ptr = stack_page + PAGE_SIZE;
+- vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
++ vector_ptr = (unsigned long)kvm_get_hyp_vector();
+
+ __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
+ __cpu_init_stage2();
+@@ -1220,6 +1220,7 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
+ cpu_hyp_reset();
+
+ return NOTIFY_OK;
++ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ if (__this_cpu_read(kvm_arm_hardware_enabled))
+ /* The hardware was enabled before suspend. */
+@@ -1384,6 +1385,12 @@ static int init_hyp_mode(void)
+ goto out_err;
+ }
+
++ err = kvm_map_vectors();
++ if (err) {
++ kvm_err("Cannot map vectors\n");
++ goto out_err;
++ }
++
+ /*
+ * Map the Hyp stack pages
+ */
+diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c
+index f1e363bab5e8..6919352cbf15 100644
+--- a/virt/kvm/arm/psci.c
++++ b/virt/kvm/arm/psci.c
+@@ -15,16 +15,16 @@
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <linux/arm-smccc.h>
+ #include <linux/preempt.h>
+ #include <linux/kvm_host.h>
+ #include <linux/wait.h>
+
+ #include <asm/cputype.h>
+ #include <asm/kvm_emulate.h>
+-#include <asm/kvm_psci.h>
+ #include <asm/kvm_host.h>
+
+-#include <uapi/linux/psci.h>
++#include <kvm/arm_psci.h>
+
+ /*
+ * This is an implementation of the Power State Coordination Interface
+@@ -33,6 +33,38 @@
+
+ #define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
+
++static u32 smccc_get_function(struct kvm_vcpu *vcpu)
++{
++ return vcpu_get_reg(vcpu, 0);
++}
++
++static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
++{
++ return vcpu_get_reg(vcpu, 1);
++}
++
++static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
++{
++ return vcpu_get_reg(vcpu, 2);
++}
++
++static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
++{
++ return vcpu_get_reg(vcpu, 3);
++}
++
++static void smccc_set_retval(struct kvm_vcpu *vcpu,
++ unsigned long a0,
++ unsigned long a1,
++ unsigned long a2,
++ unsigned long a3)
++{
++ vcpu_set_reg(vcpu, 0, a0);
++ vcpu_set_reg(vcpu, 1, a1);
++ vcpu_set_reg(vcpu, 2, a2);
++ vcpu_set_reg(vcpu, 3, a3);
++}
++
+ static unsigned long psci_affinity_mask(unsigned long affinity_level)
+ {
+ if (affinity_level <= 3)
+@@ -78,7 +110,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
+ unsigned long context_id;
+ phys_addr_t target_pc;
+
+- cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
++ cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
+ if (vcpu_mode_is_32bit(source_vcpu))
+ cpu_id &= ~((u32) 0);
+
+@@ -91,14 +123,14 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
+ if (!vcpu)
+ return PSCI_RET_INVALID_PARAMS;
+ if (!vcpu->arch.power_off) {
+- if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
++ if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1)
+ return PSCI_RET_ALREADY_ON;
+ else
+ return PSCI_RET_INVALID_PARAMS;
+ }
+
+- target_pc = vcpu_get_reg(source_vcpu, 2);
+- context_id = vcpu_get_reg(source_vcpu, 3);
++ target_pc = smccc_get_arg2(source_vcpu);
++ context_id = smccc_get_arg3(source_vcpu);
+
+ kvm_reset_vcpu(vcpu);
+
+@@ -117,7 +149,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
+ * NOTE: We always update r0 (or x0) because for PSCI v0.1
+ * the general puspose registers are undefined upon CPU_ON.
+ */
+- vcpu_set_reg(vcpu, 0, context_id);
++ smccc_set_retval(vcpu, context_id, 0, 0, 0);
+ vcpu->arch.power_off = false;
+ smp_mb(); /* Make sure the above is visible */
+
+@@ -137,8 +169,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_vcpu *tmp;
+
+- target_affinity = vcpu_get_reg(vcpu, 1);
+- lowest_affinity_level = vcpu_get_reg(vcpu, 2);
++ target_affinity = smccc_get_arg1(vcpu);
++ lowest_affinity_level = smccc_get_arg2(vcpu);
+
+ /* Determine target affinity mask */
+ target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
+@@ -200,18 +232,10 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
+ kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
+ }
+
+-int kvm_psci_version(struct kvm_vcpu *vcpu)
+-{
+- if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+- return KVM_ARM_PSCI_0_2;
+-
+- return KVM_ARM_PSCI_0_1;
+-}
+-
+ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
+ {
+ struct kvm *kvm = vcpu->kvm;
+- unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
++ u32 psci_fn = smccc_get_function(vcpu);
+ unsigned long val;
+ int ret = 1;
+
+@@ -221,7 +245,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
+ * Bits[31:16] = Major Version = 0
+ * Bits[15:0] = Minor Version = 2
+ */
+- val = 2;
++ val = KVM_ARM_PSCI_0_2;
+ break;
+ case PSCI_0_2_FN_CPU_SUSPEND:
+ case PSCI_0_2_FN64_CPU_SUSPEND:
+@@ -278,14 +302,56 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
+ break;
+ }
+
+- vcpu_set_reg(vcpu, 0, val);
++ smccc_set_retval(vcpu, val, 0, 0, 0);
++ return ret;
++}
++
++static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
++{
++ u32 psci_fn = smccc_get_function(vcpu);
++ u32 feature;
++ unsigned long val;
++ int ret = 1;
++
++ switch(psci_fn) {
++ case PSCI_0_2_FN_PSCI_VERSION:
++ val = KVM_ARM_PSCI_1_0;
++ break;
++ case PSCI_1_0_FN_PSCI_FEATURES:
++ feature = smccc_get_arg1(vcpu);
++ switch(feature) {
++ case PSCI_0_2_FN_PSCI_VERSION:
++ case PSCI_0_2_FN_CPU_SUSPEND:
++ case PSCI_0_2_FN64_CPU_SUSPEND:
++ case PSCI_0_2_FN_CPU_OFF:
++ case PSCI_0_2_FN_CPU_ON:
++ case PSCI_0_2_FN64_CPU_ON:
++ case PSCI_0_2_FN_AFFINITY_INFO:
++ case PSCI_0_2_FN64_AFFINITY_INFO:
++ case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
++ case PSCI_0_2_FN_SYSTEM_OFF:
++ case PSCI_0_2_FN_SYSTEM_RESET:
++ case PSCI_1_0_FN_PSCI_FEATURES:
++ case ARM_SMCCC_VERSION_FUNC_ID:
++ val = 0;
++ break;
++ default:
++ val = PSCI_RET_NOT_SUPPORTED;
++ break;
++ }
++ break;
++ default:
++ return kvm_psci_0_2_call(vcpu);
++ }
++
++ smccc_set_retval(vcpu, val, 0, 0, 0);
+ return ret;
+ }
+
+ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
+ {
+ struct kvm *kvm = vcpu->kvm;
+- unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
++ u32 psci_fn = smccc_get_function(vcpu);
+ unsigned long val;
+
+ switch (psci_fn) {
+@@ -303,7 +369,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
+ break;
+ }
+
+- vcpu_set_reg(vcpu, 0, val);
++ smccc_set_retval(vcpu, val, 0, 0, 0);
+ return 1;
+ }
+
+@@ -321,9 +387,11 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
+ * Errors:
+ * -EINVAL: Unrecognized PSCI function
+ */
+-int kvm_psci_call(struct kvm_vcpu *vcpu)
++static int kvm_psci_call(struct kvm_vcpu *vcpu)
+ {
+- switch (kvm_psci_version(vcpu)) {
++ switch (kvm_psci_version(vcpu, vcpu->kvm)) {
++ case KVM_ARM_PSCI_1_0:
++ return kvm_psci_1_0_call(vcpu);
+ case KVM_ARM_PSCI_0_2:
+ return kvm_psci_0_2_call(vcpu);
+ case KVM_ARM_PSCI_0_1:
+@@ -332,3 +400,30 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
+ return -EINVAL;
+ };
+ }
++
++int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
++{
++ u32 func_id = smccc_get_function(vcpu);
++ u32 val = PSCI_RET_NOT_SUPPORTED;
++ u32 feature;
++
++ switch (func_id) {
++ case ARM_SMCCC_VERSION_FUNC_ID:
++ val = ARM_SMCCC_VERSION_1_1;
++ break;
++ case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
++ feature = smccc_get_arg1(vcpu);
++ switch(feature) {
++ case ARM_SMCCC_ARCH_WORKAROUND_1:
++ if (kvm_arm_harden_branch_predictor())
++ val = 0;
++ break;
++ }
++ break;
++ default:
++ return kvm_psci_call(vcpu);
++ }
++
++ smccc_set_retval(vcpu, val, 0, 0, 0);
++ return 1;
++}