diff options
author | Alice Ferrazzi <alicef@gentoo.org> | 2018-02-17 14:25:08 +0000 |
---|---|---|
committer | Alice Ferrazzi <alicef@gentoo.org> | 2018-02-17 14:25:08 +0000 |
commit | d6237b6da0d6c278d18543a00c55cda4bbc53075 (patch) | |
tree | 0105f57348cda9f4cb84b3ac8a64df0d9e06e2fd | |
parent | linux kernel 4.14.19 (diff) | |
download | linux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.tar.gz linux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.tar.bz2 linux-patches-d6237b6da0d6c278d18543a00c55cda4bbc53075.zip |
linux kernel 4.14.20
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1018_linux-4.14.20.patch | 10698 |
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, ¬); + 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; ++} |