public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Mike Pagano" <mpagano@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/linux-patches:6.1 commit in: /
Date: Wed, 18 Jan 2023 11:29:56 +0000 (UTC)	[thread overview]
Message-ID: <1674041384.3a4f90d35a846c31efef8d7280e2ca565d778f07.mpagano@gentoo> (raw)

commit:     3a4f90d35a846c31efef8d7280e2ca565d778f07
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Wed Jan 18 11:29:44 2023 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Wed Jan 18 11:29:44 2023 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=3a4f90d3

Linux patch 6.1.7

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README            |     4 +
 1006_linux-6.1.7.patch | 10521 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 10525 insertions(+)

diff --git a/0000_README b/0000_README
index 9e9a8d04..eb8a606b 100644
--- a/0000_README
+++ b/0000_README
@@ -67,6 +67,10 @@ Patch:  1005_linux-6.1.6.patch
 From:   http://www.kernel.org
 Desc:   Linux 6.1.6
 
+Patch:  1006_linux-6.1.7.patch
+From:   http://www.kernel.org
+Desc:   Linux 6.1.7
+
 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/1006_linux-6.1.7.patch b/1006_linux-6.1.7.patch
new file mode 100644
index 00000000..9c382dc8
--- /dev/null
+++ b/1006_linux-6.1.7.patch
@@ -0,0 +1,10521 @@
+diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
+index 3b609c19e0bc4..6c5b4783812ae 100644
+--- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
++++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
+@@ -32,7 +32,7 @@ properties:
+       - description: Display byte clock
+       - description: Display byte interface clock
+       - description: Display pixel clock
+-      - description: Display escape clock
++      - description: Display core clock
+       - description: Display AHB clock
+       - description: Display AXI clock
+ 
+@@ -134,8 +134,6 @@ required:
+   - phy-names
+   - assigned-clocks
+   - assigned-clock-parents
+-  - power-domains
+-  - operating-points-v2
+   - ports
+ 
+ additionalProperties: false
+diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-10nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-10nm.yaml
+index d9ad8b659f58e..3ec466c3ab38b 100644
+--- a/Documentation/devicetree/bindings/display/msm/dsi-phy-10nm.yaml
++++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-10nm.yaml
+@@ -69,7 +69,6 @@ required:
+   - compatible
+   - reg
+   - reg-names
+-  - vdds-supply
+ 
+ unevaluatedProperties: false
+ 
+diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
+index 1342d74ecfe0f..0a7b5f110d885 100644
+--- a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
++++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
+@@ -38,7 +38,6 @@ required:
+   - compatible
+   - reg
+   - reg-names
+-  - vcca-supply
+ 
+ unevaluatedProperties: false
+ 
+diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-28nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-28nm.yaml
+index 3d8540a06fe22..2f1fd140c87df 100644
+--- a/Documentation/devicetree/bindings/display/msm/dsi-phy-28nm.yaml
++++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-28nm.yaml
+@@ -34,6 +34,10 @@ properties:
+   vddio-supply:
+     description: Phandle to vdd-io regulator device node.
+ 
++  qcom,dsi-phy-regulator-ldo-mode:
++    type: boolean
++    description: Indicates if the LDO mode PHY regulator is wanted.
++
+ required:
+   - compatible
+   - reg
+diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
+index 393d218e4a0cf..b2c6aaf1edf27 100644
+--- a/Documentation/gpu/todo.rst
++++ b/Documentation/gpu/todo.rst
+@@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks.
+ 
+ Contact: Harry Wentland, Alex Deucher
+ 
+-vmwgfx: Replace hashtable with Linux' implementation
+-----------------------------------------------------
+-
+-The vmwgfx driver uses its own hashtable implementation. Replace the
+-code with Linux' implementation and update the callers. It's mostly a
+-refactoring task, but the interfaces are different.
+-
+-Contact: Zack Rusin, Thomas Zimmermann <tzimmermann@suse.de>
+-
+-Level: Intermediate
+-
+ Bootsplash
+ ==========
+ 
+diff --git a/Documentation/sphinx/load_config.py b/Documentation/sphinx/load_config.py
+index eeb394b39e2cc..8b416bfd75ac1 100644
+--- a/Documentation/sphinx/load_config.py
++++ b/Documentation/sphinx/load_config.py
+@@ -3,7 +3,7 @@
+ 
+ import os
+ import sys
+-from sphinx.util.pycompat import execfile_
++from sphinx.util.osutil import fs_encoding
+ 
+ # ------------------------------------------------------------------------------
+ def loadConfig(namespace):
+@@ -48,7 +48,9 @@ def loadConfig(namespace):
+             sys.stdout.write("load additional sphinx-config: %s\n" % config_file)
+             config = namespace.copy()
+             config['__file__'] = config_file
+-            execfile_(config_file, config)
++            with open(config_file, 'rb') as f:
++                code = compile(f.read(), fs_encoding, 'exec')
++                exec(code, config)
+             del config['__file__']
+             namespace.update(config)
+         else:
+diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
+index 896914e3a8475..b8ec88ef2efa2 100644
+--- a/Documentation/virt/kvm/api.rst
++++ b/Documentation/virt/kvm/api.rst
+@@ -8248,6 +8248,20 @@ CPU[EAX=1]:ECX[24] (TSC_DEADLINE) is not reported by ``KVM_GET_SUPPORTED_CPUID``
+ It can be enabled if ``KVM_CAP_TSC_DEADLINE_TIMER`` is present and the kernel
+ has enabled in-kernel emulation of the local APIC.
+ 
++CPU topology
++~~~~~~~~~~~~
++
++Several CPUID values include topology information for the host CPU:
++0x0b and 0x1f for Intel systems, 0x8000001e for AMD systems.  Different
++versions of KVM return different values for this information and userspace
++should not rely on it.  Currently they return all zeroes.
++
++If userspace wishes to set up a guest topology, it should be careful that
++the values of these three leaves differ for each CPU.  In particular,
++the APIC ID is found in EDX for all subleaves of 0x0b and 0x1f, and in EAX
++for 0x8000001e; the latter also encodes the core id and node id in bits
++7:0 of EBX and ECX respectively.
++
+ Obsolete ioctls and capabilities
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ 
+diff --git a/Makefile b/Makefile
+index 19e8c6dec6e54..7eb6793ecfbfd 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 6
+ PATCHLEVEL = 1
+-SUBLEVEL = 6
++SUBLEVEL = 7
+ EXTRAVERSION =
+ NAME = Hurr durr I'ma ninja sloth
+ 
+diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h
+index 0890e4f568fb7..cbb3d961123b1 100644
+--- a/arch/arm64/include/asm/atomic_ll_sc.h
++++ b/arch/arm64/include/asm/atomic_ll_sc.h
+@@ -315,7 +315,7 @@ __ll_sc__cmpxchg_double##name(unsigned long old1,			\
+ 	"	cbnz	%w0, 1b\n"					\
+ 	"	" #mb "\n"						\
+ 	"2:"								\
+-	: "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr)	\
++	: "=&r" (tmp), "=&r" (ret), "+Q" (*(__uint128_t *)ptr)		\
+ 	: "r" (old1), "r" (old2), "r" (new1), "r" (new2)		\
+ 	: cl);								\
+ 									\
+diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
+index 52075e93de6c0..a94d6dacc0292 100644
+--- a/arch/arm64/include/asm/atomic_lse.h
++++ b/arch/arm64/include/asm/atomic_lse.h
+@@ -311,7 +311,7 @@ __lse__cmpxchg_double##name(unsigned long old1,				\
+ 	"	eor	%[old2], %[old2], %[oldval2]\n"			\
+ 	"	orr	%[old1], %[old1], %[old2]"			\
+ 	: [old1] "+&r" (x0), [old2] "+&r" (x1),				\
+-	  [v] "+Q" (*(unsigned long *)ptr)				\
++	  [v] "+Q" (*(__uint128_t *)ptr)				\
+ 	: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),		\
+ 	  [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)		\
+ 	: cl);								\
+diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
+index 9bdba47f7e149..0d40c48d81329 100644
+--- a/arch/arm64/include/asm/kvm_emulate.h
++++ b/arch/arm64/include/asm/kvm_emulate.h
+@@ -373,8 +373,26 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+ 
+ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
+ {
+-	if (kvm_vcpu_abt_iss1tw(vcpu))
+-		return true;
++	if (kvm_vcpu_abt_iss1tw(vcpu)) {
++		/*
++		 * Only a permission fault on a S1PTW should be
++		 * considered as a write. Otherwise, page tables baked
++		 * in a read-only memslot will result in an exception
++		 * being delivered in the guest.
++		 *
++		 * The drawback is that we end-up faulting twice if the
++		 * guest is using any of HW AF/DB: a translation fault
++		 * to map the page containing the PT (read only at
++		 * first), then a permission fault to allow the flags
++		 * to be set.
++		 */
++		switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
++		case ESR_ELx_FSC_PERM:
++			return true;
++		default:
++			return false;
++		}
++	}
+ 
+ 	if (kvm_vcpu_trap_is_iabt(vcpu))
+ 		return false;
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index edf6625ce9654..f1cfc44ef52fe 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -682,7 +682,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+ #define pud_leaf(pud)		(pud_present(pud) && !pud_table(pud))
+ #define pud_valid(pud)		pte_valid(pud_pte(pud))
+ #define pud_user(pud)		pte_user(pud_pte(pud))
+-
++#define pud_user_exec(pud)	pte_user_exec(pud_pte(pud))
+ 
+ static inline void set_pud(pud_t *pudp, pud_t pud)
+ {
+@@ -863,12 +863,12 @@ static inline bool pte_user_accessible_page(pte_t pte)
+ 
+ static inline bool pmd_user_accessible_page(pmd_t pmd)
+ {
+-	return pmd_leaf(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
++	return pmd_leaf(pmd) && !pmd_present_invalid(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
+ }
+ 
+ static inline bool pud_user_accessible_page(pud_t pud)
+ {
+-	return pud_leaf(pud) && pud_user(pud);
++	return pud_leaf(pud) && (pud_user(pud) || pud_user_exec(pud));
+ }
+ #endif
+ 
+diff --git a/arch/arm64/kernel/elfcore.c b/arch/arm64/kernel/elfcore.c
+index 27ef7ad3ffd2e..662a61e5e75e4 100644
+--- a/arch/arm64/kernel/elfcore.c
++++ b/arch/arm64/kernel/elfcore.c
+@@ -8,28 +8,27 @@
+ #include <asm/cpufeature.h>
+ #include <asm/mte.h>
+ 
+-#define for_each_mte_vma(vmi, vma)					\
++#define for_each_mte_vma(cprm, i, m)					\
+ 	if (system_supports_mte())					\
+-		for_each_vma(vmi, vma)					\
+-			if (vma->vm_flags & VM_MTE)
++		for (i = 0, m = cprm->vma_meta;				\
++		     i < cprm->vma_count;				\
++		     i++, m = cprm->vma_meta + i)			\
++			if (m->flags & VM_MTE)
+ 
+-static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
++static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
+ {
+-	if (vma->vm_flags & VM_DONTDUMP)
+-		return 0;
+-
+-	return vma_pages(vma) * MTE_PAGE_TAG_STORAGE;
++	return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
+ }
+ 
+ /* Derived from dump_user_range(); start/end must be page-aligned */
+ static int mte_dump_tag_range(struct coredump_params *cprm,
+-			      unsigned long start, unsigned long end)
++			      unsigned long start, unsigned long len)
+ {
+ 	int ret = 1;
+ 	unsigned long addr;
+ 	void *tags = NULL;
+ 
+-	for (addr = start; addr < end; addr += PAGE_SIZE) {
++	for (addr = start; addr < start + len; addr += PAGE_SIZE) {
+ 		struct page *page = get_dump_page(addr);
+ 
+ 		/*
+@@ -65,7 +64,6 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
+ 		mte_save_page_tags(page_address(page), tags);
+ 		put_page(page);
+ 		if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
+-			mte_free_tag_storage(tags);
+ 			ret = 0;
+ 			break;
+ 		}
+@@ -77,13 +75,13 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
+ 	return ret;
+ }
+ 
+-Elf_Half elf_core_extra_phdrs(void)
++Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
+ {
+-	struct vm_area_struct *vma;
++	int i;
++	struct core_vma_metadata *m;
+ 	int vma_count = 0;
+-	VMA_ITERATOR(vmi, current->mm, 0);
+ 
+-	for_each_mte_vma(vmi, vma)
++	for_each_mte_vma(cprm, i, m)
+ 		vma_count++;
+ 
+ 	return vma_count;
+@@ -91,18 +89,18 @@ Elf_Half elf_core_extra_phdrs(void)
+ 
+ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
+ {
+-	struct vm_area_struct *vma;
+-	VMA_ITERATOR(vmi, current->mm, 0);
++	int i;
++	struct core_vma_metadata *m;
+ 
+-	for_each_mte_vma(vmi, vma) {
++	for_each_mte_vma(cprm, i, m) {
+ 		struct elf_phdr phdr;
+ 
+ 		phdr.p_type = PT_AARCH64_MEMTAG_MTE;
+ 		phdr.p_offset = offset;
+-		phdr.p_vaddr = vma->vm_start;
++		phdr.p_vaddr = m->start;
+ 		phdr.p_paddr = 0;
+-		phdr.p_filesz = mte_vma_tag_dump_size(vma);
+-		phdr.p_memsz = vma->vm_end - vma->vm_start;
++		phdr.p_filesz = mte_vma_tag_dump_size(m);
++		phdr.p_memsz = m->end - m->start;
+ 		offset += phdr.p_filesz;
+ 		phdr.p_flags = 0;
+ 		phdr.p_align = 0;
+@@ -114,28 +112,25 @@ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
+ 	return 1;
+ }
+ 
+-size_t elf_core_extra_data_size(void)
++size_t elf_core_extra_data_size(struct coredump_params *cprm)
+ {
+-	struct vm_area_struct *vma;
++	int i;
++	struct core_vma_metadata *m;
+ 	size_t data_size = 0;
+-	VMA_ITERATOR(vmi, current->mm, 0);
+ 
+-	for_each_mte_vma(vmi, vma)
+-		data_size += mte_vma_tag_dump_size(vma);
++	for_each_mte_vma(cprm, i, m)
++		data_size += mte_vma_tag_dump_size(m);
+ 
+ 	return data_size;
+ }
+ 
+ int elf_core_write_extra_data(struct coredump_params *cprm)
+ {
+-	struct vm_area_struct *vma;
+-	VMA_ITERATOR(vmi, current->mm, 0);
+-
+-	for_each_mte_vma(vmi, vma) {
+-		if (vma->vm_flags & VM_DONTDUMP)
+-			continue;
++	int i;
++	struct core_vma_metadata *m;
+ 
+-		if (!mte_dump_tag_range(cprm, vma->vm_start, vma->vm_end))
++	for_each_mte_vma(cprm, i, m) {
++		if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
+ 			return 0;
+ 	}
+ 
+diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
+index c2fb5755bbecb..92bc9a2d702cb 100644
+--- a/arch/arm64/kernel/ptrace.c
++++ b/arch/arm64/kernel/ptrace.c
+@@ -1364,7 +1364,7 @@ enum aarch64_regset {
+ #ifdef CONFIG_ARM64_SVE
+ 	REGSET_SVE,
+ #endif
+-#ifdef CONFIG_ARM64_SVE
++#ifdef CONFIG_ARM64_SME
+ 	REGSET_SSVE,
+ 	REGSET_ZA,
+ #endif
+diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
+index 9ad911f1647c8..43adbfa5ead78 100644
+--- a/arch/arm64/kernel/signal.c
++++ b/arch/arm64/kernel/signal.c
+@@ -280,7 +280,12 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
+ 
+ 		vl = task_get_sme_vl(current);
+ 	} else {
+-		if (!system_supports_sve())
++		/*
++		 * A SME only system use SVE for streaming mode so can
++		 * have a SVE formatted context with a zero VL and no
++		 * payload data.
++		 */
++		if (!system_supports_sve() && !system_supports_sme())
+ 			return -EINVAL;
+ 
+ 		vl = task_get_sve_vl(current);
+@@ -729,7 +734,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
+ 			return err;
+ 	}
+ 
+-	if (system_supports_sve()) {
++	if (system_supports_sve() || system_supports_sme()) {
+ 		unsigned int vq = 0;
+ 
+ 		if (add_all || test_thread_flag(TIF_SVE) ||
+diff --git a/arch/ia64/kernel/elfcore.c b/arch/ia64/kernel/elfcore.c
+index 94680521fbf91..8895df1215404 100644
+--- a/arch/ia64/kernel/elfcore.c
++++ b/arch/ia64/kernel/elfcore.c
+@@ -7,7 +7,7 @@
+ #include <asm/elf.h>
+ 
+ 
+-Elf64_Half elf_core_extra_phdrs(void)
++Elf64_Half elf_core_extra_phdrs(struct coredump_params *cprm)
+ {
+ 	return GATE_EHDR->e_phnum;
+ }
+@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
+ 	return 1;
+ }
+ 
+-size_t elf_core_extra_data_size(void)
++size_t elf_core_extra_data_size(struct coredump_params *cprm)
+ {
+ 	const struct elf_phdr *const gate_phdrs =
+ 		(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
+diff --git a/arch/powerpc/include/asm/imc-pmu.h b/arch/powerpc/include/asm/imc-pmu.h
+index 4f897993b7107..699a88584ae16 100644
+--- a/arch/powerpc/include/asm/imc-pmu.h
++++ b/arch/powerpc/include/asm/imc-pmu.h
+@@ -137,7 +137,7 @@ struct imc_pmu {
+  * are inited.
+  */
+ struct imc_pmu_ref {
+-	struct mutex lock;
++	spinlock_t lock;
+ 	unsigned int id;
+ 	int refc;
+ };
+diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c
+index d517aba94d1bc..100e97daf76ba 100644
+--- a/arch/powerpc/perf/imc-pmu.c
++++ b/arch/powerpc/perf/imc-pmu.c
+@@ -14,6 +14,7 @@
+ #include <asm/cputhreads.h>
+ #include <asm/smp.h>
+ #include <linux/string.h>
++#include <linux/spinlock.h>
+ 
+ /* Nest IMC data structures and variables */
+ 
+@@ -21,7 +22,7 @@
+  * Used to avoid races in counting the nest-pmu units during hotplug
+  * register and unregister
+  */
+-static DEFINE_MUTEX(nest_init_lock);
++static DEFINE_SPINLOCK(nest_init_lock);
+ static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc);
+ static struct imc_pmu **per_nest_pmu_arr;
+ static cpumask_t nest_imc_cpumask;
+@@ -50,7 +51,7 @@ static int trace_imc_mem_size;
+  * core and trace-imc
+  */
+ static struct imc_pmu_ref imc_global_refc = {
+-	.lock = __MUTEX_INITIALIZER(imc_global_refc.lock),
++	.lock = __SPIN_LOCK_INITIALIZER(imc_global_refc.lock),
+ 	.id = 0,
+ 	.refc = 0,
+ };
+@@ -400,7 +401,7 @@ static int ppc_nest_imc_cpu_offline(unsigned int cpu)
+ 				       get_hard_smp_processor_id(cpu));
+ 		/*
+ 		 * If this is the last cpu in this chip then, skip the reference
+-		 * count mutex lock and make the reference count on this chip zero.
++		 * count lock and make the reference count on this chip zero.
+ 		 */
+ 		ref = get_nest_pmu_ref(cpu);
+ 		if (!ref)
+@@ -462,15 +463,15 @@ static void nest_imc_counters_release(struct perf_event *event)
+ 	/*
+ 	 * See if we need to disable the nest PMU.
+ 	 * If no events are currently in use, then we have to take a
+-	 * mutex to ensure that we don't race with another task doing
++	 * lock to ensure that we don't race with another task doing
+ 	 * enable or disable the nest counters.
+ 	 */
+ 	ref = get_nest_pmu_ref(event->cpu);
+ 	if (!ref)
+ 		return;
+ 
+-	/* Take the mutex lock for this node and then decrement the reference count */
+-	mutex_lock(&ref->lock);
++	/* Take the lock for this node and then decrement the reference count */
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		/*
+ 		 * The scenario where this is true is, when perf session is
+@@ -482,7 +483,7 @@ static void nest_imc_counters_release(struct perf_event *event)
+ 		 * an OPAL call to disable the engine in that node.
+ 		 *
+ 		 */
+-		mutex_unlock(&ref->lock);
++		spin_unlock(&ref->lock);
+ 		return;
+ 	}
+ 	ref->refc--;
+@@ -490,7 +491,7 @@ static void nest_imc_counters_release(struct perf_event *event)
+ 		rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,
+ 					    get_hard_smp_processor_id(event->cpu));
+ 		if (rc) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("nest-imc: Unable to stop the counters for core %d\n", node_id);
+ 			return;
+ 		}
+@@ -498,7 +499,7 @@ static void nest_imc_counters_release(struct perf_event *event)
+ 		WARN(1, "nest-imc: Invalid event reference count\n");
+ 		ref->refc = 0;
+ 	}
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ }
+ 
+ static int nest_imc_event_init(struct perf_event *event)
+@@ -557,26 +558,25 @@ static int nest_imc_event_init(struct perf_event *event)
+ 
+ 	/*
+ 	 * Get the imc_pmu_ref struct for this node.
+-	 * Take the mutex lock and then increment the count of nest pmu events
+-	 * inited.
++	 * Take the lock and then increment the count of nest pmu events inited.
+ 	 */
+ 	ref = get_nest_pmu_ref(event->cpu);
+ 	if (!ref)
+ 		return -EINVAL;
+ 
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_NEST,
+ 					     get_hard_smp_processor_id(event->cpu));
+ 		if (rc) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("nest-imc: Unable to start the counters for node %d\n",
+ 									node_id);
+ 			return rc;
+ 		}
+ 	}
+ 	++ref->refc;
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 
+ 	event->destroy = nest_imc_counters_release;
+ 	return 0;
+@@ -612,9 +612,8 @@ static int core_imc_mem_init(int cpu, int size)
+ 		return -ENOMEM;
+ 	mem_info->vbase = page_address(page);
+ 
+-	/* Init the mutex */
+ 	core_imc_refc[core_id].id = core_id;
+-	mutex_init(&core_imc_refc[core_id].lock);
++	spin_lock_init(&core_imc_refc[core_id].lock);
+ 
+ 	rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,
+ 				__pa((void *)mem_info->vbase),
+@@ -703,9 +702,8 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
+ 		perf_pmu_migrate_context(&core_imc_pmu->pmu, cpu, ncpu);
+ 	} else {
+ 		/*
+-		 * If this is the last cpu in this core then, skip taking refernce
+-		 * count mutex lock for this core and directly zero "refc" for
+-		 * this core.
++		 * If this is the last cpu in this core then skip taking reference
++		 * count lock for this core and directly zero "refc" for this core.
+ 		 */
+ 		opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
+ 				       get_hard_smp_processor_id(cpu));
+@@ -720,11 +718,11 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
+ 		 * last cpu in this core and core-imc event running
+ 		 * in this cpu.
+ 		 */
+-		mutex_lock(&imc_global_refc.lock);
++		spin_lock(&imc_global_refc.lock);
+ 		if (imc_global_refc.id == IMC_DOMAIN_CORE)
+ 			imc_global_refc.refc--;
+ 
+-		mutex_unlock(&imc_global_refc.lock);
++		spin_unlock(&imc_global_refc.lock);
+ 	}
+ 	return 0;
+ }
+@@ -739,7 +737,7 @@ static int core_imc_pmu_cpumask_init(void)
+ 
+ static void reset_global_refc(struct perf_event *event)
+ {
+-		mutex_lock(&imc_global_refc.lock);
++		spin_lock(&imc_global_refc.lock);
+ 		imc_global_refc.refc--;
+ 
+ 		/*
+@@ -751,7 +749,7 @@ static void reset_global_refc(struct perf_event *event)
+ 			imc_global_refc.refc = 0;
+ 			imc_global_refc.id = 0;
+ 		}
+-		mutex_unlock(&imc_global_refc.lock);
++		spin_unlock(&imc_global_refc.lock);
+ }
+ 
+ static void core_imc_counters_release(struct perf_event *event)
+@@ -764,17 +762,17 @@ static void core_imc_counters_release(struct perf_event *event)
+ 	/*
+ 	 * See if we need to disable the IMC PMU.
+ 	 * If no events are currently in use, then we have to take a
+-	 * mutex to ensure that we don't race with another task doing
++	 * lock to ensure that we don't race with another task doing
+ 	 * enable or disable the core counters.
+ 	 */
+ 	core_id = event->cpu / threads_per_core;
+ 
+-	/* Take the mutex lock and decrement the refernce count for this core */
++	/* Take the lock and decrement the refernce count for this core */
+ 	ref = &core_imc_refc[core_id];
+ 	if (!ref)
+ 		return;
+ 
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		/*
+ 		 * The scenario where this is true is, when perf session is
+@@ -786,7 +784,7 @@ static void core_imc_counters_release(struct perf_event *event)
+ 		 * an OPAL call to disable the engine in that core.
+ 		 *
+ 		 */
+-		mutex_unlock(&ref->lock);
++		spin_unlock(&ref->lock);
+ 		return;
+ 	}
+ 	ref->refc--;
+@@ -794,7 +792,7 @@ static void core_imc_counters_release(struct perf_event *event)
+ 		rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
+ 					    get_hard_smp_processor_id(event->cpu));
+ 		if (rc) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("IMC: Unable to stop the counters for core %d\n", core_id);
+ 			return;
+ 		}
+@@ -802,7 +800,7 @@ static void core_imc_counters_release(struct perf_event *event)
+ 		WARN(1, "core-imc: Invalid event reference count\n");
+ 		ref->refc = 0;
+ 	}
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 
+ 	reset_global_refc(event);
+ }
+@@ -840,7 +838,6 @@ static int core_imc_event_init(struct perf_event *event)
+ 	if ((!pcmi->vbase))
+ 		return -ENODEV;
+ 
+-	/* Get the core_imc mutex for this core */
+ 	ref = &core_imc_refc[core_id];
+ 	if (!ref)
+ 		return -EINVAL;
+@@ -848,22 +845,22 @@ static int core_imc_event_init(struct perf_event *event)
+ 	/*
+ 	 * Core pmu units are enabled only when it is used.
+ 	 * See if this is triggered for the first time.
+-	 * If yes, take the mutex lock and enable the core counters.
++	 * If yes, take the lock and enable the core counters.
+ 	 * If not, just increment the count in core_imc_refc struct.
+ 	 */
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
+ 					     get_hard_smp_processor_id(event->cpu));
+ 		if (rc) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("core-imc: Unable to start the counters for core %d\n",
+ 									core_id);
+ 			return rc;
+ 		}
+ 	}
+ 	++ref->refc;
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 
+ 	/*
+ 	 * Since the system can run either in accumulation or trace-mode
+@@ -874,7 +871,7 @@ static int core_imc_event_init(struct perf_event *event)
+ 	 * to know whether any other trace/thread imc
+ 	 * events are running.
+ 	 */
+-	mutex_lock(&imc_global_refc.lock);
++	spin_lock(&imc_global_refc.lock);
+ 	if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_CORE) {
+ 		/*
+ 		 * No other trace/thread imc events are running in
+@@ -883,10 +880,10 @@ static int core_imc_event_init(struct perf_event *event)
+ 		imc_global_refc.id = IMC_DOMAIN_CORE;
+ 		imc_global_refc.refc++;
+ 	} else {
+-		mutex_unlock(&imc_global_refc.lock);
++		spin_unlock(&imc_global_refc.lock);
+ 		return -EBUSY;
+ 	}
+-	mutex_unlock(&imc_global_refc.lock);
++	spin_unlock(&imc_global_refc.lock);
+ 
+ 	event->hw.event_base = (u64)pcmi->vbase + (config & IMC_EVENT_OFFSET_MASK);
+ 	event->destroy = core_imc_counters_release;
+@@ -958,10 +955,10 @@ static int ppc_thread_imc_cpu_offline(unsigned int cpu)
+ 	mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+ 
+ 	/* Reduce the refc if thread-imc event running on this cpu */
+-	mutex_lock(&imc_global_refc.lock);
++	spin_lock(&imc_global_refc.lock);
+ 	if (imc_global_refc.id == IMC_DOMAIN_THREAD)
+ 		imc_global_refc.refc--;
+-	mutex_unlock(&imc_global_refc.lock);
++	spin_unlock(&imc_global_refc.lock);
+ 
+ 	return 0;
+ }
+@@ -1001,7 +998,7 @@ static int thread_imc_event_init(struct perf_event *event)
+ 	if (!target)
+ 		return -EINVAL;
+ 
+-	mutex_lock(&imc_global_refc.lock);
++	spin_lock(&imc_global_refc.lock);
+ 	/*
+ 	 * Check if any other trace/core imc events are running in the
+ 	 * system, if not set the global id to thread-imc.
+@@ -1010,10 +1007,10 @@ static int thread_imc_event_init(struct perf_event *event)
+ 		imc_global_refc.id = IMC_DOMAIN_THREAD;
+ 		imc_global_refc.refc++;
+ 	} else {
+-		mutex_unlock(&imc_global_refc.lock);
++		spin_unlock(&imc_global_refc.lock);
+ 		return -EBUSY;
+ 	}
+-	mutex_unlock(&imc_global_refc.lock);
++	spin_unlock(&imc_global_refc.lock);
+ 
+ 	event->pmu->task_ctx_nr = perf_sw_context;
+ 	event->destroy = reset_global_refc;
+@@ -1135,25 +1132,25 @@ static int thread_imc_event_add(struct perf_event *event, int flags)
+ 	/*
+ 	 * imc pmus are enabled only when it is used.
+ 	 * See if this is triggered for the first time.
+-	 * If yes, take the mutex lock and enable the counters.
++	 * If yes, take the lock and enable the counters.
+ 	 * If not, just increment the count in ref count struct.
+ 	 */
+ 	ref = &core_imc_refc[core_id];
+ 	if (!ref)
+ 		return -EINVAL;
+ 
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		if (opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
+ 		    get_hard_smp_processor_id(smp_processor_id()))) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("thread-imc: Unable to start the counter\
+ 				for core %d\n", core_id);
+ 			return -EINVAL;
+ 		}
+ 	}
+ 	++ref->refc;
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 	return 0;
+ }
+ 
+@@ -1170,12 +1167,12 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
+ 		return;
+ 	}
+ 
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	ref->refc--;
+ 	if (ref->refc == 0) {
+ 		if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
+ 		    get_hard_smp_processor_id(smp_processor_id()))) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("thread-imc: Unable to stop the counters\
+ 				for core %d\n", core_id);
+ 			return;
+@@ -1183,7 +1180,7 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
+ 	} else if (ref->refc < 0) {
+ 		ref->refc = 0;
+ 	}
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 
+ 	/* Set bit 0 of LDBAR to zero, to stop posting updates to memory */
+ 	mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+@@ -1224,9 +1221,8 @@ static int trace_imc_mem_alloc(int cpu_id, int size)
+ 		}
+ 	}
+ 
+-	/* Init the mutex, if not already */
+ 	trace_imc_refc[core_id].id = core_id;
+-	mutex_init(&trace_imc_refc[core_id].lock);
++	spin_lock_init(&trace_imc_refc[core_id].lock);
+ 
+ 	mtspr(SPRN_LDBAR, 0);
+ 	return 0;
+@@ -1246,10 +1242,10 @@ static int ppc_trace_imc_cpu_offline(unsigned int cpu)
+ 	 * Reduce the refc if any trace-imc event running
+ 	 * on this cpu.
+ 	 */
+-	mutex_lock(&imc_global_refc.lock);
++	spin_lock(&imc_global_refc.lock);
+ 	if (imc_global_refc.id == IMC_DOMAIN_TRACE)
+ 		imc_global_refc.refc--;
+-	mutex_unlock(&imc_global_refc.lock);
++	spin_unlock(&imc_global_refc.lock);
+ 
+ 	return 0;
+ }
+@@ -1371,17 +1367,17 @@ static int trace_imc_event_add(struct perf_event *event, int flags)
+ 	}
+ 
+ 	mtspr(SPRN_LDBAR, ldbar_value);
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	if (ref->refc == 0) {
+ 		if (opal_imc_counters_start(OPAL_IMC_COUNTERS_TRACE,
+ 				get_hard_smp_processor_id(smp_processor_id()))) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("trace-imc: Unable to start the counters for core %d\n", core_id);
+ 			return -EINVAL;
+ 		}
+ 	}
+ 	++ref->refc;
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 	return 0;
+ }
+ 
+@@ -1414,19 +1410,19 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
+ 		return;
+ 	}
+ 
+-	mutex_lock(&ref->lock);
++	spin_lock(&ref->lock);
+ 	ref->refc--;
+ 	if (ref->refc == 0) {
+ 		if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_TRACE,
+ 				get_hard_smp_processor_id(smp_processor_id()))) {
+-			mutex_unlock(&ref->lock);
++			spin_unlock(&ref->lock);
+ 			pr_err("trace-imc: Unable to stop the counters for core %d\n", core_id);
+ 			return;
+ 		}
+ 	} else if (ref->refc < 0) {
+ 		ref->refc = 0;
+ 	}
+-	mutex_unlock(&ref->lock);
++	spin_unlock(&ref->lock);
+ 
+ 	trace_imc_event_stop(event, flags);
+ }
+@@ -1448,7 +1444,7 @@ static int trace_imc_event_init(struct perf_event *event)
+ 	 * no other thread is running any core/thread imc
+ 	 * events
+ 	 */
+-	mutex_lock(&imc_global_refc.lock);
++	spin_lock(&imc_global_refc.lock);
+ 	if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_TRACE) {
+ 		/*
+ 		 * No core/thread imc events are running in the
+@@ -1457,10 +1453,10 @@ static int trace_imc_event_init(struct perf_event *event)
+ 		imc_global_refc.id = IMC_DOMAIN_TRACE;
+ 		imc_global_refc.refc++;
+ 	} else {
+-		mutex_unlock(&imc_global_refc.lock);
++		spin_unlock(&imc_global_refc.lock);
+ 		return -EBUSY;
+ 	}
+-	mutex_unlock(&imc_global_refc.lock);
++	spin_unlock(&imc_global_refc.lock);
+ 
+ 	event->hw.idx = -1;
+ 
+@@ -1533,10 +1529,10 @@ static int init_nest_pmu_ref(void)
+ 	i = 0;
+ 	for_each_node(nid) {
+ 		/*
+-		 * Mutex lock to avoid races while tracking the number of
++		 * Take the lock to avoid races while tracking the number of
+ 		 * sessions using the chip's nest pmu units.
+ 		 */
+-		mutex_init(&nest_imc_refc[i].lock);
++		spin_lock_init(&nest_imc_refc[i].lock);
+ 
+ 		/*
+ 		 * Loop to init the "id" with the node_id. Variable "i" initialized to
+@@ -1633,7 +1629,7 @@ static void imc_common_mem_free(struct imc_pmu *pmu_ptr)
+ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
+ {
+ 	if (pmu_ptr->domain == IMC_DOMAIN_NEST) {
+-		mutex_lock(&nest_init_lock);
++		spin_lock(&nest_init_lock);
+ 		if (nest_pmus == 1) {
+ 			cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);
+ 			kfree(nest_imc_refc);
+@@ -1643,7 +1639,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
+ 
+ 		if (nest_pmus > 0)
+ 			nest_pmus--;
+-		mutex_unlock(&nest_init_lock);
++		spin_unlock(&nest_init_lock);
+ 	}
+ 
+ 	/* Free core_imc memory */
+@@ -1800,11 +1796,11 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
+ 		* rest. To handle the cpuhotplug callback unregister, we track
+ 		* the number of nest pmus in "nest_pmus".
+ 		*/
+-		mutex_lock(&nest_init_lock);
++		spin_lock(&nest_init_lock);
+ 		if (nest_pmus == 0) {
+ 			ret = init_nest_pmu_ref();
+ 			if (ret) {
+-				mutex_unlock(&nest_init_lock);
++				spin_unlock(&nest_init_lock);
+ 				kfree(per_nest_pmu_arr);
+ 				per_nest_pmu_arr = NULL;
+ 				goto err_free_mem;
+@@ -1812,7 +1808,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
+ 			/* Register for cpu hotplug notification. */
+ 			ret = nest_pmu_cpumask_init();
+ 			if (ret) {
+-				mutex_unlock(&nest_init_lock);
++				spin_unlock(&nest_init_lock);
+ 				kfree(nest_imc_refc);
+ 				kfree(per_nest_pmu_arr);
+ 				per_nest_pmu_arr = NULL;
+@@ -1820,7 +1816,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
+ 			}
+ 		}
+ 		nest_pmus++;
+-		mutex_unlock(&nest_init_lock);
++		spin_unlock(&nest_init_lock);
+ 		break;
+ 	case IMC_DOMAIN_CORE:
+ 		ret = core_imc_pmu_cpumask_init();
+diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
+index feaba12dbecb8..efa103b52a1a1 100644
+--- a/arch/s390/include/asm/cpu_mf.h
++++ b/arch/s390/include/asm/cpu_mf.h
+@@ -131,19 +131,21 @@ struct hws_combined_entry {
+ 	struct hws_diag_entry	diag;	/* Diagnostic-sampling data entry */
+ } __packed;
+ 
+-struct hws_trailer_entry {
+-	union {
+-		struct {
+-			unsigned int f:1;	/* 0 - Block Full Indicator   */
+-			unsigned int a:1;	/* 1 - Alert request control  */
+-			unsigned int t:1;	/* 2 - Timestamp format	      */
+-			unsigned int :29;	/* 3 - 31: Reserved	      */
+-			unsigned int bsdes:16;	/* 32-47: size of basic SDE   */
+-			unsigned int dsdes:16;	/* 48-63: size of diagnostic SDE */
+-		};
+-		unsigned long long flags;	/* 0 - 63: All indicators     */
++union hws_trailer_header {
++	struct {
++		unsigned int f:1;	/* 0 - Block Full Indicator   */
++		unsigned int a:1;	/* 1 - Alert request control  */
++		unsigned int t:1;	/* 2 - Timestamp format	      */
++		unsigned int :29;	/* 3 - 31: Reserved	      */
++		unsigned int bsdes:16;	/* 32-47: size of basic SDE   */
++		unsigned int dsdes:16;	/* 48-63: size of diagnostic SDE */
++		unsigned long long overflow; /* 64 - Overflow Count   */
+ 	};
+-	unsigned long long overflow;	 /* 64 - sample Overflow count	      */
++	__uint128_t val;
++};
++
++struct hws_trailer_entry {
++	union hws_trailer_header header; /* 0 - 15 Flags + Overflow Count     */
+ 	unsigned char timestamp[16];	 /* 16 - 31 timestamp		      */
+ 	unsigned long long reserved1;	 /* 32 -Reserved		      */
+ 	unsigned long long reserved2;	 /*				      */
+@@ -290,14 +292,11 @@ static inline unsigned long sample_rate_to_freq(struct hws_qsi_info_block *qsi,
+ 	return USEC_PER_SEC * qsi->cpu_speed / rate;
+ }
+ 
+-#define SDB_TE_ALERT_REQ_MASK	0x4000000000000000UL
+-#define SDB_TE_BUFFER_FULL_MASK 0x8000000000000000UL
+-
+ /* Return TOD timestamp contained in an trailer entry */
+ static inline unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
+ {
+ 	/* TOD in STCKE format */
+-	if (te->t)
++	if (te->header.t)
+ 		return *((unsigned long long *) &te->timestamp[1]);
+ 
+ 	/* TOD in STCK format */
+diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h
+index cb5fc06904354..081837b391e35 100644
+--- a/arch/s390/include/asm/percpu.h
++++ b/arch/s390/include/asm/percpu.h
+@@ -31,7 +31,7 @@
+ 	pcp_op_T__ *ptr__;						\
+ 	preempt_disable_notrace();					\
+ 	ptr__ = raw_cpu_ptr(&(pcp));					\
+-	prev__ = *ptr__;						\
++	prev__ = READ_ONCE(*ptr__);					\
+ 	do {								\
+ 		old__ = prev__;						\
+ 		new__ = old__ op (val);					\
+diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
+index fc6d5f58debeb..2df94d32140c4 100644
+--- a/arch/s390/kernel/machine_kexec_file.c
++++ b/arch/s390/kernel/machine_kexec_file.c
+@@ -187,8 +187,6 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ 
+ 	data->memsz = ALIGN(data->memsz, PAGE_SIZE);
+ 	buf.mem = data->memsz;
+-	if (image->type == KEXEC_TYPE_CRASH)
+-		buf.mem += crashk_res.start;
+ 
+ 	ptr = (void *)ipl_cert_list_addr;
+ 	end = ptr + ipl_cert_list_size;
+@@ -225,6 +223,9 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ 		data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
+ 	*lc_ipl_parmblock_ptr = (__u32)buf.mem;
+ 
++	if (image->type == KEXEC_TYPE_CRASH)
++		buf.mem += crashk_res.start;
++
+ 	ret = kexec_add_buffer(&buf);
+ out:
+ 	return ret;
+diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
+index 332a499651308..ce886a03545ae 100644
+--- a/arch/s390/kernel/perf_cpum_sf.c
++++ b/arch/s390/kernel/perf_cpum_sf.c
+@@ -163,14 +163,15 @@ static void free_sampling_buffer(struct sf_buffer *sfb)
+ 
+ static int alloc_sample_data_block(unsigned long *sdbt, gfp_t gfp_flags)
+ {
+-	unsigned long sdb, *trailer;
++	struct hws_trailer_entry *te;
++	unsigned long sdb;
+ 
+ 	/* Allocate and initialize sample-data-block */
+ 	sdb = get_zeroed_page(gfp_flags);
+ 	if (!sdb)
+ 		return -ENOMEM;
+-	trailer = trailer_entry_ptr(sdb);
+-	*trailer = SDB_TE_ALERT_REQ_MASK;
++	te = (struct hws_trailer_entry *)trailer_entry_ptr(sdb);
++	te->header.a = 1;
+ 
+ 	/* Link SDB into the sample-data-block-table */
+ 	*sdbt = sdb;
+@@ -1206,7 +1207,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
+ 					    "%s: Found unknown"
+ 					    " sampling data entry: te->f %i"
+ 					    " basic.def %#4x (%p)\n", __func__,
+-					    te->f, sample->def, sample);
++					    te->header.f, sample->def, sample);
+ 			/* Sample slot is not yet written or other record.
+ 			 *
+ 			 * This condition can occur if the buffer was reused
+@@ -1217,7 +1218,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
+ 			 * that are not full.  Stop processing if the first
+ 			 * invalid format was detected.
+ 			 */
+-			if (!te->f)
++			if (!te->header.f)
+ 				break;
+ 		}
+ 
+@@ -1227,6 +1228,16 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
+ 	}
+ }
+ 
++static inline __uint128_t __cdsg(__uint128_t *ptr, __uint128_t old, __uint128_t new)
++{
++	asm volatile(
++		"	cdsg	%[old],%[new],%[ptr]\n"
++		: [old] "+d" (old), [ptr] "+QS" (*ptr)
++		: [new] "d" (new)
++		: "memory", "cc");
++	return old;
++}
++
+ /* hw_perf_event_update() - Process sampling buffer
+  * @event:	The perf event
+  * @flush_all:	Flag to also flush partially filled sample-data-blocks
+@@ -1243,10 +1254,11 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
+  */
+ static void hw_perf_event_update(struct perf_event *event, int flush_all)
+ {
++	unsigned long long event_overflow, sampl_overflow, num_sdb;
++	union hws_trailer_header old, prev, new;
+ 	struct hw_perf_event *hwc = &event->hw;
+ 	struct hws_trailer_entry *te;
+ 	unsigned long *sdbt;
+-	unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags;
+ 	int done;
+ 
+ 	/*
+@@ -1266,25 +1278,25 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
+ 		te = (struct hws_trailer_entry *) trailer_entry_ptr(*sdbt);
+ 
+ 		/* Leave loop if no more work to do (block full indicator) */
+-		if (!te->f) {
++		if (!te->header.f) {
+ 			done = 1;
+ 			if (!flush_all)
+ 				break;
+ 		}
+ 
+ 		/* Check the sample overflow count */
+-		if (te->overflow)
++		if (te->header.overflow)
+ 			/* Account sample overflows and, if a particular limit
+ 			 * is reached, extend the sampling buffer.
+ 			 * For details, see sfb_account_overflows().
+ 			 */
+-			sampl_overflow += te->overflow;
++			sampl_overflow += te->header.overflow;
+ 
+ 		/* Timestamps are valid for full sample-data-blocks only */
+ 		debug_sprintf_event(sfdbg, 6, "%s: sdbt %#lx "
+ 				    "overflow %llu timestamp %#llx\n",
+-				    __func__, (unsigned long)sdbt, te->overflow,
+-				    (te->f) ? trailer_timestamp(te) : 0ULL);
++				    __func__, (unsigned long)sdbt, te->header.overflow,
++				    (te->header.f) ? trailer_timestamp(te) : 0ULL);
+ 
+ 		/* Collect all samples from a single sample-data-block and
+ 		 * flag if an (perf) event overflow happened.  If so, the PMU
+@@ -1294,12 +1306,16 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
+ 		num_sdb++;
+ 
+ 		/* Reset trailer (using compare-double-and-swap) */
++		/* READ_ONCE() 16 byte header */
++		prev.val = __cdsg(&te->header.val, 0, 0);
+ 		do {
+-			te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
+-			te_flags |= SDB_TE_ALERT_REQ_MASK;
+-		} while (!cmpxchg_double(&te->flags, &te->overflow,
+-					 te->flags, te->overflow,
+-					 te_flags, 0ULL));
++			old.val = prev.val;
++			new.val = prev.val;
++			new.f = 0;
++			new.a = 1;
++			new.overflow = 0;
++			prev.val = __cdsg(&te->header.val, old.val, new.val);
++		} while (prev.val != old.val);
+ 
+ 		/* Advance to next sample-data-block */
+ 		sdbt++;
+@@ -1384,7 +1400,7 @@ static void aux_output_end(struct perf_output_handle *handle)
+ 	range_scan = AUX_SDB_NUM_ALERT(aux);
+ 	for (i = 0, idx = aux->head; i < range_scan; i++, idx++) {
+ 		te = aux_sdb_trailer(aux, idx);
+-		if (!(te->flags & SDB_TE_BUFFER_FULL_MASK))
++		if (!te->header.f)
+ 			break;
+ 	}
+ 	/* i is num of SDBs which are full */
+@@ -1392,7 +1408,7 @@ static void aux_output_end(struct perf_output_handle *handle)
+ 
+ 	/* Remove alert indicators in the buffer */
+ 	te = aux_sdb_trailer(aux, aux->alert_mark);
+-	te->flags &= ~SDB_TE_ALERT_REQ_MASK;
++	te->header.a = 0;
+ 
+ 	debug_sprintf_event(sfdbg, 6, "%s: SDBs %ld range %ld head %ld\n",
+ 			    __func__, i, range_scan, aux->head);
+@@ -1437,9 +1453,9 @@ static int aux_output_begin(struct perf_output_handle *handle,
+ 		idx = aux->empty_mark + 1;
+ 		for (i = 0; i < range_scan; i++, idx++) {
+ 			te = aux_sdb_trailer(aux, idx);
+-			te->flags &= ~(SDB_TE_BUFFER_FULL_MASK |
+-				       SDB_TE_ALERT_REQ_MASK);
+-			te->overflow = 0;
++			te->header.f = 0;
++			te->header.a = 0;
++			te->header.overflow = 0;
+ 		}
+ 		/* Save the position of empty SDBs */
+ 		aux->empty_mark = aux->head + range - 1;
+@@ -1448,7 +1464,7 @@ static int aux_output_begin(struct perf_output_handle *handle,
+ 	/* Set alert indicator */
+ 	aux->alert_mark = aux->head + range/2 - 1;
+ 	te = aux_sdb_trailer(aux, aux->alert_mark);
+-	te->flags = te->flags | SDB_TE_ALERT_REQ_MASK;
++	te->header.a = 1;
+ 
+ 	/* Reset hardware buffer head */
+ 	head = AUX_SDB_INDEX(aux, aux->head);
+@@ -1475,14 +1491,17 @@ static int aux_output_begin(struct perf_output_handle *handle,
+ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
+ 			  unsigned long long *overflow)
+ {
+-	unsigned long long orig_overflow, orig_flags, new_flags;
++	union hws_trailer_header old, prev, new;
+ 	struct hws_trailer_entry *te;
+ 
+ 	te = aux_sdb_trailer(aux, alert_index);
++	/* READ_ONCE() 16 byte header */
++	prev.val = __cdsg(&te->header.val, 0, 0);
+ 	do {
+-		orig_flags = te->flags;
+-		*overflow = orig_overflow = te->overflow;
+-		if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
++		old.val = prev.val;
++		new.val = prev.val;
++		*overflow = old.overflow;
++		if (old.f) {
+ 			/*
+ 			 * SDB is already set by hardware.
+ 			 * Abort and try to set somewhere
+@@ -1490,10 +1509,10 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
+ 			 */
+ 			return false;
+ 		}
+-		new_flags = orig_flags | SDB_TE_ALERT_REQ_MASK;
+-	} while (!cmpxchg_double(&te->flags, &te->overflow,
+-				 orig_flags, orig_overflow,
+-				 new_flags, 0ULL));
++		new.a = 1;
++		new.overflow = 0;
++		prev.val = __cdsg(&te->header.val, old.val, new.val);
++	} while (prev.val != old.val);
+ 	return true;
+ }
+ 
+@@ -1522,8 +1541,9 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
+ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
+ 			     unsigned long long *overflow)
+ {
+-	unsigned long long orig_overflow, orig_flags, new_flags;
+ 	unsigned long i, range_scan, idx, idx_old;
++	union hws_trailer_header old, prev, new;
++	unsigned long long orig_overflow;
+ 	struct hws_trailer_entry *te;
+ 
+ 	debug_sprintf_event(sfdbg, 6, "%s: range %ld head %ld alert %ld "
+@@ -1554,17 +1574,20 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
+ 	idx_old = idx = aux->empty_mark + 1;
+ 	for (i = 0; i < range_scan; i++, idx++) {
+ 		te = aux_sdb_trailer(aux, idx);
++		/* READ_ONCE() 16 byte header */
++		prev.val = __cdsg(&te->header.val, 0, 0);
+ 		do {
+-			orig_flags = te->flags;
+-			orig_overflow = te->overflow;
+-			new_flags = orig_flags & ~SDB_TE_BUFFER_FULL_MASK;
++			old.val = prev.val;
++			new.val = prev.val;
++			orig_overflow = old.overflow;
++			new.f = 0;
++			new.overflow = 0;
+ 			if (idx == aux->alert_mark)
+-				new_flags |= SDB_TE_ALERT_REQ_MASK;
++				new.a = 1;
+ 			else
+-				new_flags &= ~SDB_TE_ALERT_REQ_MASK;
+-		} while (!cmpxchg_double(&te->flags, &te->overflow,
+-					 orig_flags, orig_overflow,
+-					 new_flags, 0ULL));
++				new.a = 0;
++			prev.val = __cdsg(&te->header.val, old.val, new.val);
++		} while (prev.val != old.val);
+ 		*overflow += orig_overflow;
+ 	}
+ 
+diff --git a/arch/x86/boot/bioscall.S b/arch/x86/boot/bioscall.S
+index 5521ea12f44e0..aa9b964575843 100644
+--- a/arch/x86/boot/bioscall.S
++++ b/arch/x86/boot/bioscall.S
+@@ -32,7 +32,7 @@ intcall:
+ 	movw	%dx, %si
+ 	movw	%sp, %di
+ 	movw	$11, %cx
+-	rep; movsd
++	rep; movsl
+ 
+ 	/* Pop full state from the stack */
+ 	popal
+@@ -67,7 +67,7 @@ intcall:
+ 	jz	4f
+ 	movw	%sp, %si
+ 	movw	$11, %cx
+-	rep; movsd
++	rep; movsl
+ 4:	addw	$44, %sp
+ 
+ 	/* Restore state and return */
+diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
+index efe0c30d3a12d..77538abeb72af 100644
+--- a/arch/x86/kernel/cpu/resctrl/monitor.c
++++ b/arch/x86/kernel/cpu/resctrl/monitor.c
+@@ -146,6 +146,30 @@ static inline struct rmid_entry *__rmid_entry(u32 rmid)
+ 	return entry;
+ }
+ 
++static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val)
++{
++	u64 msr_val;
++
++	/*
++	 * As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
++	 * with a valid event code for supported resource type and the bits
++	 * IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
++	 * IA32_QM_CTR.data (bits 61:0) reports the monitored data.
++	 * IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
++	 * are error bits.
++	 */
++	wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
++	rdmsrl(MSR_IA32_QM_CTR, msr_val);
++
++	if (msr_val & RMID_VAL_ERROR)
++		return -EIO;
++	if (msr_val & RMID_VAL_UNAVAIL)
++		return -EINVAL;
++
++	*val = msr_val;
++	return 0;
++}
++
+ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
+ 						 u32 rmid,
+ 						 enum resctrl_event_id eventid)
+@@ -172,8 +196,12 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
+ 	struct arch_mbm_state *am;
+ 
+ 	am = get_arch_mbm_state(hw_dom, rmid, eventid);
+-	if (am)
++	if (am) {
+ 		memset(am, 0, sizeof(*am));
++
++		/* Record any initial, non-zero count value. */
++		__rmid_read(rmid, eventid, &am->prev_msr);
++	}
+ }
+ 
+ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
+@@ -191,25 +219,14 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
+ 	struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
+ 	struct arch_mbm_state *am;
+ 	u64 msr_val, chunks;
++	int ret;
+ 
+ 	if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
+ 		return -EINVAL;
+ 
+-	/*
+-	 * As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
+-	 * with a valid event code for supported resource type and the bits
+-	 * IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
+-	 * IA32_QM_CTR.data (bits 61:0) reports the monitored data.
+-	 * IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
+-	 * are error bits.
+-	 */
+-	wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
+-	rdmsrl(MSR_IA32_QM_CTR, msr_val);
+-
+-	if (msr_val & RMID_VAL_ERROR)
+-		return -EIO;
+-	if (msr_val & RMID_VAL_UNAVAIL)
+-		return -EINVAL;
++	ret = __rmid_read(rmid, eventid, &msr_val);
++	if (ret)
++		return ret;
+ 
+ 	am = get_arch_mbm_state(hw_dom, rmid, eventid);
+ 	if (am) {
+diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+index e5a48f05e7876..5993da21d8225 100644
+--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+@@ -580,8 +580,10 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
+ 	/*
+ 	 * Ensure the task's closid and rmid are written before determining if
+ 	 * the task is current that will decide if it will be interrupted.
++	 * This pairs with the full barrier between the rq->curr update and
++	 * resctrl_sched_in() during context switch.
+ 	 */
+-	barrier();
++	smp_mb();
+ 
+ 	/*
+ 	 * By now, the task's closid and rmid are set. If the task is current
+@@ -2401,6 +2403,14 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
+ 			WRITE_ONCE(t->closid, to->closid);
+ 			WRITE_ONCE(t->rmid, to->mon.rmid);
+ 
++			/*
++			 * Order the closid/rmid stores above before the loads
++			 * in task_curr(). This pairs with the full barrier
++			 * between the rq->curr update and resctrl_sched_in()
++			 * during context switch.
++			 */
++			smp_mb();
++
+ 			/*
+ 			 * If the task is on a CPU, set the CPU in the mask.
+ 			 * The detection is inaccurate as tasks might move or
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 62bc7a01cecca..6047dbe048803 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -759,16 +759,22 @@ struct kvm_cpuid_array {
+ 	int nent;
+ };
+ 
++static struct kvm_cpuid_entry2 *get_next_cpuid(struct kvm_cpuid_array *array)
++{
++	if (array->nent >= array->maxnent)
++		return NULL;
++
++	return &array->entries[array->nent++];
++}
++
+ static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
+ 					      u32 function, u32 index)
+ {
+-	struct kvm_cpuid_entry2 *entry;
++	struct kvm_cpuid_entry2 *entry = get_next_cpuid(array);
+ 
+-	if (array->nent >= array->maxnent)
++	if (!entry)
+ 		return NULL;
+ 
+-	entry = &array->entries[array->nent++];
+-
+ 	memset(entry, 0, sizeof(*entry));
+ 	entry->function = function;
+ 	entry->index = index;
+@@ -945,22 +951,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
+ 		entry->edx = edx.full;
+ 		break;
+ 	}
+-	/*
+-	 * Per Intel's SDM, the 0x1f is a superset of 0xb,
+-	 * thus they can be handled by common code.
+-	 */
+ 	case 0x1f:
+ 	case 0xb:
+ 		/*
+-		 * Populate entries until the level type (ECX[15:8]) of the
+-		 * previous entry is zero.  Note, CPUID EAX.{0x1f,0xb}.0 is
+-		 * the starting entry, filled by the primary do_host_cpuid().
++		 * No topology; a valid topology is indicated by the presence
++		 * of subleaf 1.
+ 		 */
+-		for (i = 1; entry->ecx & 0xff00; ++i) {
+-			entry = do_host_cpuid(array, function, i);
+-			if (!entry)
+-				goto out;
+-		}
++		entry->eax = entry->ebx = entry->ecx = 0;
+ 		break;
+ 	case 0xd: {
+ 		u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm();
+@@ -1193,6 +1190,9 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
+ 		entry->ebx = entry->ecx = entry->edx = 0;
+ 		break;
+ 	case 0x8000001e:
++		/* Do not return host topology information.  */
++		entry->eax = entry->ebx = entry->ecx = 0;
++		entry->edx = 0; /* reserved */
+ 		break;
+ 	case 0x8000001F:
+ 		if (!kvm_cpu_cap_has(X86_FEATURE_SEV)) {
+diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c
+index 66a209f7eb86d..2642bc4c8ec07 100644
+--- a/arch/x86/mm/pat/memtype.c
++++ b/arch/x86/mm/pat/memtype.c
+@@ -434,7 +434,8 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
+ 		u8 mtrr_type, uniform;
+ 
+ 		mtrr_type = mtrr_type_lookup(start, end, &uniform);
+-		if (mtrr_type != MTRR_TYPE_WRBACK)
++		if (mtrr_type != MTRR_TYPE_WRBACK &&
++		    mtrr_type != MTRR_TYPE_INVALID)
+ 			return _PAGE_CACHE_MODE_UC_MINUS;
+ 
+ 		return _PAGE_CACHE_MODE_WB;
+diff --git a/arch/x86/um/elfcore.c b/arch/x86/um/elfcore.c
+index 48a3eb09d9516..650cdbbdaf45e 100644
+--- a/arch/x86/um/elfcore.c
++++ b/arch/x86/um/elfcore.c
+@@ -7,7 +7,7 @@
+ #include <asm/elf.h>
+ 
+ 
+-Elf32_Half elf_core_extra_phdrs(void)
++Elf32_Half elf_core_extra_phdrs(struct coredump_params *cprm)
+ {
+ 	return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0;
+ }
+@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
+ 	return 1;
+ }
+ 
+-size_t elf_core_extra_data_size(void)
++size_t elf_core_extra_data_size(struct coredump_params *cprm)
+ {
+ 	if ( vsyscall_ehdr ) {
+ 		const struct elfhdr *const ehdrp =
+diff --git a/block/blk-merge.c b/block/blk-merge.c
+index f46c87ef951df..84f03d066cb31 100644
+--- a/block/blk-merge.c
++++ b/block/blk-merge.c
+@@ -358,11 +358,13 @@ struct bio *__bio_split_to_limits(struct bio *bio, struct queue_limits *lim,
+ 	default:
+ 		split = bio_split_rw(bio, lim, nr_segs, bs,
+ 				get_max_io_size(bio, lim) << SECTOR_SHIFT);
++		if (IS_ERR(split))
++			return NULL;
+ 		break;
+ 	}
+ 
+ 	if (split) {
+-		/* there isn't chance to merge the splitted bio */
++		/* there isn't chance to merge the split bio */
+ 		split->bi_opf |= REQ_NOMERGE;
+ 
+ 		blkcg_bio_issue_init(split);
+diff --git a/block/blk-mq.c b/block/blk-mq.c
+index 0b855e033a834..63abbe342b28c 100644
+--- a/block/blk-mq.c
++++ b/block/blk-mq.c
+@@ -2919,8 +2919,11 @@ void blk_mq_submit_bio(struct bio *bio)
+ 	blk_status_t ret;
+ 
+ 	bio = blk_queue_bounce(bio, q);
+-	if (bio_may_exceed_limits(bio, &q->limits))
++	if (bio_may_exceed_limits(bio, &q->limits)) {
+ 		bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
++		if (!bio)
++			return;
++	}
+ 
+ 	if (!bio_integrity_prep(bio))
+ 		return;
+diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
+index 204fe94c7e458..a194f30876c59 100644
+--- a/drivers/acpi/glue.c
++++ b/drivers/acpi/glue.c
+@@ -75,7 +75,8 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
+ }
+ 
+ #define FIND_CHILD_MIN_SCORE	1
+-#define FIND_CHILD_MAX_SCORE	2
++#define FIND_CHILD_MID_SCORE	2
++#define FIND_CHILD_MAX_SCORE	3
+ 
+ static int match_any(struct acpi_device *adev, void *not_used)
+ {
+@@ -96,8 +97,17 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
+ 		return -ENODEV;
+ 
+ 	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
+-	if (status == AE_NOT_FOUND)
++	if (status == AE_NOT_FOUND) {
++		/*
++		 * Special case: backlight device objects without _STA are
++		 * preferred to other objects with the same _ADR value, because
++		 * it is more likely that they are actually useful.
++		 */
++		if (adev->pnp.type.backlight)
++			return FIND_CHILD_MID_SCORE;
++
+ 		return FIND_CHILD_MIN_SCORE;
++	}
+ 
+ 	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
+ 		return -ENODEV;
+diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
+index b47e93a24a9a4..dbfa58e799e28 100644
+--- a/drivers/acpi/scan.c
++++ b/drivers/acpi/scan.c
+@@ -1370,9 +1370,12 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
+ 		 * Some devices don't reliably have _HIDs & _CIDs, so add
+ 		 * synthetic HIDs to make sure drivers can find them.
+ 		 */
+-		if (acpi_is_video_device(handle))
++		if (acpi_is_video_device(handle)) {
+ 			acpi_add_id(pnp, ACPI_VIDEO_HID);
+-		else if (acpi_bay_match(handle))
++			pnp->type.backlight = 1;
++			break;
++		}
++		if (acpi_bay_match(handle))
+ 			acpi_add_id(pnp, ACPI_BAY_HID);
+ 		else if (acpi_dock_match(handle))
+ 			acpi_add_id(pnp, ACPI_DOCK_HID);
+diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
+index 76b7e7f8894e7..1db8e68cd8bce 100644
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -50,6 +50,10 @@ static void acpi_video_parse_cmdline(void)
+ 		acpi_backlight_cmdline = acpi_backlight_video;
+ 	if (!strcmp("native", acpi_video_backlight_string))
+ 		acpi_backlight_cmdline = acpi_backlight_native;
++	if (!strcmp("nvidia_wmi_ec", acpi_video_backlight_string))
++		acpi_backlight_cmdline = acpi_backlight_nvidia_wmi_ec;
++	if (!strcmp("apple_gmux", acpi_video_backlight_string))
++		acpi_backlight_cmdline = acpi_backlight_apple_gmux;
+ 	if (!strcmp("none", acpi_video_backlight_string))
+ 		acpi_backlight_cmdline = acpi_backlight_none;
+ }
+diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
+index 7f9bcc82fc9c4..d700bf06b534f 100644
+--- a/drivers/block/drbd/drbd_req.c
++++ b/drivers/block/drbd/drbd_req.c
+@@ -1607,6 +1607,8 @@ void drbd_submit_bio(struct bio *bio)
+ 	struct drbd_device *device = bio->bi_bdev->bd_disk->private_data;
+ 
+ 	bio = bio_split_to_limits(bio);
++	if (!bio)
++		return;
+ 
+ 	/*
+ 	 * what we "blindly" assume:
+diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
+index c76e0148eada3..574e470b220b0 100644
+--- a/drivers/block/ps3vram.c
++++ b/drivers/block/ps3vram.c
+@@ -587,6 +587,8 @@ static void ps3vram_submit_bio(struct bio *bio)
+ 	dev_dbg(&dev->core, "%s\n", __func__);
+ 
+ 	bio = bio_split_to_limits(bio);
++	if (!bio)
++		return;
+ 
+ 	spin_lock_irq(&priv->lock);
+ 	busy = !bio_list_empty(&priv->list);
+diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
+index 204e39006dda8..c17bd845f5fcb 100644
+--- a/drivers/cpufreq/amd-pstate.c
++++ b/drivers/cpufreq/amd-pstate.c
+@@ -307,6 +307,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
+ 		max_perf = min_perf;
+ 
+ 	amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true);
++	cpufreq_cpu_put(policy);
+ }
+ 
+ static int amd_get_min_freq(struct amd_cpudata *cpudata)
+diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
+index 19522c568aa5d..878deb4880cdb 100644
+--- a/drivers/edac/edac_device.c
++++ b/drivers/edac/edac_device.c
+@@ -394,17 +394,16 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+  *	Then restart the workq on the new delay
+  */
+ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
+-					unsigned long value)
++				    unsigned long msec)
+ {
+-	unsigned long jiffs = msecs_to_jiffies(value);
+-
+-	if (value == 1000)
+-		jiffs = round_jiffies_relative(value);
+-
+-	edac_dev->poll_msec = value;
+-	edac_dev->delay	    = jiffs;
++	edac_dev->poll_msec = msec;
++	edac_dev->delay	    = msecs_to_jiffies(msec);
+ 
+-	edac_mod_work(&edac_dev->work, jiffs);
++	/* See comment in edac_device_workq_setup() above */
++	if (edac_dev->poll_msec == 1000)
++		edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
++	else
++		edac_mod_work(&edac_dev->work, edac_dev->delay);
+ }
+ 
+ int edac_device_alloc_index(void)
+diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
+index 50ed9f2425bb5..4ed24d664d83b 100644
+--- a/drivers/edac/edac_module.h
++++ b/drivers/edac/edac_module.h
+@@ -52,7 +52,7 @@ bool edac_stop_work(struct delayed_work *work);
+ bool edac_mod_work(struct delayed_work *work, unsigned long delay);
+ 
+ extern void edac_device_reset_delay_period(struct edac_device_ctl_info
+-					   *edac_dev, unsigned long value);
++					   *edac_dev, unsigned long msec);
+ extern void edac_mc_reset_delay_period(unsigned long value);
+ 
+ /*
+diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
+index f12cc29bd4b84..033aac6be7daa 100644
+--- a/drivers/firmware/efi/efi.c
++++ b/drivers/firmware/efi/efi.c
+@@ -374,8 +374,8 @@ static int __init efisubsys_init(void)
+ 	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
+ 	if (!efi_kobj) {
+ 		pr_err("efi: Firmware registration failed.\n");
+-		destroy_workqueue(efi_rts_wq);
+-		return -ENOMEM;
++		error = -ENOMEM;
++		goto err_destroy_wq;
+ 	}
+ 
+ 	if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
+@@ -423,7 +423,10 @@ err_unregister:
+ 		generic_ops_unregister();
+ err_put:
+ 	kobject_put(efi_kobj);
+-	destroy_workqueue(efi_rts_wq);
++err_destroy_wq:
++	if (efi_rts_wq)
++		destroy_workqueue(efi_rts_wq);
++
+ 	return error;
+ }
+ 
+diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
+index f3e54f6616f02..60075e0e4943a 100644
+--- a/drivers/firmware/efi/runtime-wrappers.c
++++ b/drivers/firmware/efi/runtime-wrappers.c
+@@ -62,6 +62,7 @@ struct efi_runtime_work efi_rts_work;
+ 									\
+ 	if (!efi_enabled(EFI_RUNTIME_SERVICES)) {			\
+ 		pr_warn_once("EFI Runtime Services are disabled!\n");	\
++		efi_rts_work.status = EFI_DEVICE_ERROR;			\
+ 		goto exit;						\
+ 	}								\
+ 									\
+diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
+index e7bcfca4159f6..447ee4ea5c903 100644
+--- a/drivers/firmware/psci/psci.c
++++ b/drivers/firmware/psci/psci.c
+@@ -440,6 +440,9 @@ static const struct file_operations psci_debugfs_ops = {
+ 
+ static int __init psci_debugfs_init(void)
+ {
++	if (!invoke_psci_fn || !psci_ops.get_version)
++		return 0;
++
+ 	return PTR_ERR_OR_ZERO(debugfs_create_file("psci", 0444, NULL, NULL,
+ 						   &psci_debugfs_ops));
+ }
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 0be85d19a6f3e..8f83d5b6ceaad 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -36,6 +36,7 @@
+ #include <generated/utsrelease.h>
+ #include <linux/pci-p2pdma.h>
+ 
++#include <drm/drm_aperture.h>
+ #include <drm/drm_atomic_helper.h>
+ #include <drm/drm_probe_helper.h>
+ #include <drm/amdgpu_drm.h>
+@@ -89,6 +90,8 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
+ #define AMDGPU_MAX_RETRY_LIMIT		2
+ #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL)
+ 
++static const struct drm_driver amdgpu_kms_driver;
++
+ const char *amdgpu_asic_name[] = {
+ 	"TAHITI",
+ 	"PITCAIRN",
+@@ -3677,6 +3680,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,
+ 	if (r)
+ 		return r;
+ 
++	/* Get rid of things like offb */
++	r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver);
++	if (r)
++		return r;
++
+ 	/* Enable TMZ based on IP_VERSION */
+ 	amdgpu_gmc_tmz_set(adev);
+ 
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index b59466972ed7a..2e5d78b6635c4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -23,7 +23,6 @@
+  */
+ 
+ #include <drm/amdgpu_drm.h>
+-#include <drm/drm_aperture.h>
+ #include <drm/drm_drv.h>
+ #include <drm/drm_gem.h>
+ #include <drm/drm_vblank.h>
+@@ -2123,11 +2122,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+ 	}
+ #endif
+ 
+-	/* Get rid of things like offb */
+-	ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver);
+-	if (ret)
+-		return ret;
+-
+ 	adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev);
+ 	if (IS_ERR(adev))
+ 		return PTR_ERR(adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+index 3be3cba3a16db..cfd78c4a45baa 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+@@ -468,8 +468,9 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
+ 	return true;
+ 
+ fail:
+-	DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
+-		  man->size);
++	if (man)
++		DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
++			  man->size);
+ 	return false;
+ }
+ 
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 80dd1343594c7..75c80c557b6ec 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -882,7 +882,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
+ 		kfree(rsv);
+ 
+ 	list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
+-		drm_buddy_free_list(&mgr->mm, &rsv->blocks);
++		drm_buddy_free_list(&mgr->mm, &rsv->allocated);
+ 		kfree(rsv);
+ 	}
+ 	drm_buddy_fini(&mgr->mm);
+diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
+index 8b297ade69a24..909cf9f220c19 100644
+--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
+@@ -322,6 +322,7 @@ soc21_asic_reset_method(struct amdgpu_device *adev)
+ 	switch (adev->ip_versions[MP1_HWIP][0]) {
+ 	case IP_VERSION(13, 0, 0):
+ 	case IP_VERSION(13, 0, 7):
++	case IP_VERSION(13, 0, 10):
+ 		return AMD_RESET_METHOD_MODE1;
+ 	case IP_VERSION(13, 0, 4):
+ 		return AMD_RESET_METHOD_MODE2;
+@@ -652,6 +653,16 @@ static int soc21_common_early_init(void *handle)
+ 		}
+ 		adev->external_rev_id = adev->rev_id + 0x20;
+ 		break;
++	case IP_VERSION(11, 0, 4):
++		adev->cg_flags = AMD_CG_SUPPORT_VCN_MGCG |
++			AMD_CG_SUPPORT_JPEG_MGCG;
++		adev->pg_flags = AMD_PG_SUPPORT_VCN |
++			AMD_PG_SUPPORT_VCN_DPG |
++			AMD_PG_SUPPORT_GFX_PG |
++			AMD_PG_SUPPORT_JPEG;
++		adev->external_rev_id = adev->rev_id + 0x1;
++		break;
++
+ 	default:
+ 		/* FIXME: not supported yet */
+ 		return -EINVAL;
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+index 33ab6fdc36175..9919c39f7ea03 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+@@ -1919,8 +1919,9 @@ int dcn32_populate_dml_pipes_from_context(
+ 		timing = &pipe->stream->timing;
+ 
+ 		pipes[pipe_cnt].pipe.src.gpuvm = true;
+-		pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+-		pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
++		DC_FP_START();
++		dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt);
++		DC_FP_END();
+ 		pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
+ 		pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet
+ 		pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+index d1bf49d207de4..d90216d2fe3a8 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -2546,3 +2546,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
+ 	}
+ }
+ 
++void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
++				  int pipe_cnt)
++{
++	dc_assert_fp_enabled();
++
++	pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
++	pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
++}
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+index 3a3dc2ce4c739..ab010e7e840b8 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+@@ -73,4 +73,7 @@ int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
+ 
+ void dcn32_patch_dpm_table(struct clk_bw_params *bw_params);
+ 
++void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
++				  int pipe_cnt);
++
+ #endif
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
+index dad3e3741a4e8..190af79f3236f 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c
+@@ -67,22 +67,21 @@ int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
+ int vega10_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr,
+ 		uint32_t *speed)
+ {
+-	uint32_t current_rpm;
+-	uint32_t percent = 0;
+-
+-	if (hwmgr->thermal_controller.fanInfo.bNoFan)
+-		return 0;
++	struct amdgpu_device *adev = hwmgr->adev;
++	uint32_t duty100, duty;
++	uint64_t tmp64;
+ 
+-	if (vega10_get_current_rpm(hwmgr, &current_rpm))
+-		return -1;
++	duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
++				CG_FDO_CTRL1, FMAX_DUTY100);
++	duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
++				CG_THERMAL_STATUS, FDO_PWM_DUTY);
+ 
+-	if (hwmgr->thermal_controller.
+-			advanceFanControlParameters.usMaxFanRPM != 0)
+-		percent = current_rpm * 255 /
+-			hwmgr->thermal_controller.
+-			advanceFanControlParameters.usMaxFanRPM;
++	if (!duty100)
++		return -EINVAL;
+ 
+-	*speed = MIN(percent, 255);
++	tmp64 = (uint64_t)duty * 255;
++	do_div(tmp64, duty100);
++	*speed = MIN((uint32_t)tmp64, 255);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+index f816b1dd110ee..44bbf17e4bef1 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+@@ -568,6 +568,10 @@ struct smu_context
+ 	u32 param_reg;
+ 	u32 msg_reg;
+ 	u32 resp_reg;
++
++	u32 debug_param_reg;
++	u32 debug_msg_reg;
++	u32 debug_resp_reg;
+ };
+ 
+ struct i2c_adapter;
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
+index 9ebb8f39732a0..8b8266890a100 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
+@@ -131,7 +131,13 @@
+ #define PPSMC_MSG_EnableAudioStutterWA           0x44
+ #define PPSMC_MSG_PowerUpUmsch                   0x45
+ #define PPSMC_MSG_PowerDownUmsch                 0x46
+-#define PPSMC_Message_Count                      0x47
++#define PPSMC_MSG_SetDcsArch                     0x47
++#define PPSMC_MSG_TriggerVFFLR                   0x48
++#define PPSMC_MSG_SetNumBadMemoryPagesRetired    0x49
++#define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A
++#define PPSMC_MSG_SetPriorityDeltaGain           0x4B
++#define PPSMC_MSG_AllowIHHostInterrupt           0x4C
++#define PPSMC_Message_Count                      0x4D
+ 
+ //Debug Dump Message
+ #define DEBUGSMC_MSG_TestMessage                    0x1
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+index 58098b82df660..4180c71d930f1 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+@@ -239,7 +239,10 @@
+ 	__SMU_DUMMY_MAP(DriverMode2Reset), \
+ 	__SMU_DUMMY_MAP(GetGfxOffStatus),		 \
+ 	__SMU_DUMMY_MAP(GetGfxOffEntryCount),		 \
+-	__SMU_DUMMY_MAP(LogGfxOffResidency),
++	__SMU_DUMMY_MAP(LogGfxOffResidency),			\
++	__SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired),		\
++	__SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel), \
++	__SMU_DUMMY_MAP(AllowGpo),
+ 
+ #undef __SMU_DUMMY_MAP
+ #define __SMU_DUMMY_MAP(type)	SMU_MSG_##type
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+index a9122b3b15322..e8c6febb8b64e 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+@@ -273,6 +273,9 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu);
+ 
+ int smu_v13_0_run_btc(struct smu_context *smu);
+ 
++int smu_v13_0_gpo_control(struct smu_context *smu,
++			  bool enablement);
++
+ int smu_v13_0_deep_sleep_control(struct smu_context *smu,
+ 				 bool enablement);
+ 
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+index 8e4830a311bde..9f9f64c5cdd88 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+@@ -1258,7 +1258,8 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
+ 				uint32_t speed)
+ {
+ 	struct amdgpu_device *adev = smu->adev;
+-	uint32_t tach_period, crystal_clock_freq;
++	uint32_t crystal_clock_freq = 2500;
++	uint32_t tach_period;
+ 	int ret;
+ 
+ 	if (!speed)
+@@ -1268,7 +1269,6 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
+ 	if (ret)
+ 		return ret;
+ 
+-	crystal_clock_freq = amdgpu_asic_get_xclk(adev);
+ 	tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+ 	WREG32_SOC15(THM, 0, regCG_TACH_CTRL,
+ 		     REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL),
+@@ -2148,6 +2148,21 @@ int smu_v13_0_run_btc(struct smu_context *smu)
+ 	return res;
+ }
+ 
++int smu_v13_0_gpo_control(struct smu_context *smu,
++			  bool enablement)
++{
++	int res;
++
++	res = smu_cmn_send_smc_msg_with_param(smu,
++					      SMU_MSG_AllowGpo,
++					      enablement ? 1 : 0,
++					      NULL);
++	if (res)
++		dev_err(smu->adev->dev, "SetGpoAllow %d failed!\n", enablement);
++
++	return res;
++}
++
+ int smu_v13_0_deep_sleep_control(struct smu_context *smu,
+ 				 bool enablement)
+ {
+@@ -2249,6 +2264,10 @@ bool smu_v13_0_baco_is_support(struct smu_context *smu)
+ 	    !smu_baco->platform_support)
+ 		return false;
+ 
++	/* return true if ASIC is in BACO state already */
++	if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER)
++		return true;
++
+ 	if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) &&
+ 	    !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
+ 		return false;
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+index b8430601304f0..4c20d17e7416e 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+@@ -70,6 +70,26 @@
+ 
+ #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE	0x4000
+ 
++#define mmMP1_SMN_C2PMSG_66                                                                            0x0282
++#define mmMP1_SMN_C2PMSG_66_BASE_IDX                                                                   0
++
++#define mmMP1_SMN_C2PMSG_82                                                                            0x0292
++#define mmMP1_SMN_C2PMSG_82_BASE_IDX                                                                   0
++
++#define mmMP1_SMN_C2PMSG_90                                                                            0x029a
++#define mmMP1_SMN_C2PMSG_90_BASE_IDX                                                                   0
++
++#define mmMP1_SMN_C2PMSG_75                                                                            0x028b
++#define mmMP1_SMN_C2PMSG_75_BASE_IDX                                                                   0
++
++#define mmMP1_SMN_C2PMSG_53                                                                            0x0275
++#define mmMP1_SMN_C2PMSG_53_BASE_IDX                                                                   0
++
++#define mmMP1_SMN_C2PMSG_54                                                                            0x0276
++#define mmMP1_SMN_C2PMSG_54_BASE_IDX                                                                   0
++
++#define DEBUGSMC_MSG_Mode1Reset	2
++
+ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = {
+ 	MSG_MAP(TestMessage,			PPSMC_MSG_TestMessage,                 1),
+ 	MSG_MAP(GetSmuVersion,			PPSMC_MSG_GetSmuVersion,               1),
+@@ -121,6 +141,10 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
+ 	MSG_MAP(PrepareMp1ForUnload,		PPSMC_MSG_PrepareMp1ForUnload,         0),
+ 	MSG_MAP(DFCstateControl,		PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
+ 	MSG_MAP(ArmD3,				PPSMC_MSG_ArmD3,                       0),
++	MSG_MAP(SetNumBadMemoryPagesRetired,	PPSMC_MSG_SetNumBadMemoryPagesRetired,   0),
++	MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel,
++			    PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,   0),
++	MSG_MAP(AllowGpo,			PPSMC_MSG_SetGpoAllow,           0),
+ };
+ 
+ static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
+@@ -189,6 +213,7 @@ static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] =
+ 	FEA_MAP(SOC_PCC),
+ 	[SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
+ 	[SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
++	[SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
+ };
+ 
+ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
+@@ -1878,6 +1903,69 @@ static int smu_v13_0_0_set_df_cstate(struct smu_context *smu,
+ 					       NULL);
+ }
+ 
++static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
++{
++	int ret;
++	struct amdgpu_device *adev = smu->adev;
++
++	if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
++		ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
++	else
++		ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL);
++
++	if (!ret)
++		msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
++
++	return ret;
++}
++
++static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu)
++{
++	struct amdgpu_device *adev = smu->adev;
++
++	smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
++	smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
++	smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
++
++	smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
++	smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
++	smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
++}
++
++static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu,
++		uint32_t size)
++{
++	int ret = 0;
++
++	/* message SMU to update the bad page number on SMUBUS */
++	ret = smu_cmn_send_smc_msg_with_param(smu,
++					  SMU_MSG_SetNumBadMemoryPagesRetired,
++					  size, NULL);
++	if (ret)
++		dev_err(smu->adev->dev,
++			  "[%s] failed to message SMU to update bad memory pages number\n",
++			  __func__);
++
++	return ret;
++}
++
++static int smu_v13_0_0_send_bad_mem_channel_flag(struct smu_context *smu,
++		uint32_t size)
++{
++	int ret = 0;
++
++	/* message SMU to update the bad channel info on SMUBUS */
++	ret = smu_cmn_send_smc_msg_with_param(smu,
++				  SMU_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,
++				  size, NULL);
++	if (ret)
++		dev_err(smu->adev->dev,
++			  "[%s] failed to message SMU to update bad memory pages channel info\n",
++			  __func__);
++
++	return ret;
++}
++
+ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
+ 	.get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
+ 	.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
+@@ -1945,9 +2033,12 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
+ 	.baco_enter = smu_v13_0_0_baco_enter,
+ 	.baco_exit = smu_v13_0_0_baco_exit,
+ 	.mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported,
+-	.mode1_reset = smu_v13_0_mode1_reset,
++	.mode1_reset = smu_v13_0_0_mode1_reset,
+ 	.set_mp1_state = smu_v13_0_0_set_mp1_state,
+ 	.set_df_cstate = smu_v13_0_0_set_df_cstate,
++	.send_hbm_bad_pages_num = smu_v13_0_0_smu_send_bad_mem_page_num,
++	.send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
++	.gpo_control = smu_v13_0_gpo_control,
+ };
+ 
+ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
+@@ -1959,5 +2050,5 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
+ 	smu->table_map = smu_v13_0_0_table_map;
+ 	smu->pwr_src_map = smu_v13_0_0_pwr_src_map;
+ 	smu->workload_map = smu_v13_0_0_workload_map;
+-	smu_v13_0_set_smu_mailbox_registers(smu);
++	smu_v13_0_0_set_smu_mailbox_registers(smu);
+ }
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+index 222924363a681..eea06939e7da1 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+@@ -123,6 +123,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
+ 	MSG_MAP(SetMGpuFanBoostLimitRpm,	PPSMC_MSG_SetMGpuFanBoostLimitRpm,     0),
+ 	MSG_MAP(DFCstateControl,		PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
+ 	MSG_MAP(ArmD3,				PPSMC_MSG_ArmD3,                       0),
++	MSG_MAP(AllowGpo,			PPSMC_MSG_SetGpoAllow,           0),
+ };
+ 
+ static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
+@@ -191,6 +192,7 @@ static struct cmn2asic_mapping smu_v13_0_7_feature_mask_map[SMU_FEATURE_COUNT] =
+ 	FEA_MAP(SOC_PCC),
+ 	[SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
+ 	[SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
++	[SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
+ };
+ 
+ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {
+@@ -1711,6 +1713,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
+ 	.mode1_reset = smu_v13_0_mode1_reset,
+ 	.set_mp1_state = smu_v13_0_7_set_mp1_state,
+ 	.set_df_cstate = smu_v13_0_7_set_df_cstate,
++	.gpo_control = smu_v13_0_gpo_control,
+ };
+ 
+ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+index e4f8f90ac5aa0..768b6e7dbd771 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+@@ -233,6 +233,18 @@ static void __smu_cmn_send_msg(struct smu_context *smu,
+ 	WREG32(smu->msg_reg, msg);
+ }
+ 
++static int __smu_cmn_send_debug_msg(struct smu_context *smu,
++			       u32 msg,
++			       u32 param)
++{
++	struct amdgpu_device *adev = smu->adev;
++
++	WREG32(smu->debug_param_reg, param);
++	WREG32(smu->debug_msg_reg, msg);
++	WREG32(smu->debug_resp_reg, 0);
++
++	return 0;
++}
+ /**
+  * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status
+  * @smu: pointer to an SMU context
+@@ -386,6 +398,12 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
+ 					       read_arg);
+ }
+ 
++int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
++			 uint32_t msg)
++{
++	return __smu_cmn_send_debug_msg(smu, msg, 0);
++}
++
+ int smu_cmn_to_asic_specific_index(struct smu_context *smu,
+ 				   enum smu_cmn2asic_mapping_type type,
+ 				   uint32_t index)
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+index 1526ce09c399b..f82cf76dd3a47 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+@@ -42,6 +42,9 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
+ 			 enum smu_message_type msg,
+ 			 uint32_t *read_arg);
+ 
++int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
++			 uint32_t msg);
++
+ int smu_cmn_wait_for_response(struct smu_context *smu);
+ 
+ int smu_cmn_to_asic_specific_index(struct smu_context *smu,
+diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
+index 11bb593994718..3d1f50f481cfd 100644
+--- a/drivers/gpu/drm/drm_buddy.c
++++ b/drivers/gpu/drm/drm_buddy.c
+@@ -38,6 +38,25 @@ static void drm_block_free(struct drm_buddy *mm,
+ 	kmem_cache_free(slab_blocks, block);
+ }
+ 
++static void list_insert_sorted(struct drm_buddy *mm,
++			       struct drm_buddy_block *block)
++{
++	struct drm_buddy_block *node;
++	struct list_head *head;
++
++	head = &mm->free_list[drm_buddy_block_order(block)];
++	if (list_empty(head)) {
++		list_add(&block->link, head);
++		return;
++	}
++
++	list_for_each_entry(node, head, link)
++		if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node))
++			break;
++
++	__list_add(&block->link, node->link.prev, &node->link);
++}
++
+ static void mark_allocated(struct drm_buddy_block *block)
+ {
+ 	block->header &= ~DRM_BUDDY_HEADER_STATE;
+@@ -52,8 +71,7 @@ static void mark_free(struct drm_buddy *mm,
+ 	block->header &= ~DRM_BUDDY_HEADER_STATE;
+ 	block->header |= DRM_BUDDY_FREE;
+ 
+-	list_add(&block->link,
+-		 &mm->free_list[drm_buddy_block_order(block)]);
++	list_insert_sorted(mm, block);
+ }
+ 
+ static void mark_split(struct drm_buddy_block *block)
+@@ -387,20 +405,26 @@ err_undo:
+ }
+ 
+ static struct drm_buddy_block *
+-get_maxblock(struct list_head *head)
++get_maxblock(struct drm_buddy *mm, unsigned int order)
+ {
+ 	struct drm_buddy_block *max_block = NULL, *node;
++	unsigned int i;
+ 
+-	max_block = list_first_entry_or_null(head,
+-					     struct drm_buddy_block,
+-					     link);
+-	if (!max_block)
+-		return NULL;
++	for (i = order; i <= mm->max_order; ++i) {
++		if (!list_empty(&mm->free_list[i])) {
++			node = list_last_entry(&mm->free_list[i],
++					       struct drm_buddy_block,
++					       link);
++			if (!max_block) {
++				max_block = node;
++				continue;
++			}
+ 
+-	list_for_each_entry(node, head, link) {
+-		if (drm_buddy_block_offset(node) >
+-		    drm_buddy_block_offset(max_block))
+-			max_block = node;
++			if (drm_buddy_block_offset(node) >
++			    drm_buddy_block_offset(max_block)) {
++				max_block = node;
++			}
++		}
+ 	}
+ 
+ 	return max_block;
+@@ -412,20 +436,23 @@ alloc_from_freelist(struct drm_buddy *mm,
+ 		    unsigned long flags)
+ {
+ 	struct drm_buddy_block *block = NULL;
+-	unsigned int i;
++	unsigned int tmp;
+ 	int err;
+ 
+-	for (i = order; i <= mm->max_order; ++i) {
+-		if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
+-			block = get_maxblock(&mm->free_list[i]);
+-			if (block)
+-				break;
+-		} else {
+-			block = list_first_entry_or_null(&mm->free_list[i],
+-							 struct drm_buddy_block,
+-							 link);
+-			if (block)
+-				break;
++	if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
++		block = get_maxblock(mm, order);
++		if (block)
++			/* Store the obtained block order */
++			tmp = drm_buddy_block_order(block);
++	} else {
++		for (tmp = order; tmp <= mm->max_order; ++tmp) {
++			if (!list_empty(&mm->free_list[tmp])) {
++				block = list_last_entry(&mm->free_list[tmp],
++							struct drm_buddy_block,
++							link);
++				if (block)
++					break;
++			}
+ 		}
+ 	}
+ 
+@@ -434,18 +461,18 @@ alloc_from_freelist(struct drm_buddy *mm,
+ 
+ 	BUG_ON(!drm_buddy_block_is_free(block));
+ 
+-	while (i != order) {
++	while (tmp != order) {
+ 		err = split_block(mm, block);
+ 		if (unlikely(err))
+ 			goto err_undo;
+ 
+ 		block = block->right;
+-		i--;
++		tmp--;
+ 	}
+ 	return block;
+ 
+ err_undo:
+-	if (i != order)
++	if (tmp != order)
+ 		__drm_buddy_free(mm, block);
+ 	return ERR_PTR(err);
+ }
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+index 1e29b1e6d1868..2353723ca1bd2 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+@@ -1688,6 +1688,10 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
+ 	init_contexts(&i915->gem.contexts);
+ }
+ 
++/*
++ * Note that this implicitly consumes the ctx reference, by placing
++ * the ctx in the context_xa.
++ */
+ static void gem_context_register(struct i915_gem_context *ctx,
+ 				 struct drm_i915_file_private *fpriv,
+ 				 u32 id)
+@@ -1703,10 +1707,6 @@ static void gem_context_register(struct i915_gem_context *ctx,
+ 	snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
+ 		 current->comm, pid_nr(ctx->pid));
+ 
+-	/* And finally expose ourselves to userspace via the idr */
+-	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
+-	WARN_ON(old);
+-
+ 	spin_lock(&ctx->client->ctx_lock);
+ 	list_add_tail_rcu(&ctx->client_link, &ctx->client->ctx_list);
+ 	spin_unlock(&ctx->client->ctx_lock);
+@@ -1714,6 +1714,10 @@ static void gem_context_register(struct i915_gem_context *ctx,
+ 	spin_lock(&i915->gem.contexts.lock);
+ 	list_add_tail(&ctx->link, &i915->gem.contexts.list);
+ 	spin_unlock(&i915->gem.contexts.lock);
++
++	/* And finally expose ourselves to userspace via the idr */
++	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
++	WARN_ON(old);
+ }
+ 
+ int i915_gem_context_open(struct drm_i915_private *i915,
+@@ -2199,14 +2203,22 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv,
+ 	if (IS_ERR(ctx))
+ 		return ctx;
+ 
++	/*
++	 * One for the xarray and one for the caller.  We need to grab
++	 * the reference *prior* to making the ctx visble to userspace
++	 * in gem_context_register(), as at any point after that
++	 * userspace can try to race us with another thread destroying
++	 * the context under our feet.
++	 */
++	i915_gem_context_get(ctx);
++
+ 	gem_context_register(ctx, file_priv, id);
+ 
+ 	old = xa_erase(&file_priv->proto_context_xa, id);
+ 	GEM_BUG_ON(old != pc);
+ 	proto_context_close(file_priv->dev_priv, pc);
+ 
+-	/* One for the xarray and one for the caller */
+-	return i915_gem_context_get(ctx);
++	return ctx;
+ }
+ 
+ struct i915_gem_context *
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+index 83bfeb872bdaa..fcbccd8d244e9 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+@@ -1343,8 +1343,13 @@ int intel_engines_init(struct intel_gt *gt)
+ 			return err;
+ 
+ 		err = setup(engine);
+-		if (err)
++		if (err) {
++			intel_engine_cleanup_common(engine);
+ 			return err;
++		}
++
++		/* The backend should now be responsible for cleanup */
++		GEM_BUG_ON(engine->release == NULL);
+ 
+ 		err = engine_init_common(engine);
+ 		if (err)
+diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
+index d651ccd0ab20b..9486dd3bed991 100644
+--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
++++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
+@@ -22,11 +22,9 @@ bool is_object_gt(struct kobject *kobj)
+ 	return !strncmp(kobj->name, "gt", 2);
+ }
+ 
+-struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
++struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
+ 					    const char *name)
+ {
+-	struct kobject *kobj = &dev->kobj;
+-
+ 	/*
+ 	 * We are interested at knowing from where the interface
+ 	 * has been called, whether it's called from gt/ or from
+@@ -38,6 +36,7 @@ struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
+ 	 * "struct drm_i915_private *" type.
+ 	 */
+ 	if (!is_object_gt(kobj)) {
++		struct device *dev = kobj_to_dev(kobj);
+ 		struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
+ 
+ 		return to_gt(i915);
+@@ -51,18 +50,18 @@ static struct kobject *gt_get_parent_obj(struct intel_gt *gt)
+ 	return &gt->i915->drm.primary->kdev->kobj;
+ }
+ 
+-static ssize_t id_show(struct device *dev,
+-		       struct device_attribute *attr,
++static ssize_t id_show(struct kobject *kobj,
++		       struct kobj_attribute *attr,
+ 		       char *buf)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 
+ 	return sysfs_emit(buf, "%u\n", gt->info.id);
+ }
+-static DEVICE_ATTR_RO(id);
++static struct kobj_attribute attr_id = __ATTR_RO(id);
+ 
+ static struct attribute *id_attrs[] = {
+-	&dev_attr_id.attr,
++	&attr_id.attr,
+ 	NULL,
+ };
+ ATTRIBUTE_GROUPS(id);
+diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
+index 6232923a420d0..c3a123faee987 100644
+--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
++++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h
+@@ -30,7 +30,7 @@ static inline struct intel_gt *kobj_to_gt(struct kobject *kobj)
+ 
+ void intel_gt_sysfs_register(struct intel_gt *gt);
+ void intel_gt_sysfs_unregister(struct intel_gt *gt);
+-struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
++struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
+ 					    const char *name);
+ 
+ #endif /* SYSFS_GT_H */
+diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+index 180dd6f3ef571..b108f0a8a044c 100644
+--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
++++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+@@ -24,14 +24,15 @@ enum intel_gt_sysfs_op {
+ };
+ 
+ static int
+-sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
++sysfs_gt_attribute_w_func(struct kobject *kobj, struct attribute *attr,
+ 			  int (func)(struct intel_gt *gt, u32 val), u32 val)
+ {
+ 	struct intel_gt *gt;
+ 	int ret;
+ 
+-	if (!is_object_gt(&dev->kobj)) {
++	if (!is_object_gt(kobj)) {
+ 		int i;
++		struct device *dev = kobj_to_dev(kobj);
+ 		struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
+ 
+ 		for_each_gt(gt, i915, i) {
+@@ -40,7 +41,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
+ 				break;
+ 		}
+ 	} else {
+-		gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++		gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
+ 		ret = func(gt, val);
+ 	}
+ 
+@@ -48,7 +49,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
+ }
+ 
+ static u32
+-sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
++sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr,
+ 			  u32 (func)(struct intel_gt *gt),
+ 			  enum intel_gt_sysfs_op op)
+ {
+@@ -57,8 +58,9 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
+ 
+ 	ret = (op == INTEL_GT_SYSFS_MAX) ? 0 : (u32) -1;
+ 
+-	if (!is_object_gt(&dev->kobj)) {
++	if (!is_object_gt(kobj)) {
+ 		int i;
++		struct device *dev = kobj_to_dev(kobj);
+ 		struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
+ 
+ 		for_each_gt(gt, i915, i) {
+@@ -77,7 +79,7 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
+ 			}
+ 		}
+ 	} else {
+-		gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++		gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
+ 		ret = func(gt);
+ 	}
+ 
+@@ -92,6 +94,76 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
+ #define sysfs_gt_attribute_r_max_func(d, a, f) \
+ 		sysfs_gt_attribute_r_func(d, a, f, INTEL_GT_SYSFS_MAX)
+ 
++#define INTEL_GT_SYSFS_SHOW(_name, _attr_type)							\
++	static ssize_t _name##_show_common(struct kobject *kobj,				\
++					   struct attribute *attr, char *buff)			\
++	{											\
++		u32 val = sysfs_gt_attribute_r_##_attr_type##_func(kobj, attr,			\
++								   __##_name##_show);		\
++												\
++		return sysfs_emit(buff, "%u\n", val);						\
++	}											\
++	static ssize_t _name##_show(struct kobject *kobj,					\
++				    struct kobj_attribute *attr, char *buff)			\
++	{											\
++		return _name ##_show_common(kobj, &attr->attr, buff);				\
++	}											\
++	static ssize_t _name##_dev_show(struct device *dev,					\
++					struct device_attribute *attr, char *buff)		\
++	{											\
++		return _name##_show_common(&dev->kobj, &attr->attr, buff);			\
++	}
++
++#define INTEL_GT_SYSFS_STORE(_name, _func)						\
++	static ssize_t _name##_store_common(struct kobject *kobj,			\
++					    struct attribute *attr,			\
++					    const char *buff, size_t count)		\
++	{										\
++		int ret;								\
++		u32 val;								\
++											\
++		ret = kstrtou32(buff, 0, &val);						\
++		if (ret)								\
++			return ret;							\
++											\
++		ret = sysfs_gt_attribute_w_func(kobj, attr, _func, val);		\
++											\
++		return ret ?: count;							\
++	}										\
++	static ssize_t _name##_store(struct kobject *kobj,				\
++				     struct kobj_attribute *attr, const char *buff,	\
++				     size_t count)					\
++	{										\
++		return _name##_store_common(kobj, &attr->attr, buff, count);		\
++	}										\
++	static ssize_t _name##_dev_store(struct device *dev,				\
++					 struct device_attribute *attr,			\
++					 const char *buff, size_t count)		\
++	{										\
++		return _name##_store_common(&dev->kobj, &attr->attr, buff, count);	\
++	}
++
++#define INTEL_GT_SYSFS_SHOW_MAX(_name) INTEL_GT_SYSFS_SHOW(_name, max)
++#define INTEL_GT_SYSFS_SHOW_MIN(_name) INTEL_GT_SYSFS_SHOW(_name, min)
++
++#define INTEL_GT_ATTR_RW(_name) \
++	static struct kobj_attribute attr_##_name = __ATTR_RW(_name)
++
++#define INTEL_GT_ATTR_RO(_name) \
++	static struct kobj_attribute attr_##_name = __ATTR_RO(_name)
++
++#define INTEL_GT_DUAL_ATTR_RW(_name) \
++	static struct device_attribute dev_attr_##_name = __ATTR(_name, 0644,		\
++								 _name##_dev_show,	\
++								 _name##_dev_store);	\
++	INTEL_GT_ATTR_RW(_name)
++
++#define INTEL_GT_DUAL_ATTR_RO(_name) \
++	static struct device_attribute dev_attr_##_name = __ATTR(_name, 0444,		\
++								 _name##_dev_show,	\
++								 NULL);			\
++	INTEL_GT_ATTR_RO(_name)
++
+ #ifdef CONFIG_PM
+ static u32 get_residency(struct intel_gt *gt, i915_reg_t reg)
+ {
+@@ -104,11 +176,8 @@ static u32 get_residency(struct intel_gt *gt, i915_reg_t reg)
+ 	return DIV_ROUND_CLOSEST_ULL(res, 1000);
+ }
+ 
+-static ssize_t rc6_enable_show(struct device *dev,
+-			       struct device_attribute *attr,
+-			       char *buff)
++static u8 get_rc6_mask(struct intel_gt *gt)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
+ 	u8 mask = 0;
+ 
+ 	if (HAS_RC6(gt->i915))
+@@ -118,37 +187,35 @@ static ssize_t rc6_enable_show(struct device *dev,
+ 	if (HAS_RC6pp(gt->i915))
+ 		mask |= BIT(2);
+ 
+-	return sysfs_emit(buff, "%x\n", mask);
++	return mask;
+ }
+ 
+-static u32 __rc6_residency_ms_show(struct intel_gt *gt)
++static ssize_t rc6_enable_show(struct kobject *kobj,
++			       struct kobj_attribute *attr,
++			       char *buff)
+ {
+-	return get_residency(gt, GEN6_GT_GFX_RC6);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
++
++	return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
+ }
+ 
+-static ssize_t rc6_residency_ms_show(struct device *dev,
+-				     struct device_attribute *attr,
+-				     char *buff)
++static ssize_t rc6_enable_dev_show(struct device *dev,
++				   struct device_attribute *attr,
++				   char *buff)
+ {
+-	u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
+-						      __rc6_residency_ms_show);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name);
+ 
+-	return sysfs_emit(buff, "%u\n", rc6_residency);
++	return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
+ }
+ 
+-static u32 __rc6p_residency_ms_show(struct intel_gt *gt)
++static u32 __rc6_residency_ms_show(struct intel_gt *gt)
+ {
+-	return get_residency(gt, GEN6_GT_GFX_RC6p);
++	return get_residency(gt, GEN6_GT_GFX_RC6);
+ }
+ 
+-static ssize_t rc6p_residency_ms_show(struct device *dev,
+-				      struct device_attribute *attr,
+-				      char *buff)
++static u32 __rc6p_residency_ms_show(struct intel_gt *gt)
+ {
+-	u32 rc6p_residency = sysfs_gt_attribute_r_min_func(dev, attr,
+-						__rc6p_residency_ms_show);
+-
+-	return sysfs_emit(buff, "%u\n", rc6p_residency);
++	return get_residency(gt, GEN6_GT_GFX_RC6p);
+ }
+ 
+ static u32 __rc6pp_residency_ms_show(struct intel_gt *gt)
+@@ -156,67 +223,69 @@ static u32 __rc6pp_residency_ms_show(struct intel_gt *gt)
+ 	return get_residency(gt, GEN6_GT_GFX_RC6pp);
+ }
+ 
+-static ssize_t rc6pp_residency_ms_show(struct device *dev,
+-				       struct device_attribute *attr,
+-				       char *buff)
+-{
+-	u32 rc6pp_residency = sysfs_gt_attribute_r_min_func(dev, attr,
+-						__rc6pp_residency_ms_show);
+-
+-	return sysfs_emit(buff, "%u\n", rc6pp_residency);
+-}
+-
+ static u32 __media_rc6_residency_ms_show(struct intel_gt *gt)
+ {
+ 	return get_residency(gt, VLV_GT_MEDIA_RC6);
+ }
+ 
+-static ssize_t media_rc6_residency_ms_show(struct device *dev,
+-					   struct device_attribute *attr,
+-					   char *buff)
+-{
+-	u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
+-						__media_rc6_residency_ms_show);
++INTEL_GT_SYSFS_SHOW_MIN(rc6_residency_ms);
++INTEL_GT_SYSFS_SHOW_MIN(rc6p_residency_ms);
++INTEL_GT_SYSFS_SHOW_MIN(rc6pp_residency_ms);
++INTEL_GT_SYSFS_SHOW_MIN(media_rc6_residency_ms);
+ 
+-	return sysfs_emit(buff, "%u\n", rc6_residency);
+-}
+-
+-static DEVICE_ATTR_RO(rc6_enable);
+-static DEVICE_ATTR_RO(rc6_residency_ms);
+-static DEVICE_ATTR_RO(rc6p_residency_ms);
+-static DEVICE_ATTR_RO(rc6pp_residency_ms);
+-static DEVICE_ATTR_RO(media_rc6_residency_ms);
++INTEL_GT_DUAL_ATTR_RO(rc6_enable);
++INTEL_GT_DUAL_ATTR_RO(rc6_residency_ms);
++INTEL_GT_DUAL_ATTR_RO(rc6p_residency_ms);
++INTEL_GT_DUAL_ATTR_RO(rc6pp_residency_ms);
++INTEL_GT_DUAL_ATTR_RO(media_rc6_residency_ms);
+ 
+ static struct attribute *rc6_attrs[] = {
++	&attr_rc6_enable.attr,
++	&attr_rc6_residency_ms.attr,
++	NULL
++};
++
++static struct attribute *rc6p_attrs[] = {
++	&attr_rc6p_residency_ms.attr,
++	&attr_rc6pp_residency_ms.attr,
++	NULL
++};
++
++static struct attribute *media_rc6_attrs[] = {
++	&attr_media_rc6_residency_ms.attr,
++	NULL
++};
++
++static struct attribute *rc6_dev_attrs[] = {
+ 	&dev_attr_rc6_enable.attr,
+ 	&dev_attr_rc6_residency_ms.attr,
+ 	NULL
+ };
+ 
+-static struct attribute *rc6p_attrs[] = {
++static struct attribute *rc6p_dev_attrs[] = {
+ 	&dev_attr_rc6p_residency_ms.attr,
+ 	&dev_attr_rc6pp_residency_ms.attr,
+ 	NULL
+ };
+ 
+-static struct attribute *media_rc6_attrs[] = {
++static struct attribute *media_rc6_dev_attrs[] = {
+ 	&dev_attr_media_rc6_residency_ms.attr,
+ 	NULL
+ };
+ 
+ static const struct attribute_group rc6_attr_group[] = {
+ 	{ .attrs = rc6_attrs, },
+-	{ .name = power_group_name, .attrs = rc6_attrs, },
++	{ .name = power_group_name, .attrs = rc6_dev_attrs, },
+ };
+ 
+ static const struct attribute_group rc6p_attr_group[] = {
+ 	{ .attrs = rc6p_attrs, },
+-	{ .name = power_group_name, .attrs = rc6p_attrs, },
++	{ .name = power_group_name, .attrs = rc6p_dev_attrs, },
+ };
+ 
+ static const struct attribute_group media_rc6_attr_group[] = {
+ 	{ .attrs = media_rc6_attrs, },
+-	{ .name = power_group_name, .attrs = media_rc6_attrs, },
++	{ .name = power_group_name, .attrs = media_rc6_dev_attrs, },
+ };
+ 
+ static int __intel_gt_sysfs_create_group(struct kobject *kobj,
+@@ -271,104 +340,34 @@ static u32 __act_freq_mhz_show(struct intel_gt *gt)
+ 	return intel_rps_read_actual_frequency(&gt->rps);
+ }
+ 
+-static ssize_t act_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 actual_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						    __act_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", actual_freq);
+-}
+-
+ static u32 __cur_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	return intel_rps_get_requested_frequency(&gt->rps);
+ }
+ 
+-static ssize_t cur_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 cur_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						 __cur_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", cur_freq);
+-}
+-
+ static u32 __boost_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	return intel_rps_get_boost_frequency(&gt->rps);
+ }
+ 
+-static ssize_t boost_freq_mhz_show(struct device *dev,
+-				   struct device_attribute *attr,
+-				   char *buff)
+-{
+-	u32 boost_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						   __boost_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", boost_freq);
+-}
+-
+ static int __boost_freq_mhz_store(struct intel_gt *gt, u32 val)
+ {
+ 	return intel_rps_set_boost_frequency(&gt->rps, val);
+ }
+ 
+-static ssize_t boost_freq_mhz_store(struct device *dev,
+-				    struct device_attribute *attr,
+-				    const char *buff, size_t count)
+-{
+-	ssize_t ret;
+-	u32 val;
+-
+-	ret = kstrtou32(buff, 0, &val);
+-	if (ret)
+-		return ret;
+-
+-	return sysfs_gt_attribute_w_func(dev, attr,
+-					 __boost_freq_mhz_store, val) ?: count;
+-}
+-
+-static u32 __rp0_freq_mhz_show(struct intel_gt *gt)
++static u32 __RP0_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	return intel_rps_get_rp0_frequency(&gt->rps);
+ }
+ 
+-static ssize_t RP0_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 rp0_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						     __rp0_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", rp0_freq);
+-}
+-
+-static u32 __rp1_freq_mhz_show(struct intel_gt *gt)
+-{
+-	return intel_rps_get_rp1_frequency(&gt->rps);
+-}
+-
+-static ssize_t RP1_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 rp1_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						     __rp1_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", rp1_freq);
+-}
+-
+-static u32 __rpn_freq_mhz_show(struct intel_gt *gt)
++static u32 __RPn_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	return intel_rps_get_rpn_frequency(&gt->rps);
+ }
+ 
+-static ssize_t RPn_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
++static u32 __RP1_freq_mhz_show(struct intel_gt *gt)
+ {
+-	u32 rpn_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						     __rpn_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", rpn_freq);
++	return intel_rps_get_rp1_frequency(&gt->rps);
+ }
+ 
+ static u32 __max_freq_mhz_show(struct intel_gt *gt)
+@@ -376,71 +375,21 @@ static u32 __max_freq_mhz_show(struct intel_gt *gt)
+ 	return intel_rps_get_max_frequency(&gt->rps);
+ }
+ 
+-static ssize_t max_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 max_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						     __max_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", max_freq);
+-}
+-
+ static int __set_max_freq(struct intel_gt *gt, u32 val)
+ {
+ 	return intel_rps_set_max_frequency(&gt->rps, val);
+ }
+ 
+-static ssize_t max_freq_mhz_store(struct device *dev,
+-				  struct device_attribute *attr,
+-				  const char *buff, size_t count)
+-{
+-	int ret;
+-	u32 val;
+-
+-	ret = kstrtou32(buff, 0, &val);
+-	if (ret)
+-		return ret;
+-
+-	ret = sysfs_gt_attribute_w_func(dev, attr, __set_max_freq, val);
+-
+-	return ret ?: count;
+-}
+-
+ static u32 __min_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	return intel_rps_get_min_frequency(&gt->rps);
+ }
+ 
+-static ssize_t min_freq_mhz_show(struct device *dev,
+-				 struct device_attribute *attr, char *buff)
+-{
+-	u32 min_freq = sysfs_gt_attribute_r_min_func(dev, attr,
+-						     __min_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", min_freq);
+-}
+-
+ static int __set_min_freq(struct intel_gt *gt, u32 val)
+ {
+ 	return intel_rps_set_min_frequency(&gt->rps, val);
+ }
+ 
+-static ssize_t min_freq_mhz_store(struct device *dev,
+-				  struct device_attribute *attr,
+-				  const char *buff, size_t count)
+-{
+-	int ret;
+-	u32 val;
+-
+-	ret = kstrtou32(buff, 0, &val);
+-	if (ret)
+-		return ret;
+-
+-	ret = sysfs_gt_attribute_w_func(dev, attr, __set_min_freq, val);
+-
+-	return ret ?: count;
+-}
+-
+ static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
+ {
+ 	struct intel_rps *rps = &gt->rps;
+@@ -448,23 +397,31 @@ static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
+ 	return intel_gpu_freq(rps, rps->efficient_freq);
+ }
+ 
+-static ssize_t vlv_rpe_freq_mhz_show(struct device *dev,
+-				     struct device_attribute *attr, char *buff)
+-{
+-	u32 rpe_freq = sysfs_gt_attribute_r_max_func(dev, attr,
+-						 __vlv_rpe_freq_mhz_show);
+-
+-	return sysfs_emit(buff, "%u\n", rpe_freq);
+-}
+-
+-#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store) \
+-	static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, _show, _store); \
+-	static struct device_attribute dev_attr_rps_##_name = __ATTR(rps_##_name, _mode, _show, _store)
+-
+-#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name)				\
+-		INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL)
+-#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name)				\
+-		INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store)
++INTEL_GT_SYSFS_SHOW_MAX(act_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(boost_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(cur_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(RP0_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(RP1_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(RPn_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(max_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MIN(min_freq_mhz);
++INTEL_GT_SYSFS_SHOW_MAX(vlv_rpe_freq_mhz);
++INTEL_GT_SYSFS_STORE(boost_freq_mhz, __boost_freq_mhz_store);
++INTEL_GT_SYSFS_STORE(max_freq_mhz, __set_max_freq);
++INTEL_GT_SYSFS_STORE(min_freq_mhz, __set_min_freq);
++
++#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store, _show_dev, _store_dev)		\
++	static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode,		\
++								    _show_dev, _store_dev);	\
++	static struct kobj_attribute attr_rps_##_name = __ATTR(rps_##_name, _mode,		\
++							       _show, _store)
++
++#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name)						\
++		INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL,		\
++					_name##_dev_show, NULL)
++#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name)						\
++		INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store,	\
++					_name##_dev_show, _name##_dev_store)
+ 
+ /* The below macros generate static structures */
+ INTEL_GT_RPS_SYSFS_ATTR_RO(act_freq_mhz);
+@@ -475,32 +432,31 @@ INTEL_GT_RPS_SYSFS_ATTR_RO(RP1_freq_mhz);
+ INTEL_GT_RPS_SYSFS_ATTR_RO(RPn_freq_mhz);
+ INTEL_GT_RPS_SYSFS_ATTR_RW(max_freq_mhz);
+ INTEL_GT_RPS_SYSFS_ATTR_RW(min_freq_mhz);
+-
+-static DEVICE_ATTR_RO(vlv_rpe_freq_mhz);
+-
+-#define GEN6_ATTR(s) { \
+-		&dev_attr_##s##_act_freq_mhz.attr, \
+-		&dev_attr_##s##_cur_freq_mhz.attr, \
+-		&dev_attr_##s##_boost_freq_mhz.attr, \
+-		&dev_attr_##s##_max_freq_mhz.attr, \
+-		&dev_attr_##s##_min_freq_mhz.attr, \
+-		&dev_attr_##s##_RP0_freq_mhz.attr, \
+-		&dev_attr_##s##_RP1_freq_mhz.attr, \
+-		&dev_attr_##s##_RPn_freq_mhz.attr, \
++INTEL_GT_RPS_SYSFS_ATTR_RO(vlv_rpe_freq_mhz);
++
++#define GEN6_ATTR(p, s) { \
++		&p##attr_##s##_act_freq_mhz.attr, \
++		&p##attr_##s##_cur_freq_mhz.attr, \
++		&p##attr_##s##_boost_freq_mhz.attr, \
++		&p##attr_##s##_max_freq_mhz.attr, \
++		&p##attr_##s##_min_freq_mhz.attr, \
++		&p##attr_##s##_RP0_freq_mhz.attr, \
++		&p##attr_##s##_RP1_freq_mhz.attr, \
++		&p##attr_##s##_RPn_freq_mhz.attr, \
+ 		NULL, \
+ 	}
+ 
+-#define GEN6_RPS_ATTR GEN6_ATTR(rps)
+-#define GEN6_GT_ATTR  GEN6_ATTR(gt)
++#define GEN6_RPS_ATTR GEN6_ATTR(, rps)
++#define GEN6_GT_ATTR  GEN6_ATTR(dev_, gt)
+ 
+ static const struct attribute * const gen6_rps_attrs[] = GEN6_RPS_ATTR;
+ static const struct attribute * const gen6_gt_attrs[]  = GEN6_GT_ATTR;
+ 
+-static ssize_t punit_req_freq_mhz_show(struct device *dev,
+-				       struct device_attribute *attr,
++static ssize_t punit_req_freq_mhz_show(struct kobject *kobj,
++				       struct kobj_attribute *attr,
+ 				       char *buff)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	u32 preq = intel_rps_read_punit_req_frequency(&gt->rps);
+ 
+ 	return sysfs_emit(buff, "%u\n", preq);
+@@ -508,17 +464,17 @@ static ssize_t punit_req_freq_mhz_show(struct device *dev,
+ 
+ struct intel_gt_bool_throttle_attr {
+ 	struct attribute attr;
+-	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
++	ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+ 			char *buf);
+ 	i915_reg_t reg32;
+ 	u32 mask;
+ };
+ 
+-static ssize_t throttle_reason_bool_show(struct device *dev,
+-					 struct device_attribute *attr,
++static ssize_t throttle_reason_bool_show(struct kobject *kobj,
++					 struct kobj_attribute *attr,
+ 					 char *buff)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	struct intel_gt_bool_throttle_attr *t_attr =
+ 				(struct intel_gt_bool_throttle_attr *) attr;
+ 	bool val = rps_read_mask_mmio(&gt->rps, t_attr->reg32, t_attr->mask);
+@@ -534,7 +490,7 @@ struct intel_gt_bool_throttle_attr attr_##sysfs_func__ = { \
+ 	.mask = mask__, \
+ }
+ 
+-static DEVICE_ATTR_RO(punit_req_freq_mhz);
++INTEL_GT_ATTR_RO(punit_req_freq_mhz);
+ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_status, GT0_PERF_LIMIT_REASONS_MASK);
+ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl1, POWER_LIMIT_1_MASK);
+ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl2, POWER_LIMIT_2_MASK);
+@@ -597,8 +553,8 @@ static const struct attribute *throttle_reason_attrs[] = {
+ #define U8_8_VAL_MASK           0xffff
+ #define U8_8_SCALE_TO_VALUE     "0.00390625"
+ 
+-static ssize_t freq_factor_scale_show(struct device *dev,
+-				      struct device_attribute *attr,
++static ssize_t freq_factor_scale_show(struct kobject *kobj,
++				      struct kobj_attribute *attr,
+ 				      char *buff)
+ {
+ 	return sysfs_emit(buff, "%s\n", U8_8_SCALE_TO_VALUE);
+@@ -610,11 +566,11 @@ static u32 media_ratio_mode_to_factor(u32 mode)
+ 	return !mode ? mode : 256 / mode;
+ }
+ 
+-static ssize_t media_freq_factor_show(struct device *dev,
+-				      struct device_attribute *attr,
++static ssize_t media_freq_factor_show(struct kobject *kobj,
++				      struct kobj_attribute *attr,
+ 				      char *buff)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
+ 	intel_wakeref_t wakeref;
+ 	u32 mode;
+@@ -641,11 +597,11 @@ static ssize_t media_freq_factor_show(struct device *dev,
+ 	return sysfs_emit(buff, "%u\n", media_ratio_mode_to_factor(mode));
+ }
+ 
+-static ssize_t media_freq_factor_store(struct device *dev,
+-				       struct device_attribute *attr,
++static ssize_t media_freq_factor_store(struct kobject *kobj,
++				       struct kobj_attribute *attr,
+ 				       const char *buff, size_t count)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
+ 	u32 factor, mode;
+ 	int err;
+@@ -670,11 +626,11 @@ static ssize_t media_freq_factor_store(struct device *dev,
+ 	return err ?: count;
+ }
+ 
+-static ssize_t media_RP0_freq_mhz_show(struct device *dev,
+-				       struct device_attribute *attr,
++static ssize_t media_RP0_freq_mhz_show(struct kobject *kobj,
++				       struct kobj_attribute *attr,
+ 				       char *buff)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	u32 val;
+ 	int err;
+ 
+@@ -691,11 +647,11 @@ static ssize_t media_RP0_freq_mhz_show(struct device *dev,
+ 	return sysfs_emit(buff, "%u\n", val);
+ }
+ 
+-static ssize_t media_RPn_freq_mhz_show(struct device *dev,
+-				       struct device_attribute *attr,
++static ssize_t media_RPn_freq_mhz_show(struct kobject *kobj,
++				       struct kobj_attribute *attr,
+ 				       char *buff)
+ {
+-	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
++	struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
+ 	u32 val;
+ 	int err;
+ 
+@@ -712,17 +668,17 @@ static ssize_t media_RPn_freq_mhz_show(struct device *dev,
+ 	return sysfs_emit(buff, "%u\n", val);
+ }
+ 
+-static DEVICE_ATTR_RW(media_freq_factor);
+-static struct device_attribute dev_attr_media_freq_factor_scale =
++INTEL_GT_ATTR_RW(media_freq_factor);
++static struct kobj_attribute attr_media_freq_factor_scale =
+ 	__ATTR(media_freq_factor.scale, 0444, freq_factor_scale_show, NULL);
+-static DEVICE_ATTR_RO(media_RP0_freq_mhz);
+-static DEVICE_ATTR_RO(media_RPn_freq_mhz);
++INTEL_GT_ATTR_RO(media_RP0_freq_mhz);
++INTEL_GT_ATTR_RO(media_RPn_freq_mhz);
+ 
+ static const struct attribute *media_perf_power_attrs[] = {
+-	&dev_attr_media_freq_factor.attr,
+-	&dev_attr_media_freq_factor_scale.attr,
+-	&dev_attr_media_RP0_freq_mhz.attr,
+-	&dev_attr_media_RPn_freq_mhz.attr,
++	&attr_media_freq_factor.attr,
++	&attr_media_freq_factor_scale.attr,
++	&attr_media_RP0_freq_mhz.attr,
++	&attr_media_RPn_freq_mhz.attr,
+ 	NULL
+ };
+ 
+@@ -754,20 +710,29 @@ static const struct attribute * const rps_defaults_attrs[] = {
+ 	NULL
+ };
+ 
+-static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj,
+-				const struct attribute * const *attrs)
++static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj)
+ {
++	const struct attribute * const *attrs;
++	struct attribute *vlv_attr;
+ 	int ret;
+ 
+ 	if (GRAPHICS_VER(gt->i915) < 6)
+ 		return 0;
+ 
++	if (is_object_gt(kobj)) {
++		attrs = gen6_rps_attrs;
++		vlv_attr = &attr_rps_vlv_rpe_freq_mhz.attr;
++	} else {
++		attrs = gen6_gt_attrs;
++		vlv_attr = &dev_attr_gt_vlv_rpe_freq_mhz.attr;
++	}
++
+ 	ret = sysfs_create_files(kobj, attrs);
+ 	if (ret)
+ 		return ret;
+ 
+ 	if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915))
+-		ret = sysfs_create_file(kobj, &dev_attr_vlv_rpe_freq_mhz.attr);
++		ret = sysfs_create_file(kobj, vlv_attr);
+ 
+ 	return ret;
+ }
+@@ -778,9 +743,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
+ 
+ 	intel_sysfs_rc6_init(gt, kobj);
+ 
+-	ret = is_object_gt(kobj) ?
+-	      intel_sysfs_rps_init(gt, kobj, gen6_rps_attrs) :
+-	      intel_sysfs_rps_init(gt, kobj, gen6_gt_attrs);
++	ret = intel_sysfs_rps_init(gt, kobj);
+ 	if (ret)
+ 		drm_warn(&gt->i915->drm,
+ 			 "failed to create gt%u RPS sysfs files (%pe)",
+@@ -790,7 +753,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
+ 	if (!is_object_gt(kobj))
+ 		return;
+ 
+-	ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr);
++	ret = sysfs_create_file(kobj, &attr_punit_req_freq_mhz.attr);
+ 	if (ret)
+ 		drm_warn(&gt->i915->drm,
+ 			 "failed to create gt%u punit_req_freq_mhz sysfs (%pe)",
+diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
+index b366743569862..10b930eaa8cb8 100644
+--- a/drivers/gpu/drm/i915/gt/intel_reset.c
++++ b/drivers/gpu/drm/i915/gt/intel_reset.c
+@@ -278,6 +278,7 @@ out:
+ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
+ {
+ 	struct intel_uncore *uncore = gt->uncore;
++	int loops = 2;
+ 	int err;
+ 
+ 	/*
+@@ -285,18 +286,39 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
+ 	 * for fifo space for the write or forcewake the chip for
+ 	 * the read
+ 	 */
+-	intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
++	do {
++		intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
+ 
+-	/* Wait for the device to ack the reset requests */
+-	err = __intel_wait_for_register_fw(uncore,
+-					   GEN6_GDRST, hw_domain_mask, 0,
+-					   500, 0,
+-					   NULL);
++		/*
++		 * Wait for the device to ack the reset requests.
++		 *
++		 * On some platforms, e.g. Jasperlake, we see that the
++		 * engine register state is not cleared until shortly after
++		 * GDRST reports completion, causing a failure as we try
++		 * to immediately resume while the internal state is still
++		 * in flux. If we immediately repeat the reset, the second
++		 * reset appears to serialise with the first, and since
++		 * it is a no-op, the registers should retain their reset
++		 * value. However, there is still a concern that upon
++		 * leaving the second reset, the internal engine state
++		 * is still in flux and not ready for resuming.
++		 */
++		err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
++						   hw_domain_mask, 0,
++						   2000, 0,
++						   NULL);
++	} while (err == 0 && --loops);
+ 	if (err)
+ 		GT_TRACE(gt,
+ 			 "Wait for 0x%08x engines reset failed\n",
+ 			 hw_domain_mask);
+ 
++	/*
++	 * As we have observed that the engine state is still volatile
++	 * after GDRST is acked, impose a small delay to let everything settle.
++	 */
++	udelay(50);
++
+ 	return err;
+ }
+ 
+diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
+index 4d06875de14a1..c8ad8f37e5cfe 100644
+--- a/drivers/gpu/drm/i915/i915_vma.c
++++ b/drivers/gpu/drm/i915/i915_vma.c
+@@ -2114,7 +2114,7 @@ int i915_vma_unbind_async(struct i915_vma *vma, bool trylock_vm)
+ 	if (!obj->mm.rsgt)
+ 		return -EBUSY;
+ 
+-	err = dma_resv_reserve_fences(obj->base.resv, 1);
++	err = dma_resv_reserve_fences(obj->base.resv, 2);
+ 	if (err)
+ 		return -EBUSY;
+ 
+diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+index e7adc5c632d07..3d78efb066b1e 100644
+--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+@@ -29,11 +29,9 @@ enum {
+ 	ADRENO_FW_MAX,
+ };
+ 
+-enum adreno_quirks {
+-	ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
+-	ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
+-	ADRENO_QUIRK_LMLOADKILL_DISABLE = 3,
+-};
++#define ADRENO_QUIRK_TWO_PASS_USE_WFI		BIT(0)
++#define ADRENO_QUIRK_FAULT_DETECT_MASK		BIT(1)
++#define ADRENO_QUIRK_LMLOADKILL_DISABLE		BIT(2)
+ 
+ struct adreno_rev {
+ 	uint8_t  core;
+@@ -65,7 +63,7 @@ struct adreno_info {
+ 	const char *name;
+ 	const char *fw[ADRENO_FW_MAX];
+ 	uint32_t gmem;
+-	enum adreno_quirks quirks;
++	u64 quirks;
+ 	struct msm_gpu *(*init)(struct drm_device *dev);
+ 	const char *zapfw;
+ 	u32 inactive_period;
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+index 7cbcef6efe171..62f6ff6abf410 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+@@ -132,7 +132,6 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
+  * dpu_encoder_phys_wb_setup_fb - setup output framebuffer
+  * @phys_enc:	Pointer to physical encoder
+  * @fb:		Pointer to output framebuffer
+- * @wb_roi:	Pointer to output region of interest
+  */
+ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
+ 		struct drm_framebuffer *fb)
+@@ -692,7 +691,7 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
+ 
+ /**
+  * dpu_encoder_phys_wb_init - initialize writeback encoder
+- * @init:	Pointer to init info structure with initialization params
++ * @p:	Pointer to init info structure with initialization params
+  */
+ struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
+ 		struct dpu_enc_phys_init_params *p)
+diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
+index d030a93a08c36..cc3efed593aa1 100644
+--- a/drivers/gpu/drm/msm/dp/dp_aux.c
++++ b/drivers/gpu/drm/msm/dp/dp_aux.c
+@@ -423,6 +423,10 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux)
+ 
+ 	isr = dp_catalog_aux_get_irq(aux->catalog);
+ 
++	/* no interrupts pending, return immediately */
++	if (!isr)
++		return;
++
+ 	if (!aux->cmd_busy)
+ 		return;
+ 
+diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
+index 105b5b48e828c..681c1b889b31a 100644
+--- a/drivers/gpu/drm/msm/msm_drv.c
++++ b/drivers/gpu/drm/msm/msm_drv.c
+@@ -1271,7 +1271,7 @@ void msm_drv_shutdown(struct platform_device *pdev)
+ 	 * msm_drm_init, drm_dev->registered is used as an indicator that the
+ 	 * shutdown will be successful.
+ 	 */
+-	if (drm && drm->registered)
++	if (drm && drm->registered && priv->kms)
+ 		drm_atomic_helper_shutdown(drm);
+ }
+ 
+diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
+index e13c5c12b775f..3b8d6991b04e0 100644
+--- a/drivers/gpu/drm/msm/msm_mdss.c
++++ b/drivers/gpu/drm/msm/msm_mdss.c
+@@ -46,15 +46,17 @@ struct msm_mdss {
+ static int msm_mdss_parse_data_bus_icc_path(struct device *dev,
+ 					    struct msm_mdss *msm_mdss)
+ {
+-	struct icc_path *path0 = of_icc_get(dev, "mdp0-mem");
+-	struct icc_path *path1 = of_icc_get(dev, "mdp1-mem");
++	struct icc_path *path0;
++	struct icc_path *path1;
+ 
++	path0 = of_icc_get(dev, "mdp0-mem");
+ 	if (IS_ERR_OR_NULL(path0))
+ 		return PTR_ERR_OR_ZERO(path0);
+ 
+ 	msm_mdss->path[0] = path0;
+ 	msm_mdss->num_paths = 1;
+ 
++	path1 = of_icc_get(dev, "mdp1-mem");
+ 	if (!IS_ERR_OR_NULL(path1)) {
+ 		msm_mdss->path[1] = path1;
+ 		msm_mdss->num_paths++;
+diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+index 5d05093014ac3..9f4a90493aeac 100644
+--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
++++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+@@ -358,10 +358,18 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
+ 		drm_gem_object_release(obj);
+ 		return ret;
+ 	}
+-	drm_gem_object_put(obj);
+ 
+ 	rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
+ 	rc->bo_handle = handle;
++
++	/*
++	 * The handle owns the reference now.  But we must drop our
++	 * remaining reference *after* we no longer need to dereference
++	 * the obj.  Otherwise userspace could guess the handle and
++	 * race closing it from another thread.
++	 */
++	drm_gem_object_put(obj);
++
+ 	return 0;
+ }
+ 
+@@ -723,11 +731,18 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
+ 		drm_gem_object_release(obj);
+ 		return ret;
+ 	}
+-	drm_gem_object_put(obj);
+ 
+ 	rc_blob->res_handle = bo->hw_res_handle;
+ 	rc_blob->bo_handle = handle;
+ 
++	/*
++	 * The handle owns the reference now.  But we must drop our
++	 * remaining reference *after* we no longer need to dereference
++	 * the obj.  Otherwise userspace could guess the handle and
++	 * race closing it from another thread.
++	 */
++	drm_gem_object_put(obj);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
+index eee73b9aa404b..68e350f410ad3 100644
+--- a/drivers/gpu/drm/vmwgfx/Makefile
++++ b/drivers/gpu/drm/vmwgfx/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+-vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \
++vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
+ 	    vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \
+ 	    vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
+ 	    vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \
+diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c
+index 26a55fef1ab50..ddf8373c1d779 100644
+--- a/drivers/gpu/drm/vmwgfx/ttm_object.c
++++ b/drivers/gpu/drm/vmwgfx/ttm_object.c
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR MIT */
+ /**************************************************************************
+  *
+- * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA
++ * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -44,16 +44,20 @@
+ 
+ #define pr_fmt(fmt) "[TTM] " fmt
+ 
++#include "ttm_object.h"
++#include "vmwgfx_drv.h"
++
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
+ #include <linux/slab.h>
+ #include <linux/atomic.h>
+ #include <linux/module.h>
+-#include "ttm_object.h"
+-#include "vmwgfx_drv.h"
++#include <linux/hashtable.h>
+ 
+ MODULE_IMPORT_NS(DMA_BUF);
+ 
++#define VMW_TTM_OBJECT_REF_HT_ORDER 10
++
+ /**
+  * struct ttm_object_file
+  *
+@@ -74,16 +78,14 @@ struct ttm_object_file {
+ 	struct ttm_object_device *tdev;
+ 	spinlock_t lock;
+ 	struct list_head ref_list;
+-	struct vmwgfx_open_hash ref_hash;
++	DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER);
+ 	struct kref refcount;
+ };
+ 
+ /*
+  * struct ttm_object_device
+  *
+- * @object_lock: lock that protects the object_hash hash table.
+- *
+- * @object_hash: hash table for fast lookup of object global names.
++ * @object_lock: lock that protects idr.
+  *
+  * @object_count: Per device object count.
+  *
+@@ -92,7 +94,6 @@ struct ttm_object_file {
+ 
+ struct ttm_object_device {
+ 	spinlock_t object_lock;
+-	struct vmwgfx_open_hash object_hash;
+ 	atomic_t object_count;
+ 	struct dma_buf_ops ops;
+ 	void (*dmabuf_release)(struct dma_buf *dma_buf);
+@@ -138,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile)
+ 	return tfile;
+ }
+ 
++static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile,
++				  uint64_t key,
++				  struct vmwgfx_hash_item **p_hash)
++{
++	struct vmwgfx_hash_item *hash;
++
++	hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) {
++		if (hash->key == key) {
++			*p_hash = hash;
++			return 0;
++		}
++	}
++	return -EINVAL;
++}
++
++static int ttm_tfile_find_ref(struct ttm_object_file *tfile,
++			      uint64_t key,
++			      struct vmwgfx_hash_item **p_hash)
++{
++	struct vmwgfx_hash_item *hash;
++
++	hash_for_each_possible(tfile->ref_hash, hash, head, key) {
++		if (hash->key == key) {
++			*p_hash = hash;
++			return 0;
++		}
++	}
++	return -EINVAL;
++}
++
+ static void ttm_object_file_destroy(struct kref *kref)
+ {
+ 	struct ttm_object_file *tfile =
+@@ -223,64 +254,29 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
+ 	kref_put(&base->refcount, ttm_release_base);
+ }
+ 
+-/**
+- * ttm_base_object_noref_lookup - look up a base object without reference
+- * @tfile: The struct ttm_object_file the object is registered with.
+- * @key: The object handle.
+- *
+- * This function looks up a ttm base object and returns a pointer to it
+- * without refcounting the pointer. The returned pointer is only valid
+- * until ttm_base_object_noref_release() is called, and the object
+- * pointed to by the returned pointer may be doomed. Any persistent usage
+- * of the object requires a refcount to be taken using kref_get_unless_zero().
+- * Iff this function returns successfully it needs to be paired with
+- * ttm_base_object_noref_release() and no sleeping- or scheduling functions
+- * may be called inbetween these function callse.
+- *
+- * Return: A pointer to the object if successful or NULL otherwise.
+- */
+-struct ttm_base_object *
+-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
+-{
+-	struct vmwgfx_hash_item *hash;
+-	struct vmwgfx_open_hash *ht = &tfile->ref_hash;
+-	int ret;
+-
+-	rcu_read_lock();
+-	ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
+-	if (ret) {
+-		rcu_read_unlock();
+-		return NULL;
+-	}
+-
+-	__release(RCU);
+-	return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
+-}
+-EXPORT_SYMBOL(ttm_base_object_noref_lookup);
+-
+ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
+-					       uint32_t key)
++					       uint64_t key)
+ {
+ 	struct ttm_base_object *base = NULL;
+ 	struct vmwgfx_hash_item *hash;
+-	struct vmwgfx_open_hash *ht = &tfile->ref_hash;
+ 	int ret;
+ 
+-	rcu_read_lock();
+-	ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
++	spin_lock(&tfile->lock);
++	ret = ttm_tfile_find_ref(tfile, key, &hash);
+ 
+ 	if (likely(ret == 0)) {
+-		base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
++		base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
+ 		if (!kref_get_unless_zero(&base->refcount))
+ 			base = NULL;
+ 	}
+-	rcu_read_unlock();
++	spin_unlock(&tfile->lock);
++
+ 
+ 	return base;
+ }
+ 
+ struct ttm_base_object *
+-ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
++ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key)
+ {
+ 	struct ttm_base_object *base;
+ 
+@@ -299,7 +295,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
+ 		       bool *existed,
+ 		       bool require_existed)
+ {
+-	struct vmwgfx_open_hash *ht = &tfile->ref_hash;
+ 	struct ttm_ref_object *ref;
+ 	struct vmwgfx_hash_item *hash;
+ 	int ret = -EINVAL;
+@@ -312,10 +307,10 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
+ 
+ 	while (ret == -EINVAL) {
+ 		rcu_read_lock();
+-		ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash);
++		ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash);
+ 
+ 		if (ret == 0) {
+-			ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
++			ref = hlist_entry(hash, struct ttm_ref_object, hash);
+ 			if (kref_get_unless_zero(&ref->kref)) {
+ 				rcu_read_unlock();
+ 				break;
+@@ -337,21 +332,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
+ 		kref_init(&ref->kref);
+ 
+ 		spin_lock(&tfile->lock);
+-		ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash);
+-
+-		if (likely(ret == 0)) {
+-			list_add_tail(&ref->head, &tfile->ref_list);
+-			kref_get(&base->refcount);
+-			spin_unlock(&tfile->lock);
+-			if (existed != NULL)
+-				*existed = false;
+-			break;
+-		}
++		hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key);
++		ret = 0;
+ 
++		list_add_tail(&ref->head, &tfile->ref_list);
++		kref_get(&base->refcount);
+ 		spin_unlock(&tfile->lock);
+-		BUG_ON(ret != -EINVAL);
+-
+-		kfree(ref);
++		if (existed != NULL)
++			*existed = false;
+ 	}
+ 
+ 	return ret;
+@@ -363,10 +351,8 @@ ttm_ref_object_release(struct kref *kref)
+ 	struct ttm_ref_object *ref =
+ 	    container_of(kref, struct ttm_ref_object, kref);
+ 	struct ttm_object_file *tfile = ref->tfile;
+-	struct vmwgfx_open_hash *ht;
+ 
+-	ht = &tfile->ref_hash;
+-	(void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
++	hash_del_rcu(&ref->hash.head);
+ 	list_del(&ref->head);
+ 	spin_unlock(&tfile->lock);
+ 
+@@ -378,18 +364,17 @@ ttm_ref_object_release(struct kref *kref)
+ int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
+ 			      unsigned long key)
+ {
+-	struct vmwgfx_open_hash *ht = &tfile->ref_hash;
+ 	struct ttm_ref_object *ref;
+ 	struct vmwgfx_hash_item *hash;
+ 	int ret;
+ 
+ 	spin_lock(&tfile->lock);
+-	ret = vmwgfx_ht_find_item(ht, key, &hash);
++	ret = ttm_tfile_find_ref(tfile, key, &hash);
+ 	if (unlikely(ret != 0)) {
+ 		spin_unlock(&tfile->lock);
+ 		return -EINVAL;
+ 	}
+-	ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
++	ref = hlist_entry(hash, struct ttm_ref_object, hash);
+ 	kref_put(&ref->kref, ttm_ref_object_release);
+ 	spin_unlock(&tfile->lock);
+ 	return 0;
+@@ -416,16 +401,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
+ 	}
+ 
+ 	spin_unlock(&tfile->lock);
+-	vmwgfx_ht_remove(&tfile->ref_hash);
+ 
+ 	ttm_object_file_unref(&tfile);
+ }
+ 
+-struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
+-					     unsigned int hash_order)
++struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev)
+ {
+ 	struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
+-	int ret;
+ 
+ 	if (unlikely(tfile == NULL))
+ 		return NULL;
+@@ -435,34 +417,21 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
+ 	kref_init(&tfile->refcount);
+ 	INIT_LIST_HEAD(&tfile->ref_list);
+ 
+-	ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order);
+-	if (ret)
+-		goto out_err;
++	hash_init(tfile->ref_hash);
+ 
+ 	return tfile;
+-out_err:
+-	vmwgfx_ht_remove(&tfile->ref_hash);
+-
+-	kfree(tfile);
+-
+-	return NULL;
+ }
+ 
+ struct ttm_object_device *
+-ttm_object_device_init(unsigned int hash_order,
+-		       const struct dma_buf_ops *ops)
++ttm_object_device_init(const struct dma_buf_ops *ops)
+ {
+ 	struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
+-	int ret;
+ 
+ 	if (unlikely(tdev == NULL))
+ 		return NULL;
+ 
+ 	spin_lock_init(&tdev->object_lock);
+ 	atomic_set(&tdev->object_count, 0);
+-	ret = vmwgfx_ht_create(&tdev->object_hash, hash_order);
+-	if (ret != 0)
+-		goto out_no_object_hash;
+ 
+ 	/*
+ 	 * Our base is at VMWGFX_NUM_MOB + 1 because we want to create
+@@ -477,10 +446,6 @@ ttm_object_device_init(unsigned int hash_order,
+ 	tdev->dmabuf_release = tdev->ops.release;
+ 	tdev->ops.release = ttm_prime_dmabuf_release;
+ 	return tdev;
+-
+-out_no_object_hash:
+-	kfree(tdev);
+-	return NULL;
+ }
+ 
+ void ttm_object_device_release(struct ttm_object_device **p_tdev)
+@@ -491,7 +456,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev)
+ 
+ 	WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
+ 	idr_destroy(&tdev->idr);
+-	vmwgfx_ht_remove(&tdev->object_hash);
+ 
+ 	kfree(tdev);
+ }
+diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h
+index 1a2fa0f83f5f9..8098a3846bae3 100644
+--- a/drivers/gpu/drm/vmwgfx/ttm_object.h
++++ b/drivers/gpu/drm/vmwgfx/ttm_object.h
+@@ -1,6 +1,6 @@
+ /**************************************************************************
+  *
+- * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
++ * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -42,8 +42,6 @@
+ #include <linux/list.h>
+ #include <linux/rcupdate.h>
+ 
+-#include "vmwgfx_hashtab.h"
+-
+ /**
+  * enum ttm_object_type
+  *
+@@ -104,7 +102,7 @@ struct ttm_base_object {
+ 	struct ttm_object_file *tfile;
+ 	struct kref refcount;
+ 	void (*refcount_release) (struct ttm_base_object **base);
+-	u32 handle;
++	u64 handle;
+ 	enum ttm_object_type object_type;
+ 	u32 shareable;
+ };
+@@ -164,7 +162,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
+  */
+ 
+ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
+-						      *tfile, uint32_t key);
++						      *tfile, uint64_t key);
+ 
+ /**
+  * ttm_base_object_lookup_for_ref
+@@ -178,7 +176,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
+  */
+ 
+ extern struct ttm_base_object *
+-ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key);
++ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key);
+ 
+ /**
+  * ttm_base_object_unref
+@@ -237,14 +235,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
+  * ttm_object_file_init - initialize a struct ttm_object file
+  *
+  * @tdev: A struct ttm_object device this file is initialized on.
+- * @hash_order: Order of the hash table used to hold the reference objects.
+  *
+  * This is typically called by the file_ops::open function.
+  */
+ 
+ extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device
+-						    *tdev,
+-						    unsigned int hash_order);
++						    *tdev);
+ 
+ /**
+  * ttm_object_file_release - release data held by a ttm_object_file
+@@ -262,7 +258,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
+ /**
+  * ttm_object device init - initialize a struct ttm_object_device
+  *
+- * @hash_order: Order of hash table used to hash the base objects.
+  * @ops: DMA buf ops for prime objects of this device.
+  *
+  * This function is typically called on device initialization to prepare
+@@ -270,8 +265,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
+  */
+ 
+ extern struct ttm_object_device *
+-ttm_object_device_init(unsigned int hash_order,
+-		       const struct dma_buf_ops *ops);
++ttm_object_device_init(const struct dma_buf_ops *ops);
+ 
+ /**
+  * ttm_object_device_release - release data held by a ttm_object_device
+@@ -313,18 +307,4 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
+ #define ttm_prime_object_kfree(__obj, __prime)		\
+ 	kfree_rcu(__obj, __prime.base.rhead)
+ 
+-struct ttm_base_object *
+-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key);
+-
+-/**
+- * ttm_base_object_noref_release - release a base object pointer looked up
+- * without reference
+- *
+- * Releases a base object pointer looked up with ttm_base_object_noref_lookup().
+- */
+-static inline void ttm_base_object_noref_release(void)
+-{
+-	__acquire(RCU);
+-	rcu_read_unlock();
+-}
+ #endif
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+index 822251aaab0a1..973a0a52462e9 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+@@ -715,44 +715,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
+ 	return 0;
+ }
+ 
+-/**
+- * vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference
+- * @filp: The TTM object file the handle is registered with.
+- * @handle: The user buffer object handle.
+- *
+- * This function looks up a struct vmw_bo and returns a pointer to the
+- * struct vmw_buffer_object it derives from without refcounting the pointer.
+- * The returned pointer is only valid until vmw_user_bo_noref_release() is
+- * called, and the object pointed to by the returned pointer may be doomed.
+- * Any persistent usage of the object requires a refcount to be taken using
+- * ttm_bo_reference_unless_doomed(). Iff this function returns successfully it
+- * needs to be paired with vmw_user_bo_noref_release() and no sleeping-
+- * or scheduling functions may be called in between these function calls.
+- *
+- * Return: A struct vmw_buffer_object pointer if successful or negative
+- * error pointer on failure.
+- */
+-struct vmw_buffer_object *
+-vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle)
+-{
+-	struct vmw_buffer_object *vmw_bo;
+-	struct ttm_buffer_object *bo;
+-	struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle);
+-
+-	if (!gobj) {
+-		DRM_ERROR("Invalid buffer object handle 0x%08lx.\n",
+-			  (unsigned long)handle);
+-		return ERR_PTR(-ESRCH);
+-	}
+-	vmw_bo = gem_to_vmw_bo(gobj);
+-	bo = ttm_bo_get_unless_zero(&vmw_bo->base);
+-	vmw_bo = vmw_buffer_object(bo);
+-	drm_gem_object_put(gobj);
+-
+-	return vmw_bo;
+-}
+-
+-
+ /**
+  * vmw_bo_fence_single - Utility function to fence a single TTM buffer
+  *                       object without unreserving it.
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
+index 82ef58ccdd428..47bc0b411055f 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0 OR MIT
+ /**************************************************************************
+  *
+- * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA
++ * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the
+@@ -28,6 +28,8 @@
+ #include "vmwgfx_drv.h"
+ #include "vmwgfx_resource_priv.h"
+ 
++#include <linux/hashtable.h>
++
+ #define VMW_CMDBUF_RES_MAN_HT_ORDER 12
+ 
+ /**
+@@ -59,7 +61,7 @@ struct vmw_cmdbuf_res {
+  * @resources and @list are protected by the cmdbuf mutex for now.
+  */
+ struct vmw_cmdbuf_res_manager {
+-	struct vmwgfx_open_hash resources;
++	DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
+ 	struct list_head list;
+ 	struct vmw_private *dev_priv;
+ };
+@@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
+ 		      u32 user_key)
+ {
+ 	struct vmwgfx_hash_item *hash;
+-	int ret;
+ 	unsigned long key = user_key | (res_type << 24);
+ 
+-	ret = vmwgfx_ht_find_item(&man->resources, key, &hash);
+-	if (unlikely(ret != 0))
+-		return ERR_PTR(ret);
+-
+-	return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res;
++	hash_for_each_possible_rcu(man->resources, hash, head, key) {
++		if (hash->key == key)
++			return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res;
++	}
++	return ERR_PTR(-EINVAL);
+ }
+ 
+ /**
+@@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
+ 				struct vmw_cmdbuf_res *entry)
+ {
+ 	list_del(&entry->head);
+-	WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash));
++	hash_del_rcu(&entry->hash.head);
+ 	vmw_resource_unreference(&entry->res);
+ 	kfree(entry);
+ }
+@@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list)
+ void vmw_cmdbuf_res_revert(struct list_head *list)
+ {
+ 	struct vmw_cmdbuf_res *entry, *next;
+-	int ret;
+ 
+ 	list_for_each_entry_safe(entry, next, list, head) {
+ 		switch (entry->state) {
+@@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list)
+ 			vmw_cmdbuf_res_free(entry->man, entry);
+ 			break;
+ 		case VMW_CMDBUF_RES_DEL:
+-			ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash);
+-			BUG_ON(ret);
++			hash_add_rcu(entry->man->resources, &entry->hash.head,
++						entry->hash.key);
+ 			list_move_tail(&entry->head, &entry->man->list);
+ 			entry->state = VMW_CMDBUF_RES_COMMITTED;
+ 			break;
+@@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
+ 		       struct list_head *list)
+ {
+ 	struct vmw_cmdbuf_res *cres;
+-	int ret;
+ 
+ 	cres = kzalloc(sizeof(*cres), GFP_KERNEL);
+ 	if (unlikely(!cres))
+ 		return -ENOMEM;
+ 
+ 	cres->hash.key = user_key | (res_type << 24);
+-	ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash);
+-	if (unlikely(ret != 0)) {
+-		kfree(cres);
+-		goto out_invalid_key;
+-	}
++	hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key);
+ 
+ 	cres->state = VMW_CMDBUF_RES_ADD;
+ 	cres->res = vmw_resource_reference(res);
+ 	cres->man = man;
+ 	list_add_tail(&cres->head, list);
+ 
+-out_invalid_key:
+-	return ret;
++	return 0;
+ }
+ 
+ /**
+@@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
+ 			  struct list_head *list,
+ 			  struct vmw_resource **res_p)
+ {
+-	struct vmw_cmdbuf_res *entry;
++	struct vmw_cmdbuf_res *entry = NULL;
+ 	struct vmwgfx_hash_item *hash;
+-	int ret;
++	unsigned long key = user_key | (res_type << 24);
+ 
+-	ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24),
+-			       &hash);
+-	if (likely(ret != 0))
++	hash_for_each_possible_rcu(man->resources, hash, head, key) {
++		if (hash->key == key) {
++			entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash);
++			break;
++		}
++	}
++	if (unlikely(!entry))
+ 		return -EINVAL;
+ 
+-	entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
+-
+ 	switch (entry->state) {
+ 	case VMW_CMDBUF_RES_ADD:
+ 		vmw_cmdbuf_res_free(man, entry);
+ 		*res_p = NULL;
+ 		break;
+ 	case VMW_CMDBUF_RES_COMMITTED:
+-		(void) vmwgfx_ht_remove_item(&man->resources, &entry->hash);
++		hash_del_rcu(&entry->hash.head);
+ 		list_del(&entry->head);
+ 		entry->state = VMW_CMDBUF_RES_DEL;
+ 		list_add_tail(&entry->head, list);
+@@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager *
+ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
+ {
+ 	struct vmw_cmdbuf_res_manager *man;
+-	int ret;
+ 
+ 	man = kzalloc(sizeof(*man), GFP_KERNEL);
+ 	if (!man)
+@@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
+ 
+ 	man->dev_priv = dev_priv;
+ 	INIT_LIST_HEAD(&man->list);
+-	ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
+-	if (ret == 0)
+-		return man;
+-
+-	kfree(man);
+-	return ERR_PTR(ret);
++	hash_init(man->resources);
++	return man;
+ }
+ 
+ /**
+@@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
+ 	list_for_each_entry_safe(entry, next, &man->list, head)
+ 		vmw_cmdbuf_res_free(man, entry);
+ 
+-	vmwgfx_ht_remove(&man->resources);
+ 	kfree(man);
+ }
+ 
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+index d7bd5eb1d3acd..b909a3ce9af3c 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+@@ -25,10 +25,13 @@
+  *
+  **************************************************************************/
+ 
+-#include <linux/dma-mapping.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-#include <linux/cc_platform.h>
++
++#include "vmwgfx_drv.h"
++
++#include "vmwgfx_devcaps.h"
++#include "vmwgfx_mksstat.h"
++#include "vmwgfx_binding.h"
++#include "ttm_object.h"
+ 
+ #include <drm/drm_aperture.h>
+ #include <drm/drm_drv.h>
+@@ -41,11 +44,11 @@
+ #include <drm/ttm/ttm_placement.h>
+ #include <generated/utsrelease.h>
+ 
+-#include "ttm_object.h"
+-#include "vmwgfx_binding.h"
+-#include "vmwgfx_devcaps.h"
+-#include "vmwgfx_drv.h"
+-#include "vmwgfx_mksstat.h"
++#include <linux/cc_platform.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/version.h>
+ 
+ #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
+ 
+@@ -806,6 +809,43 @@ static int vmw_detect_version(struct vmw_private *dev)
+ 	return 0;
+ }
+ 
++static void vmw_write_driver_id(struct vmw_private *dev)
++{
++	if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) {
++		vmw_write(dev,  SVGA_REG_GUEST_DRIVER_ID,
++			  SVGA_REG_GUEST_DRIVER_ID_LINUX);
++
++		vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1,
++			  LINUX_VERSION_MAJOR << 24 |
++			  LINUX_VERSION_PATCHLEVEL << 16 |
++			  LINUX_VERSION_SUBLEVEL);
++		vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2,
++			  VMWGFX_DRIVER_MAJOR << 24 |
++			  VMWGFX_DRIVER_MINOR << 16 |
++			  VMWGFX_DRIVER_PATCHLEVEL);
++		vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0);
++
++		vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
++			  SVGA_REG_GUEST_DRIVER_ID_SUBMIT);
++	}
++}
++
++static void vmw_sw_context_init(struct vmw_private *dev_priv)
++{
++	struct vmw_sw_context *sw_context = &dev_priv->ctx;
++
++	hash_init(sw_context->res_ht);
++}
++
++static void vmw_sw_context_fini(struct vmw_private *dev_priv)
++{
++	struct vmw_sw_context *sw_context = &dev_priv->ctx;
++
++	vfree(sw_context->cmd_bounce);
++	if (sw_context->staged_bindings)
++		vmw_binding_state_free(sw_context->staged_bindings);
++}
++
+ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
+ {
+ 	int ret;
+@@ -815,6 +855,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
+ 
+ 	dev_priv->drm.dev_private = dev_priv;
+ 
++	vmw_sw_context_init(dev_priv);
++
+ 	mutex_init(&dev_priv->cmdbuf_mutex);
+ 	mutex_init(&dev_priv->binding_mutex);
+ 	spin_lock_init(&dev_priv->resource_lock);
+@@ -970,7 +1012,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
+ 		goto out_err0;
+ 	}
+ 
+-	dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops);
++	dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops);
+ 
+ 	if (unlikely(dev_priv->tdev == NULL)) {
+ 		drm_err(&dev_priv->drm,
+@@ -1091,6 +1133,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
+ 	vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)",
+ 			VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
+ 			VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE);
++	vmw_write_driver_id(dev_priv);
+ 
+ 	if (dev_priv->enable_fb) {
+ 		vmw_fifo_resource_inc(dev_priv);
+@@ -1143,9 +1186,7 @@ static void vmw_driver_unload(struct drm_device *dev)
+ 
+ 	unregister_pm_notifier(&dev_priv->pm_nb);
+ 
+-	if (dev_priv->ctx.res_ht_initialized)
+-		vmwgfx_ht_remove(&dev_priv->ctx.res_ht);
+-	vfree(dev_priv->ctx.cmd_bounce);
++	vmw_sw_context_fini(dev_priv);
+ 	if (dev_priv->enable_fb) {
+ 		vmw_fb_off(dev_priv);
+ 		vmw_fb_close(dev_priv);
+@@ -1173,8 +1214,6 @@ static void vmw_driver_unload(struct drm_device *dev)
+ 		vmw_irq_uninstall(&dev_priv->drm);
+ 
+ 	ttm_object_device_release(&dev_priv->tdev);
+-	if (dev_priv->ctx.staged_bindings)
+-		vmw_binding_state_free(dev_priv->ctx.staged_bindings);
+ 
+ 	for (i = vmw_res_context; i < vmw_res_max; ++i)
+ 		idr_destroy(&dev_priv->res_idr[i]);
+@@ -1203,7 +1242,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+ 	if (unlikely(!vmw_fp))
+ 		return ret;
+ 
+-	vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
++	vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev);
+ 	if (unlikely(vmw_fp->tfile == NULL))
+ 		goto out_no_tfile;
+ 
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+index 09e2d738aa876..0bc1ebc43002b 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+@@ -30,6 +30,7 @@
+ 
+ #include <linux/suspend.h>
+ #include <linux/sync_file.h>
++#include <linux/hashtable.h>
+ 
+ #include <drm/drm_auth.h>
+ #include <drm/drm_device.h>
+@@ -42,7 +43,6 @@
+ #include "ttm_object.h"
+ 
+ #include "vmwgfx_fence.h"
+-#include "vmwgfx_hashtab.h"
+ #include "vmwgfx_reg.h"
+ #include "vmwgfx_validation.h"
+ 
+@@ -93,6 +93,7 @@
+ #define VMW_RES_STREAM ttm_driver_type2
+ #define VMW_RES_FENCE ttm_driver_type3
+ #define VMW_RES_SHADER ttm_driver_type4
++#define VMW_RES_HT_ORDER 12
+ 
+ #define MKSSTAT_CAPACITY_LOG2 5U
+ #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)
+@@ -102,6 +103,11 @@ struct vmw_fpriv {
+ 	bool gb_aware; /* user-space is guest-backed aware */
+ };
+ 
++struct vmwgfx_hash_item {
++	struct hlist_node head;
++	unsigned long key;
++};
++
+ /**
+  * struct vmw_buffer_object - TTM buffer object with vmwgfx additions
+  * @base: The TTM buffer object
+@@ -425,8 +431,7 @@ struct vmw_ctx_validation_info;
+  * @ctx: The validation context
+  */
+ struct vmw_sw_context{
+-	struct vmwgfx_open_hash res_ht;
+-	bool res_ht_initialized;
++	DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER);
+ 	bool kernel;
+ 	struct vmw_fpriv *fp;
+ 	struct drm_file *filp;
+@@ -821,12 +826,7 @@ extern int vmw_user_resource_lookup_handle(
+ 	uint32_t handle,
+ 	const struct vmw_user_resource_conv *converter,
+ 	struct vmw_resource **p_res);
+-extern struct vmw_resource *
+-vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
+-				      struct ttm_object_file *tfile,
+-				      uint32_t handle,
+-				      const struct vmw_user_resource_conv *
+-				      converter);
++
+ extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
+ 				  struct drm_file *file_priv);
+ extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
+@@ -865,15 +865,6 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
+ 	return !RB_EMPTY_NODE(&res->mob_node);
+ }
+ 
+-/**
+- * vmw_user_resource_noref_release - release a user resource pointer looked up
+- * without reference
+- */
+-static inline void vmw_user_resource_noref_release(void)
+-{
+-	ttm_base_object_noref_release();
+-}
+-
+ /**
+  * Buffer object helper functions - vmwgfx_bo.c
+  */
+@@ -925,8 +916,6 @@ extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
+ extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
+ 			       struct ttm_resource *mem);
+ extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
+-extern struct vmw_buffer_object *
+-vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle);
+ 
+ /**
+  * vmw_bo_adjust_prio - Adjust the buffer object eviction priority
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+index f085dbd4736d5..70cfed4fdba04 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0 OR MIT
+ /**************************************************************************
+  *
+- * Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA
++ * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the
+@@ -25,6 +25,7 @@
+  *
+  **************************************************************************/
+ #include <linux/sync_file.h>
++#include <linux/hashtable.h>
+ 
+ #include "vmwgfx_drv.h"
+ #include "vmwgfx_reg.h"
+@@ -34,7 +35,6 @@
+ #include "vmwgfx_binding.h"
+ #include "vmwgfx_mksstat.h"
+ 
+-#define VMW_RES_HT_ORDER 12
+ 
+ /*
+  * Helper macro to get dx_ctx_node if available otherwise print an error
+@@ -290,20 +290,26 @@ static void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache,
+ 	rcache->valid_handle = 0;
+ }
+ 
++enum vmw_val_add_flags {
++	vmw_val_add_flag_none  =      0,
++	vmw_val_add_flag_noctx = 1 << 0,
++};
++
+ /**
+- * vmw_execbuf_res_noref_val_add - Add a resource described by an unreferenced
+- * rcu-protected pointer to the validation list.
++ * vmw_execbuf_res_val_add - Add a resource to the validation list.
+  *
+  * @sw_context: Pointer to the software context.
+  * @res: Unreferenced rcu-protected pointer to the resource.
+  * @dirty: Whether to change dirty status.
++ * @flags: specifies whether to use the context or not
+  *
+  * Returns: 0 on success. Negative error code on failure. Typical error codes
+  * are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed.
+  */
+-static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
+-					 struct vmw_resource *res,
+-					 u32 dirty)
++static int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context,
++				   struct vmw_resource *res,
++				   u32 dirty,
++				   u32 flags)
+ {
+ 	struct vmw_private *dev_priv = res->dev_priv;
+ 	int ret;
+@@ -318,24 +324,30 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
+ 		if (dirty)
+ 			vmw_validation_res_set_dirty(sw_context->ctx,
+ 						     rcache->private, dirty);
+-		vmw_user_resource_noref_release();
+ 		return 0;
+ 	}
+ 
+-	priv_size = vmw_execbuf_res_size(dev_priv, res_type);
+-	ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
+-					  dirty, (void **)&ctx_info,
+-					  &first_usage);
+-	vmw_user_resource_noref_release();
+-	if (ret)
+-		return ret;
++	if ((flags & vmw_val_add_flag_noctx) != 0) {
++		ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
++						  (void **)&ctx_info, NULL);
++		if (ret)
++			return ret;
+ 
+-	if (priv_size && first_usage) {
+-		ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
+-					      ctx_info);
+-		if (ret) {
+-			VMW_DEBUG_USER("Failed first usage context setup.\n");
++	} else {
++		priv_size = vmw_execbuf_res_size(dev_priv, res_type);
++		ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
++						  dirty, (void **)&ctx_info,
++						  &first_usage);
++		if (ret)
+ 			return ret;
++
++		if (priv_size && first_usage) {
++			ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
++						      ctx_info);
++			if (ret) {
++				VMW_DEBUG_USER("Failed first usage context setup.\n");
++				return ret;
++			}
+ 		}
+ 	}
+ 
+@@ -343,43 +355,6 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
+ 	return 0;
+ }
+ 
+-/**
+- * vmw_execbuf_res_noctx_val_add - Add a non-context resource to the resource
+- * validation list if it's not already on it
+- *
+- * @sw_context: Pointer to the software context.
+- * @res: Pointer to the resource.
+- * @dirty: Whether to change dirty status.
+- *
+- * Returns: Zero on success. Negative error code on failure.
+- */
+-static int vmw_execbuf_res_noctx_val_add(struct vmw_sw_context *sw_context,
+-					 struct vmw_resource *res,
+-					 u32 dirty)
+-{
+-	struct vmw_res_cache_entry *rcache;
+-	enum vmw_res_type res_type = vmw_res_type(res);
+-	void *ptr;
+-	int ret;
+-
+-	rcache = &sw_context->res_cache[res_type];
+-	if (likely(rcache->valid && rcache->res == res)) {
+-		if (dirty)
+-			vmw_validation_res_set_dirty(sw_context->ctx,
+-						     rcache->private, dirty);
+-		return 0;
+-	}
+-
+-	ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
+-					  &ptr, NULL);
+-	if (ret)
+-		return ret;
+-
+-	vmw_execbuf_rcache_update(rcache, res, ptr);
+-
+-	return 0;
+-}
+-
+ /**
+  * vmw_view_res_val_add - Add a view and the surface it's pointing to to the
+  * validation list
+@@ -398,13 +373,13 @@ static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
+ 	 * First add the resource the view is pointing to, otherwise it may be
+ 	 * swapped out when the view is validated.
+ 	 */
+-	ret = vmw_execbuf_res_noctx_val_add(sw_context, vmw_view_srf(view),
+-					    vmw_view_dirtying(view));
++	ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view),
++				      vmw_view_dirtying(view), vmw_val_add_flag_noctx);
+ 	if (ret)
+ 		return ret;
+ 
+-	return vmw_execbuf_res_noctx_val_add(sw_context, view,
+-					     VMW_RES_DIRTY_NONE);
++	return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE,
++				       vmw_val_add_flag_noctx);
+ }
+ 
+ /**
+@@ -475,8 +450,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
+ 			if (IS_ERR(res))
+ 				continue;
+ 
+-			ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-							    VMW_RES_DIRTY_SET);
++			ret = vmw_execbuf_res_val_add(sw_context, res,
++						      VMW_RES_DIRTY_SET,
++						      vmw_val_add_flag_noctx);
+ 			if (unlikely(ret != 0))
+ 				return ret;
+ 		}
+@@ -490,9 +466,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
+ 		if (vmw_res_type(entry->res) == vmw_res_view)
+ 			ret = vmw_view_res_val_add(sw_context, entry->res);
+ 		else
+-			ret = vmw_execbuf_res_noctx_val_add
+-				(sw_context, entry->res,
+-				 vmw_binding_dirtying(entry->bt));
++			ret = vmw_execbuf_res_val_add(sw_context, entry->res,
++						      vmw_binding_dirtying(entry->bt),
++						      vmw_val_add_flag_noctx);
+ 		if (unlikely(ret != 0))
+ 			break;
+ 	}
+@@ -658,7 +634,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
+ {
+ 	struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type];
+ 	struct vmw_resource *res;
+-	int ret;
++	int ret = 0;
++	bool needs_unref = false;
+ 
+ 	if (p_res)
+ 		*p_res = NULL;
+@@ -683,17 +660,18 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
+ 		if (ret)
+ 			return ret;
+ 
+-		res = vmw_user_resource_noref_lookup_handle
+-			(dev_priv, sw_context->fp->tfile, *id_loc, converter);
+-		if (IS_ERR(res)) {
++		ret = vmw_user_resource_lookup_handle
++			(dev_priv, sw_context->fp->tfile, *id_loc, converter, &res);
++		if (ret != 0) {
+ 			VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n",
+ 				       (unsigned int) *id_loc);
+-			return PTR_ERR(res);
++			return ret;
+ 		}
++		needs_unref = true;
+ 
+-		ret = vmw_execbuf_res_noref_val_add(sw_context, res, dirty);
++		ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none);
+ 		if (unlikely(ret != 0))
+-			return ret;
++			goto res_check_done;
+ 
+ 		if (rcache->valid && rcache->res == res) {
+ 			rcache->valid_handle = true;
+@@ -708,7 +686,11 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
+ 	if (p_res)
+ 		*p_res = res;
+ 
+-	return 0;
++res_check_done:
++	if (needs_unref)
++		vmw_resource_unreference(&res);
++
++	return ret;
+ }
+ 
+ /**
+@@ -1171,9 +1153,9 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
+ 	int ret;
+ 
+ 	vmw_validation_preload_bo(sw_context->ctx);
+-	vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
+-	if (IS_ERR(vmw_bo)) {
+-		VMW_DEBUG_USER("Could not find or use MOB buffer.\n");
++	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
++	if (ret != 0) {
++		drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
+ 		return PTR_ERR(vmw_bo);
+ 	}
+ 	ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false);
+@@ -1225,9 +1207,9 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
+ 	int ret;
+ 
+ 	vmw_validation_preload_bo(sw_context->ctx);
+-	vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
+-	if (IS_ERR(vmw_bo)) {
+-		VMW_DEBUG_USER("Could not find or use GMR region.\n");
++	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
++	if (ret != 0) {
++		drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
+ 		return PTR_ERR(vmw_bo);
+ 	}
+ 	ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false);
+@@ -2025,8 +2007,9 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
+ 		res = vmw_shader_lookup(vmw_context_res_man(ctx),
+ 					cmd->body.shid, cmd->body.type);
+ 		if (!IS_ERR(res)) {
+-			ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-							    VMW_RES_DIRTY_NONE);
++			ret = vmw_execbuf_res_val_add(sw_context, res,
++						      VMW_RES_DIRTY_NONE,
++						      vmw_val_add_flag_noctx);
+ 			if (unlikely(ret != 0))
+ 				return ret;
+ 
+@@ -2273,8 +2256,9 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
+ 			return PTR_ERR(res);
+ 		}
+ 
+-		ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-						    VMW_RES_DIRTY_NONE);
++		ret = vmw_execbuf_res_val_add(sw_context, res,
++					      VMW_RES_DIRTY_NONE,
++					      vmw_val_add_flag_noctx);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -2777,8 +2761,8 @@ static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
+ 		return PTR_ERR(res);
+ 	}
+ 
+-	ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-					    VMW_RES_DIRTY_NONE);
++	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
++				      vmw_val_add_flag_noctx);
+ 	if (ret) {
+ 		VMW_DEBUG_USER("Error creating resource validation node.\n");
+ 		return ret;
+@@ -3098,8 +3082,8 @@ static int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv,
+ 
+ 	vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes);
+ 
+-	ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-					    VMW_RES_DIRTY_NONE);
++	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
++				      vmw_val_add_flag_noctx);
+ 	if (ret) {
+ 		DRM_ERROR("Error creating resource validation node.\n");
+ 		return ret;
+@@ -3148,8 +3132,8 @@ static int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv,
+ 		return 0;
+ 	}
+ 
+-	ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
+-					    VMW_RES_DIRTY_NONE);
++	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
++				      vmw_val_add_flag_noctx);
+ 	if (ret) {
+ 		DRM_ERROR("Error creating resource validation node.\n");
+ 		return ret;
+@@ -4067,22 +4051,26 @@ static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
+ 	if (ret)
+ 		return ret;
+ 
+-	res = vmw_user_resource_noref_lookup_handle
++	ret = vmw_user_resource_lookup_handle
+ 		(dev_priv, sw_context->fp->tfile, handle,
+-		 user_context_converter);
+-	if (IS_ERR(res)) {
++		 user_context_converter, &res);
++	if (ret != 0) {
+ 		VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n",
+ 			       (unsigned int) handle);
+-		return PTR_ERR(res);
++		return ret;
+ 	}
+ 
+-	ret = vmw_execbuf_res_noref_val_add(sw_context, res, VMW_RES_DIRTY_SET);
+-	if (unlikely(ret != 0))
++	ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET,
++				      vmw_val_add_flag_none);
++	if (unlikely(ret != 0)) {
++		vmw_resource_unreference(&res);
+ 		return ret;
++	}
+ 
+ 	sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res);
+ 	sw_context->man = vmw_context_res_man(res);
+ 
++	vmw_resource_unreference(&res);
+ 	return 0;
+ }
+ 
+@@ -4101,7 +4089,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
+ 	int ret;
+ 	int32_t out_fence_fd = -1;
+ 	struct sync_file *sync_file = NULL;
+-	DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1);
++	DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
+ 
+ 	if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
+ 		out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
+@@ -4164,14 +4152,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
+ 	if (sw_context->staged_bindings)
+ 		vmw_binding_state_reset(sw_context->staged_bindings);
+ 
+-	if (!sw_context->res_ht_initialized) {
+-		ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
+-		if (unlikely(ret != 0))
+-			goto out_unlock;
+-
+-		sw_context->res_ht_initialized = true;
+-	}
+-
+ 	INIT_LIST_HEAD(&sw_context->staged_cmd_res);
+ 	sw_context->ctx = &val_ctx;
+ 	ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c
+deleted file mode 100644
+index 06aebc12774e7..0000000000000
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c
++++ /dev/null
+@@ -1,199 +0,0 @@
+-/*
+- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+- * All Rights Reserved.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the
+- * "Software"), to deal in the Software without restriction, including
+- * without limitation the rights to use, copy, modify, merge, publish,
+- * distribute, sub license, and/or sell copies of the Software, and to
+- * permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice (including the
+- * next paragraph) shall be included in all copies or substantial portions
+- * of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+- * USE OR OTHER DEALINGS IN THE SOFTWARE.
+- */
+-
+-/*
+- * Simple open hash tab implementation.
+- *
+- * Authors:
+- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+- */
+-
+-#include <linux/export.h>
+-#include <linux/hash.h>
+-#include <linux/mm.h>
+-#include <linux/rculist.h>
+-#include <linux/slab.h>
+-#include <linux/vmalloc.h>
+-
+-#include <drm/drm_print.h>
+-
+-#include "vmwgfx_hashtab.h"
+-
+-int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order)
+-{
+-	unsigned int size = 1 << order;
+-
+-	ht->order = order;
+-	ht->table = NULL;
+-	if (size <= PAGE_SIZE / sizeof(*ht->table))
+-		ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
+-	else
+-		ht->table = vzalloc(array_size(size, sizeof(*ht->table)));
+-	if (!ht->table) {
+-		DRM_ERROR("Out of memory for hash table\n");
+-		return -ENOMEM;
+-	}
+-	return 0;
+-}
+-
+-void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key)
+-{
+-	struct vmwgfx_hash_item *entry;
+-	struct hlist_head *h_list;
+-	unsigned int hashed_key;
+-	int count = 0;
+-
+-	hashed_key = hash_long(key, ht->order);
+-	DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
+-	h_list = &ht->table[hashed_key];
+-	hlist_for_each_entry(entry, h_list, head)
+-		DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
+-}
+-
+-static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key)
+-{
+-	struct vmwgfx_hash_item *entry;
+-	struct hlist_head *h_list;
+-	unsigned int hashed_key;
+-
+-	hashed_key = hash_long(key, ht->order);
+-	h_list = &ht->table[hashed_key];
+-	hlist_for_each_entry(entry, h_list, head) {
+-		if (entry->key == key)
+-			return &entry->head;
+-		if (entry->key > key)
+-			break;
+-	}
+-	return NULL;
+-}
+-
+-static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key)
+-{
+-	struct vmwgfx_hash_item *entry;
+-	struct hlist_head *h_list;
+-	unsigned int hashed_key;
+-
+-	hashed_key = hash_long(key, ht->order);
+-	h_list = &ht->table[hashed_key];
+-	hlist_for_each_entry_rcu(entry, h_list, head) {
+-		if (entry->key == key)
+-			return &entry->head;
+-		if (entry->key > key)
+-			break;
+-	}
+-	return NULL;
+-}
+-
+-int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
+-{
+-	struct vmwgfx_hash_item *entry;
+-	struct hlist_head *h_list;
+-	struct hlist_node *parent;
+-	unsigned int hashed_key;
+-	unsigned long key = item->key;
+-
+-	hashed_key = hash_long(key, ht->order);
+-	h_list = &ht->table[hashed_key];
+-	parent = NULL;
+-	hlist_for_each_entry(entry, h_list, head) {
+-		if (entry->key == key)
+-			return -EINVAL;
+-		if (entry->key > key)
+-			break;
+-		parent = &entry->head;
+-	}
+-	if (parent)
+-		hlist_add_behind_rcu(&item->head, parent);
+-	else
+-		hlist_add_head_rcu(&item->head, h_list);
+-	return 0;
+-}
+-
+-/*
+- * Just insert an item and return any "bits" bit key that hasn't been
+- * used before.
+- */
+-int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
+-				 unsigned long seed, int bits, int shift,
+-				 unsigned long add)
+-{
+-	int ret;
+-	unsigned long mask = (1UL << bits) - 1;
+-	unsigned long first, unshifted_key;
+-
+-	unshifted_key = hash_long(seed, bits);
+-	first = unshifted_key;
+-	do {
+-		item->key = (unshifted_key << shift) + add;
+-		ret = vmwgfx_ht_insert_item(ht, item);
+-		if (ret)
+-			unshifted_key = (unshifted_key + 1) & mask;
+-	} while (ret && (unshifted_key != first));
+-
+-	if (ret) {
+-		DRM_ERROR("Available key bit space exhausted\n");
+-		return -EINVAL;
+-	}
+-	return 0;
+-}
+-
+-int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
+-			struct vmwgfx_hash_item **item)
+-{
+-	struct hlist_node *list;
+-
+-	list = vmwgfx_ht_find_key_rcu(ht, key);
+-	if (!list)
+-		return -EINVAL;
+-
+-	*item = hlist_entry(list, struct vmwgfx_hash_item, head);
+-	return 0;
+-}
+-
+-int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key)
+-{
+-	struct hlist_node *list;
+-
+-	list = vmwgfx_ht_find_key(ht, key);
+-	if (list) {
+-		hlist_del_init_rcu(list);
+-		return 0;
+-	}
+-	return -EINVAL;
+-}
+-
+-int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
+-{
+-	hlist_del_init_rcu(&item->head);
+-	return 0;
+-}
+-
+-void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht)
+-{
+-	if (ht->table) {
+-		kvfree(ht->table);
+-		ht->table = NULL;
+-	}
+-}
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h
+deleted file mode 100644
+index a9ce12922e21c..0000000000000
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h
++++ /dev/null
+@@ -1,83 +0,0 @@
+-/*
+- * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
+- * All Rights Reserved.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a
+- * copy of this software and associated documentation files (the
+- * "Software"), to deal in the Software without restriction, including
+- * without limitation the rights to use, copy, modify, merge, publish,
+- * distribute, sub license, and/or sell copies of the Software, and to
+- * permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice (including the
+- * next paragraph) shall be included in all copies or substantial portions
+- * of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+- * USE OR OTHER DEALINGS IN THE SOFTWARE.
+- */
+-
+-/*
+- * Simple open hash tab implementation.
+- *
+- * Authors:
+- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+- */
+-
+-/*
+- * TODO: Replace this hashtable with Linux' generic implementation
+- *       from <linux/hashtable.h>.
+- */
+-
+-#ifndef VMWGFX_HASHTAB_H
+-#define VMWGFX_HASHTAB_H
+-
+-#include <linux/list.h>
+-
+-#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
+-
+-struct vmwgfx_hash_item {
+-	struct hlist_node head;
+-	unsigned long key;
+-};
+-
+-struct vmwgfx_open_hash {
+-	struct hlist_head *table;
+-	u8 order;
+-};
+-
+-int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order);
+-int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
+-int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
+-				 unsigned long seed, int bits, int shift,
+-				 unsigned long add);
+-int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
+-			struct vmwgfx_hash_item **item);
+-
+-void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key);
+-int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key);
+-int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
+-void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht);
+-
+-/*
+- * RCU-safe interface
+- *
+- * The user of this API needs to make sure that two or more instances of the
+- * hash table manipulation functions are never run simultaneously.
+- * The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously
+- * with any of the manipulation functions as long as it's called from within
+- * an RCU read-locked section.
+- */
+-#define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item
+-#define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please
+-#define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key
+-#define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item
+-#define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item
+-
+-#endif
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+index f66caa540e146..c7d645e5ec7bf 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+@@ -281,39 +281,6 @@ out_bad_resource:
+ 	return ret;
+ }
+ 
+-/**
+- * vmw_user_resource_noref_lookup_handle - lookup a struct resource from a
+- * TTM user-space handle and perform basic type checks
+- *
+- * @dev_priv:     Pointer to a device private struct
+- * @tfile:        Pointer to a struct ttm_object_file identifying the caller
+- * @handle:       The TTM user-space handle
+- * @converter:    Pointer to an object describing the resource type
+- *
+- * If the handle can't be found or is associated with an incorrect resource
+- * type, -EINVAL will be returned.
+- */
+-struct vmw_resource *
+-vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
+-				      struct ttm_object_file *tfile,
+-				      uint32_t handle,
+-				      const struct vmw_user_resource_conv
+-				      *converter)
+-{
+-	struct ttm_base_object *base;
+-
+-	base = ttm_base_object_noref_lookup(tfile, handle);
+-	if (!base)
+-		return ERR_PTR(-ESRCH);
+-
+-	if (unlikely(ttm_base_object_type(base) != converter->object_type)) {
+-		ttm_base_object_noref_release();
+-		return ERR_PTR(-EINVAL);
+-	}
+-
+-	return converter->base_obj_to_res(base);
+-}
+-
+ /*
+  * Helper function that looks either a surface or bo.
+  *
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+index f46891012be30..f5c4a40fb16d7 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0 OR MIT
+ /**************************************************************************
+  *
+- * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
++ * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -180,11 +180,16 @@ vmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
+ 	if (!ctx->merge_dups)
+ 		return NULL;
+ 
+-	if (ctx->ht) {
++	if (ctx->sw_context) {
+ 		struct vmwgfx_hash_item *hash;
++		unsigned long key = (unsigned long) vbo;
+ 
+-		if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash))
+-			bo_node = container_of(hash, typeof(*bo_node), hash);
++		hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
++			if (hash->key == key) {
++				bo_node = container_of(hash, typeof(*bo_node), hash);
++				break;
++			}
++		}
+ 	} else {
+ 		struct  vmw_validation_bo_node *entry;
+ 
+@@ -217,11 +222,16 @@ vmw_validation_find_res_dup(struct vmw_validation_context *ctx,
+ 	if (!ctx->merge_dups)
+ 		return NULL;
+ 
+-	if (ctx->ht) {
++	if (ctx->sw_context) {
+ 		struct vmwgfx_hash_item *hash;
++		unsigned long key = (unsigned long) res;
+ 
+-		if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash))
+-			res_node = container_of(hash, typeof(*res_node), hash);
++		hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
++			if (hash->key == key) {
++				res_node = container_of(hash, typeof(*res_node), hash);
++				break;
++			}
++		}
+ 	} else {
+ 		struct  vmw_validation_res_node *entry;
+ 
+@@ -269,20 +279,15 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx,
+ 		}
+ 	} else {
+ 		struct ttm_validate_buffer *val_buf;
+-		int ret;
+ 
+ 		bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
+ 		if (!bo_node)
+ 			return -ENOMEM;
+ 
+-		if (ctx->ht) {
++		if (ctx->sw_context) {
+ 			bo_node->hash.key = (unsigned long) vbo;
+-			ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash);
+-			if (ret) {
+-				DRM_ERROR("Failed to initialize a buffer "
+-					  "validation entry.\n");
+-				return ret;
+-			}
++			hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head,
++				bo_node->hash.key);
+ 		}
+ 		val_buf = &bo_node->base;
+ 		val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
+@@ -316,7 +321,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
+ 				bool *first_usage)
+ {
+ 	struct vmw_validation_res_node *node;
+-	int ret;
+ 
+ 	node = vmw_validation_find_res_dup(ctx, res);
+ 	if (node) {
+@@ -330,14 +334,9 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
+ 		return -ENOMEM;
+ 	}
+ 
+-	if (ctx->ht) {
++	if (ctx->sw_context) {
+ 		node->hash.key = (unsigned long) res;
+-		ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash);
+-		if (ret) {
+-			DRM_ERROR("Failed to initialize a resource validation "
+-				  "entry.\n");
+-			return ret;
+-		}
++		hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key);
+ 	}
+ 	node->res = vmw_resource_reference_unless_doomed(res);
+ 	if (!node->res)
+@@ -681,19 +680,19 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx)
+ 	struct vmw_validation_bo_node *entry;
+ 	struct vmw_validation_res_node *val;
+ 
+-	if (!ctx->ht)
++	if (!ctx->sw_context)
+ 		return;
+ 
+ 	list_for_each_entry(entry, &ctx->bo_list, base.head)
+-		(void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash);
++		hash_del_rcu(&entry->hash.head);
+ 
+ 	list_for_each_entry(val, &ctx->resource_list, head)
+-		(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
++		hash_del_rcu(&val->hash.head);
+ 
+ 	list_for_each_entry(val, &ctx->resource_ctx_list, head)
+-		(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
++		hash_del_rcu(&entry->hash.head);
+ 
+-	ctx->ht = NULL;
++	ctx->sw_context = NULL;
+ }
+ 
+ /**
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
+index f21df053882ba..ab9ec226f433a 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR MIT */
+ /**************************************************************************
+  *
+- * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
++ * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -29,12 +29,11 @@
+ #define _VMWGFX_VALIDATION_H_
+ 
+ #include <linux/list.h>
++#include <linux/hashtable.h>
+ #include <linux/ww_mutex.h>
+ 
+ #include <drm/ttm/ttm_execbuf_util.h>
+ 
+-#include "vmwgfx_hashtab.h"
+-
+ #define VMW_RES_DIRTY_NONE 0
+ #define VMW_RES_DIRTY_SET BIT(0)
+ #define VMW_RES_DIRTY_CLEAR BIT(1)
+@@ -59,7 +58,7 @@
+  * @total_mem: Amount of reserved memory.
+  */
+ struct vmw_validation_context {
+-	struct vmwgfx_open_hash *ht;
++	struct vmw_sw_context *sw_context;
+ 	struct list_head resource_list;
+ 	struct list_head resource_ctx_list;
+ 	struct list_head bo_list;
+@@ -82,16 +81,16 @@ struct vmw_fence_obj;
+ /**
+  * DECLARE_VAL_CONTEXT - Declare a validation context with initialization
+  * @_name: The name of the variable
+- * @_ht: The hash table used to find dups or NULL if none
++ * @_sw_context: Contains the hash table used to find dups or NULL if none
+  * @_merge_dups: Whether to merge duplicate buffer object- or resource
+  * entries. If set to true, ideally a hash table pointer should be supplied
+  * as well unless the number of resources and buffer objects per validation
+  * is known to be very small
+  */
+ #endif
+-#define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups)			\
++#define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups)		\
+ 	struct vmw_validation_context _name =				\
+-	{ .ht = _ht,							\
++	{ .sw_context = _sw_context,					\
+ 	  .resource_list = LIST_HEAD_INIT((_name).resource_list),	\
+ 	  .resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \
+ 	  .bo_list = LIST_HEAD_INIT((_name).bo_list),			\
+@@ -114,19 +113,6 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx)
+ 	return !list_empty(&ctx->bo_list);
+ }
+ 
+-/**
+- * vmw_validation_set_ht - Register a hash table for duplicate finding
+- * @ctx: The validation context
+- * @ht: Pointer to a hash table to use for duplicate finding
+- * This function is intended to be used if the hash table wasn't
+- * available at validation context declaration time
+- */
+-static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx,
+-					 struct vmwgfx_open_hash *ht)
+-{
+-	ctx->ht = ht;
+-}
+-
+ /**
+  * vmw_validation_bo_reserve - Reserve buffer objects registered with a
+  * validation context
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 6d5df91c5c465..d4d8bfee9febc 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -3854,7 +3854,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
+ 
+ static void arm_smmu_device_shutdown(struct platform_device *pdev)
+ {
+-	arm_smmu_device_remove(pdev);
++	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
++
++	arm_smmu_device_disable(smmu);
+ }
+ 
+ static const struct of_device_id arm_smmu_of_match[] = {
+diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+index 30dab1418e3ff..f38b54a887678 100644
+--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+@@ -1319,8 +1319,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
+ 
+ 	switch (cap) {
+ 	case IOMMU_CAP_CACHE_COHERENCY:
+-		/* Assume that a coherent TCU implies coherent TBUs */
+-		return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
++		/*
++		 * It's overwhelmingly the case in practice that when the pagetable
++		 * walk interface is connected to a coherent interconnect, all the
++		 * translation interfaces are too. Furthermore if the device is
++		 * natively coherent, then its translation interface must also be.
++		 */
++		return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK ||
++			device_get_dma_attr(dev) == DEV_DMA_COHERENT;
+ 	case IOMMU_CAP_NOEXEC:
+ 		return true;
+ 	default:
+@@ -2188,19 +2194,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
+ 	return 0;
+ }
+ 
+-static int arm_smmu_device_remove(struct platform_device *pdev)
++static void arm_smmu_device_shutdown(struct platform_device *pdev)
+ {
+ 	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+ 
+ 	if (!smmu)
+-		return -ENODEV;
++		return;
+ 
+ 	if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
+ 		dev_notice(&pdev->dev, "disabling translation\n");
+ 
+-	iommu_device_unregister(&smmu->iommu);
+-	iommu_device_sysfs_remove(&smmu->iommu);
+-
+ 	arm_smmu_rpm_get(smmu);
+ 	/* Turn the thing off */
+ 	arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD);
+@@ -2212,12 +2215,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
+ 		clk_bulk_disable(smmu->num_clks, smmu->clks);
+ 
+ 	clk_bulk_unprepare(smmu->num_clks, smmu->clks);
+-	return 0;
+ }
+ 
+-static void arm_smmu_device_shutdown(struct platform_device *pdev)
++static int arm_smmu_device_remove(struct platform_device *pdev)
+ {
+-	arm_smmu_device_remove(pdev);
++	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
++
++	if (!smmu)
++		return -ENODEV;
++
++	iommu_device_unregister(&smmu->iommu);
++	iommu_device_sysfs_remove(&smmu->iommu);
++
++	arm_smmu_device_shutdown(pdev);
++
++	return 0;
+ }
+ 
+ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
+diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
+index a44ad92fc5eb7..fe452ce466429 100644
+--- a/drivers/iommu/iova.c
++++ b/drivers/iommu/iova.c
+@@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
+ 
+ 	curr = __get_cached_rbnode(iovad, limit_pfn);
+ 	curr_iova = to_iova(curr);
+-	retry_pfn = curr_iova->pfn_hi + 1;
++	retry_pfn = curr_iova->pfn_hi;
+ 
+ retry:
+ 	do {
+@@ -211,7 +211,7 @@ retry:
+ 	if (high_pfn < size || new_pfn < low_pfn) {
+ 		if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) {
+ 			high_pfn = limit_pfn;
+-			low_pfn = retry_pfn;
++			low_pfn = retry_pfn + 1;
+ 			curr = iova_find_limit(iovad, limit_pfn);
+ 			curr_iova = to_iova(curr);
+ 			goto retry;
+diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
+index 6e0e65831eb70..a978220eb620e 100644
+--- a/drivers/iommu/mtk_iommu_v1.c
++++ b/drivers/iommu/mtk_iommu_v1.c
+@@ -685,7 +685,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
+ 	ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
+ 				     dev_name(&pdev->dev));
+ 	if (ret)
+-		return ret;
++		goto out_clk_unprepare;
+ 
+ 	ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
+ 	if (ret)
+@@ -700,6 +700,8 @@ out_dev_unreg:
+ 	iommu_device_unregister(&data->iommu);
+ out_sysfs_remove:
+ 	iommu_device_sysfs_remove(&data->iommu);
++out_clk_unprepare:
++	clk_disable_unprepare(data->bclk);
+ 	return ret;
+ }
+ 
+diff --git a/drivers/md/dm.c b/drivers/md/dm.c
+index e30c2d2bc9c78..d49809e9db96e 100644
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1755,6 +1755,8 @@ static void dm_split_and_process_bio(struct mapped_device *md,
+ 		 * otherwise associated queue_limits won't be imposed.
+ 		 */
+ 		bio = bio_split_to_limits(bio);
++		if (!bio)
++			return;
+ 	}
+ 
+ 	init_clone_info(&ci, md, map, bio, is_abnormal);
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index fd82881761d34..b911085060dc3 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -443,6 +443,8 @@ static void md_submit_bio(struct bio *bio)
+ 	}
+ 
+ 	bio = bio_split_to_limits(bio);
++	if (!bio)
++		return;
+ 
+ 	if (mddev->ro == 1 && unlikely(rw == WRITE)) {
+ 		if (bio_sectors(bio) != 0)
+diff --git a/drivers/mtd/parsers/scpart.c b/drivers/mtd/parsers/scpart.c
+index 02601bb33de4e..6e5e11c37078f 100644
+--- a/drivers/mtd/parsers/scpart.c
++++ b/drivers/mtd/parsers/scpart.c
+@@ -50,7 +50,7 @@ static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs,
+ 	int cnt = 0;
+ 	int res = 0;
+ 	int res2;
+-	loff_t offs;
++	uint32_t offs;
+ 	size_t retlen;
+ 	struct sc_part_desc *pdesc = NULL;
+ 	struct sc_part_desc *tmpdesc;
+diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
+index 2e0655c0b606f..5dbf52aa03551 100644
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -10,6 +10,7 @@
+ #include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/module.h>
++#include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/mutex.h>
+ #include <linux/math64.h>
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index f5a8bae8d79a1..edca16b5f9e34 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -990,7 +990,7 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
+ 			     DMA_ATTR_WEAK_ORDERING);
+ 	skb = build_skb(page_address(page), PAGE_SIZE);
+ 	if (!skb) {
+-		__free_page(page);
++		page_pool_recycle_direct(rxr->page_pool, page);
+ 		return NULL;
+ 	}
+ 	skb_mark_for_recycle(skb);
+@@ -1028,7 +1028,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
+ 
+ 	skb = napi_alloc_skb(&rxr->bnapi->napi, payload);
+ 	if (!skb) {
+-		__free_page(page);
++		page_pool_recycle_direct(rxr->page_pool, page);
+ 		return NULL;
+ 	}
+ 
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+index 081bd2c3f2891..e84e5be8e59ed 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+@@ -3130,7 +3130,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num,
+ 
+ 	hclgevf_update_rss_size(handle, new_tqps_num);
+ 
+-	hclge_comm_get_rss_tc_info(cur_rss_size, hdev->hw_tc_map,
++	hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map,
+ 				   tc_offset, tc_valid, tc_size);
+ 	ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset,
+ 					 tc_valid, tc_size);
+diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
+index f71e132ede094..260c55951c287 100644
+--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
+@@ -3850,7 +3850,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
+ 				field_flags |= IAVF_CLOUD_FIELD_IIP;
+ 			} else {
+ 				dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
+-					be32_to_cpu(match.mask->dst));
++					be32_to_cpu(match.mask->src));
+ 				return -EINVAL;
+ 			}
+ 		}
+diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
+index b5a7f246d230f..43e199b5b513b 100644
+--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
++++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
+@@ -363,6 +363,7 @@ ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+ 	/* Send the data out to a hardware port */
+ 	write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
+ 	if (!write_buf) {
++		kfree(cmd_buf);
+ 		err = -ENOMEM;
+ 		goto exit;
+ 	}
+@@ -460,6 +461,9 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
+ 	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
+ 		pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
+ 					       GFP_KERNEL);
++		if (!pf->gnss_tty_port[i])
++			goto err_out;
++
+ 		pf->gnss_serial[i] = NULL;
+ 
+ 		tty_port_init(pf->gnss_tty_port[i]);
+@@ -469,21 +473,23 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
+ 	err = tty_register_driver(tty_driver);
+ 	if (err) {
+ 		dev_err(dev, "Failed to register TTY driver err=%d\n", err);
+-
+-		for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
+-			tty_port_destroy(pf->gnss_tty_port[i]);
+-			kfree(pf->gnss_tty_port[i]);
+-		}
+-		kfree(ttydrv_name);
+-		tty_driver_kref_put(pf->ice_gnss_tty_driver);
+-
+-		return NULL;
++		goto err_out;
+ 	}
+ 
+ 	for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
+ 		dev_info(dev, "%s%d registered\n", ttydrv_name, i);
+ 
+ 	return tty_driver;
++
++err_out:
++	while (i--) {
++		tty_port_destroy(pf->gnss_tty_port[i]);
++		kfree(pf->gnss_tty_port[i]);
++	}
++	kfree(ttydrv_name);
++	tty_driver_kref_put(pf->ice_gnss_tty_driver);
++
++	return NULL;
+ }
+ 
+ /**
+diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
+index 4ad35fbdc02e8..dbfa4b9dee066 100644
+--- a/drivers/net/ethernet/intel/igc/igc_defines.h
++++ b/drivers/net/ethernet/intel/igc/igc_defines.h
+@@ -466,7 +466,9 @@
+ #define IGC_TSAUXC_EN_TT0	BIT(0)  /* Enable target time 0. */
+ #define IGC_TSAUXC_EN_TT1	BIT(1)  /* Enable target time 1. */
+ #define IGC_TSAUXC_EN_CLK0	BIT(2)  /* Enable Configurable Frequency Clock 0. */
++#define IGC_TSAUXC_ST0		BIT(4)  /* Start Clock 0 Toggle on Target Time 0. */
+ #define IGC_TSAUXC_EN_CLK1	BIT(5)  /* Enable Configurable Frequency Clock 1. */
++#define IGC_TSAUXC_ST1		BIT(7)  /* Start Clock 1 Toggle on Target Time 1. */
+ #define IGC_TSAUXC_EN_TS0	BIT(8)  /* Enable hardware timestamp 0. */
+ #define IGC_TSAUXC_AUTT0	BIT(9)  /* Auxiliary Timestamp Taken. */
+ #define IGC_TSAUXC_EN_TS1	BIT(10) /* Enable hardware timestamp 0. */
+diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
+index 8dbb9f903ca70..c34734d432e0d 100644
+--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
+@@ -322,7 +322,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
+ 		ts = ns_to_timespec64(ns);
+ 		if (rq->perout.index == 1) {
+ 			if (use_freq) {
+-				tsauxc_mask = IGC_TSAUXC_EN_CLK1;
++				tsauxc_mask = IGC_TSAUXC_EN_CLK1 | IGC_TSAUXC_ST1;
+ 				tsim_mask = 0;
+ 			} else {
+ 				tsauxc_mask = IGC_TSAUXC_EN_TT1;
+@@ -333,7 +333,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
+ 			freqout = IGC_FREQOUT1;
+ 		} else {
+ 			if (use_freq) {
+-				tsauxc_mask = IGC_TSAUXC_EN_CLK0;
++				tsauxc_mask = IGC_TSAUXC_EN_CLK0 | IGC_TSAUXC_ST0;
+ 				tsim_mask = 0;
+ 			} else {
+ 				tsauxc_mask = IGC_TSAUXC_EN_TT0;
+@@ -347,10 +347,12 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
+ 		tsauxc = rd32(IGC_TSAUXC);
+ 		tsim = rd32(IGC_TSIM);
+ 		if (rq->perout.index == 1) {
+-			tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1);
++			tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1 |
++				    IGC_TSAUXC_ST1);
+ 			tsim &= ~IGC_TSICR_TT1;
+ 		} else {
+-			tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0);
++			tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0 |
++				    IGC_TSAUXC_ST0);
+ 			tsim &= ~IGC_TSICR_TT0;
+ 		}
+ 		if (on) {
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+index 24aa97f993ca1..123dca9ce4683 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+@@ -855,9 +855,11 @@ static struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn)
+ 	rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn);
+ 	if (rp_pdev && rp_pdev->subordinate) {
+ 		bus = rp_pdev->subordinate->number;
++		pci_dev_put(rp_pdev);
+ 		return pci_get_domain_bus_and_slot(0, bus, 0);
+ 	}
+ 
++	pci_dev_put(rp_pdev);
+ 	return NULL;
+ }
+ 
+@@ -874,6 +876,7 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw)
+ 	struct ixgbe_adapter *adapter = hw->back;
+ 	struct pci_dev *pdev = adapter->pdev;
+ 	struct pci_dev *func0_pdev;
++	bool has_mii = false;
+ 
+ 	/* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices
+ 	 * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0
+@@ -884,15 +887,16 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw)
+ 	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0));
+ 	if (func0_pdev) {
+ 		if (func0_pdev == pdev)
+-			return true;
+-		else
+-			return false;
++			has_mii = true;
++		goto out;
+ 	}
+ 	func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0));
+ 	if (func0_pdev == pdev)
+-		return true;
++		has_mii = true;
+ 
+-	return false;
++out:
++	pci_dev_put(func0_pdev);
++	return has_mii;
+ }
+ 
+ /**
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+index c8724bfa86b0e..8fdd3afe59981 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+@@ -768,9 +768,9 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
+ 
+ 	cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
+ 	if (enable)
+-		cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN;
++		cfg |= DATA_PKT_RX_EN | DATA_PKT_TX_EN;
+ 	else
+-		cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN);
++		cfg &= ~(DATA_PKT_RX_EN | DATA_PKT_TX_EN);
+ 	cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg);
+ 	return 0;
+ }
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+index 0b06788b8d80a..04338db38671b 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+@@ -30,7 +30,6 @@
+ #define CMR_P2X_SEL_SHIFT		59ULL
+ #define CMR_P2X_SEL_NIX0		1ULL
+ #define CMR_P2X_SEL_NIX1		2ULL
+-#define CMR_EN				BIT_ULL(55)
+ #define DATA_PKT_TX_EN			BIT_ULL(53)
+ #define DATA_PKT_RX_EN			BIT_ULL(54)
+ #define CGX_LMAC_TYPE_SHIFT		40
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+index 86653bb8e403a..7f8ffbf79cf74 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+@@ -758,6 +758,8 @@ static void otx2vf_remove(struct pci_dev *pdev)
+ 	if (vf->otx2_wq)
+ 		destroy_workqueue(vf->otx2_wq);
+ 	otx2_ptp_destroy(vf);
++	otx2_mcam_flow_del(vf);
++	otx2_shutdown_tc(vf);
+ 	otx2vf_disable_mbox_intr(vf);
+ 	otx2_detach_resources(&vf->mbox);
+ 	if (test_bit(CN10K_LMTST, &vf->hw.cap_flag))
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+index e7a894ba5c3ea..723891eb86eec 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+@@ -2177,15 +2177,9 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
+ 		return -EINVAL;
+ 	}
+ 
+-	cmd->stats = kvcalloc(MLX5_CMD_OP_MAX, sizeof(*cmd->stats), GFP_KERNEL);
+-	if (!cmd->stats)
+-		return -ENOMEM;
+-
+ 	cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
+-	if (!cmd->pool) {
+-		err = -ENOMEM;
+-		goto dma_pool_err;
+-	}
++	if (!cmd->pool)
++		return -ENOMEM;
+ 
+ 	err = alloc_cmd_page(dev, cmd);
+ 	if (err)
+@@ -2269,8 +2263,6 @@ err_free_page:
+ 
+ err_free_pool:
+ 	dma_pool_destroy(cmd->pool);
+-dma_pool_err:
+-	kvfree(cmd->stats);
+ 	return err;
+ }
+ 
+@@ -2283,7 +2275,6 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
+ 	destroy_msg_cache(dev);
+ 	free_cmd_page(dev, cmd);
+ 	dma_pool_destroy(cmd->pool);
+-	kvfree(cmd->stats);
+ }
+ 
+ void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
+index fd07c4cbfd1d2..1f62c702b6255 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
+@@ -88,6 +88,8 @@ static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
+ 	struct udphdr *udp = (struct udphdr *)(buf);
+ 	struct vxlanhdr *vxh;
+ 
++	if (tun_key->tun_flags & TUNNEL_VXLAN_OPT)
++		return -EOPNOTSUPP;
+ 	vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
+ 	*ip_proto = IPPROTO_UDP;
+ 
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+index f900709639f6e..b92d541b5286e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+@@ -62,6 +62,7 @@ struct mlx5e_macsec_sa {
+ 	u32 enc_key_id;
+ 	u32 next_pn;
+ 	sci_t sci;
++	ssci_t ssci;
+ 	salt_t salt;
+ 
+ 	struct rhash_head hash;
+@@ -358,7 +359,6 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+ 	struct mlx5_macsec_obj_attrs obj_attrs;
+ 	union mlx5e_macsec_rule *macsec_rule;
+-	struct macsec_key *key;
+ 	int err;
+ 
+ 	obj_attrs.next_pn = sa->next_pn;
+@@ -368,13 +368,9 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
+ 	obj_attrs.aso_pdn = macsec->aso.pdn;
+ 	obj_attrs.epn_state = sa->epn_state;
+ 
+-	key = (is_tx) ? &ctx->sa.tx_sa->key : &ctx->sa.rx_sa->key;
+-
+ 	if (sa->epn_state.epn_enabled) {
+-		obj_attrs.ssci = (is_tx) ? cpu_to_be32((__force u32)ctx->sa.tx_sa->ssci) :
+-					   cpu_to_be32((__force u32)ctx->sa.rx_sa->ssci);
+-
+-		memcpy(&obj_attrs.salt, &key->salt, sizeof(key->salt));
++		obj_attrs.ssci = cpu_to_be32((__force u32)sa->ssci);
++		memcpy(&obj_attrs.salt, &sa->salt, sizeof(sa->salt));
+ 	}
+ 
+ 	obj_attrs.replay_window = ctx->secy->replay_window;
+@@ -499,10 +495,11 @@ mlx5e_macsec_get_macsec_device_context(const struct mlx5e_macsec *macsec,
+ }
+ 
+ static void update_macsec_epn(struct mlx5e_macsec_sa *sa, const struct macsec_key *key,
+-			      const pn_t *next_pn_halves)
++			      const pn_t *next_pn_halves, ssci_t ssci)
+ {
+ 	struct mlx5e_macsec_epn_state *epn_state = &sa->epn_state;
+ 
++	sa->ssci = ssci;
+ 	sa->salt = key->salt;
+ 	epn_state->epn_enabled = 1;
+ 	epn_state->epn_msb = next_pn_halves->upper;
+@@ -550,7 +547,8 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx)
+ 	tx_sa->assoc_num = assoc_num;
+ 
+ 	if (secy->xpn)
+-		update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves);
++		update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves,
++				  ctx_tx_sa->ssci);
+ 
+ 	err = mlx5_create_encryption_key(mdev, ctx->sa.key, secy->key_len,
+ 					 MLX5_ACCEL_OBJ_MACSEC_KEY,
+@@ -945,7 +943,8 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx)
+ 	rx_sa->fs_id = rx_sc->sc_xarray_element->fs_id;
+ 
+ 	if (ctx->secy->xpn)
+-		update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves);
++		update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves,
++				  ctx_rx_sa->ssci);
+ 
+ 	err = mlx5_create_encryption_key(mdev, ctx->sa.key, ctx->secy->key_len,
+ 					 MLX5_ACCEL_OBJ_MACSEC_KEY,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 951ede4338132..4dc149ef618c4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -4071,6 +4071,9 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
+ 	struct mlx5e_vlan_table *vlan;
+ 	struct mlx5e_params *params;
+ 
++	if (!netif_device_present(netdev))
++		return features;
++
+ 	vlan = mlx5e_fs_get_vlan(priv->fs);
+ 	mutex_lock(&priv->state_lock);
+ 	params = &priv->channels.params;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index a61a43fc8d5c5..56d1bd22c7c66 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -2300,7 +2300,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
+ 
+ 	priv = mlx5i_epriv(netdev);
+ 	tstamp = &priv->tstamp;
+-	stats = rq->stats;
++	stats = &priv->channel_stats[rq->ix]->rq;
+ 
+ 	flags_rqpn = be32_to_cpu(cqe->flags_rqpn);
+ 	g = (flags_rqpn >> 28) & 3;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index bd9936af45827..4c313b7424bf5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -1283,7 +1283,6 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
+ 
+ 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
+ 		err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
+-		mlx5e_mod_hdr_dealloc(&parse_attr->mod_hdr_acts);
+ 		if (err)
+ 			return err;
+ 	}
+@@ -1341,8 +1340,10 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
+ 	}
+ 	mutex_unlock(&tc->t_lock);
+ 
+-	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
++	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
++		mlx5e_mod_hdr_dealloc(&attr->parse_attr->mod_hdr_acts);
+ 		mlx5e_detach_mod_hdr(priv, flow);
++	}
+ 
+ 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
+ 		mlx5_fc_destroy(priv->mdev, attr->counter);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+index 8c6c9bcb3dc3f..b4e263e8cfb87 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+@@ -142,7 +142,7 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
+ 		if (mlx5_esw_indir_table_decap_vport(attr))
+ 			vport = mlx5_esw_indir_table_decap_vport(attr);
+ 
+-		if (attr && !attr->chain && esw_attr->int_port)
++		if (!attr->chain && esw_attr && esw_attr->int_port)
+ 			metadata =
+ 				mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port);
+ 		else
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+index c247cca154e9c..eff92dc0927c1 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+@@ -90,9 +90,21 @@ static void mlx5i_get_ringparam(struct net_device *dev,
+ static int mlx5i_set_channels(struct net_device *dev,
+ 			      struct ethtool_channels *ch)
+ {
+-	struct mlx5e_priv *priv = mlx5i_epriv(dev);
++	struct mlx5i_priv *ipriv = netdev_priv(dev);
++	struct mlx5e_priv *epriv = mlx5i_epriv(dev);
++
++	/* rtnl lock protects from race between this ethtool op and sub
++	 * interface ndo_init/uninit.
++	 */
++	ASSERT_RTNL();
++	if (ipriv->num_sub_interfaces > 0) {
++		mlx5_core_warn(epriv->mdev,
++			       "can't change number of channels for interfaces with sub interfaces (%u)\n",
++			       ipriv->num_sub_interfaces);
++		return -EINVAL;
++	}
+ 
+-	return mlx5e_ethtool_set_channels(priv, ch);
++	return mlx5e_ethtool_set_channels(epriv, ch);
+ }
+ 
+ static void mlx5i_get_channels(struct net_device *dev,
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+index 84f5352b0ce19..038ae0fcf9d45 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+@@ -160,6 +160,44 @@ void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
+ 	stats->tx_dropped = sstats->tx_queue_dropped;
+ }
+ 
++struct net_device *mlx5i_parent_get(struct net_device *netdev)
++{
++	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
++	struct mlx5i_priv *ipriv, *parent_ipriv;
++	struct net_device *parent_dev;
++	int parent_ifindex;
++
++	ipriv = priv->ppriv;
++
++	parent_ifindex = netdev->netdev_ops->ndo_get_iflink(netdev);
++	parent_dev = dev_get_by_index(dev_net(netdev), parent_ifindex);
++	if (!parent_dev)
++		return NULL;
++
++	parent_ipriv = netdev_priv(parent_dev);
++
++	ASSERT_RTNL();
++	parent_ipriv->num_sub_interfaces++;
++
++	ipriv->parent_dev = parent_dev;
++
++	return parent_dev;
++}
++
++void mlx5i_parent_put(struct net_device *netdev)
++{
++	struct mlx5e_priv *priv = mlx5i_epriv(netdev);
++	struct mlx5i_priv *ipriv, *parent_ipriv;
++
++	ipriv = priv->ppriv;
++	parent_ipriv = netdev_priv(ipriv->parent_dev);
++
++	ASSERT_RTNL();
++	parent_ipriv->num_sub_interfaces--;
++
++	dev_put(ipriv->parent_dev);
++}
++
+ int mlx5i_init_underlay_qp(struct mlx5e_priv *priv)
+ {
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+index 99d46fda9f82f..f3f2af972020a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+@@ -54,9 +54,11 @@ struct mlx5i_priv {
+ 	struct rdma_netdev rn; /* keep this first */
+ 	u32 qpn;
+ 	bool   sub_interface;
++	u32    num_sub_interfaces;
+ 	u32    qkey;
+ 	u16    pkey_index;
+ 	struct mlx5i_pkey_qpn_ht *qpn_htbl;
++	struct net_device *parent_dev;
+ 	char  *mlx5e_priv[];
+ };
+ 
+@@ -117,5 +119,9 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
+ 		   struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more);
+ void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
+ 
++/* Reference management for child to parent interfaces. */
++struct net_device *mlx5i_parent_get(struct net_device *netdev);
++void mlx5i_parent_put(struct net_device *netdev);
++
+ #endif /* CONFIG_MLX5_CORE_IPOIB */
+ #endif /* __MLX5E_IPOB_H__ */
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+index 0227a521d301e..0cf4eaf852d2a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+@@ -158,21 +158,28 @@ static int mlx5i_pkey_dev_init(struct net_device *dev)
+ 	struct mlx5e_priv *priv = mlx5i_epriv(dev);
+ 	struct mlx5i_priv *ipriv, *parent_ipriv;
+ 	struct net_device *parent_dev;
+-	int parent_ifindex;
+ 
+ 	ipriv = priv->ppriv;
+ 
+-	/* Get QPN to netdevice hash table from parent */
+-	parent_ifindex = dev->netdev_ops->ndo_get_iflink(dev);
+-	parent_dev = dev_get_by_index(dev_net(dev), parent_ifindex);
++	/* Link to parent */
++	parent_dev = mlx5i_parent_get(dev);
+ 	if (!parent_dev) {
+ 		mlx5_core_warn(priv->mdev, "failed to get parent device\n");
+ 		return -EINVAL;
+ 	}
+ 
++	if (dev->num_rx_queues < parent_dev->real_num_rx_queues) {
++		mlx5_core_warn(priv->mdev,
++			       "failed to create child device with rx queues [%d] less than parent's [%d]\n",
++			       dev->num_rx_queues,
++			       parent_dev->real_num_rx_queues);
++		mlx5i_parent_put(dev);
++		return -EINVAL;
++	}
++
++	/* Get QPN to netdevice hash table from parent */
+ 	parent_ipriv = netdev_priv(parent_dev);
+ 	ipriv->qpn_htbl = parent_ipriv->qpn_htbl;
+-	dev_put(parent_dev);
+ 
+ 	return mlx5i_dev_init(dev);
+ }
+@@ -184,6 +191,7 @@ static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ 
+ static void mlx5i_pkey_dev_cleanup(struct net_device *netdev)
+ {
++	mlx5i_parent_put(netdev);
+ 	return mlx5i_dev_cleanup(netdev);
+ }
+ 
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+index d3a9ae80fd30e..d7ddfc489536e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+@@ -691,7 +691,7 @@ static int mlx5_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+ static const struct ptp_clock_info mlx5_ptp_clock_info = {
+ 	.owner		= THIS_MODULE,
+ 	.name		= "mlx5_ptp",
+-	.max_adj	= 100000000,
++	.max_adj	= 50000000,
+ 	.n_alarm	= 0,
+ 	.n_ext_ts	= 0,
+ 	.n_per_out	= 0,
+diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+index e5a2bbe064f8f..8e368318558ac 100644
+--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+@@ -853,6 +853,9 @@ void lan966x_ptp_deinit(struct lan966x *lan966x)
+ 	struct lan966x_port *port;
+ 	int i;
+ 
++	if (!lan966x->ptp)
++		return;
++
+ 	for (i = 0; i < lan966x->num_phys_ports; i++) {
+ 		port = lan966x->ports[i];
+ 		if (!port)
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index a73d061d9fcb1..fe8dc8e0522b0 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -1996,10 +1996,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
+ 
+ 		/* 8168F family. */
+ 		{ 0x7c8, 0x488,	RTL_GIGA_MAC_VER_38 },
+-		/* It seems this chip version never made it to
+-		 * the wild. Let's disable detection.
+-		 * { 0x7cf, 0x481,	RTL_GIGA_MAC_VER_36 },
+-		 */
++		{ 0x7cf, 0x481,	RTL_GIGA_MAC_VER_36 },
+ 		{ 0x7cf, 0x480,	RTL_GIGA_MAC_VER_35 },
+ 
+ 		/* 8168E family. */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+index d42e1afb65213..2f7d8e4561d92 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+@@ -90,7 +90,6 @@ struct mediatek_dwmac_plat_data {
+ struct mediatek_dwmac_variant {
+ 	int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat);
+ 	int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat);
+-	void (*dwmac_fix_mac_speed)(void *priv, unsigned int speed);
+ 
+ 	/* clock ids to be requested */
+ 	const char * const *clk_list;
+@@ -443,32 +442,9 @@ static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
+ 	return 0;
+ }
+ 
+-static void mt8195_fix_mac_speed(void *priv, unsigned int speed)
+-{
+-	struct mediatek_dwmac_plat_data *priv_plat = priv;
+-
+-	if ((phy_interface_mode_is_rgmii(priv_plat->phy_mode))) {
+-		/* prefer 2ns fixed delay which is controlled by TXC_PHASE_CTRL,
+-		 * when link speed is 1Gbps with RGMII interface,
+-		 * Fall back to delay macro circuit for 10/100Mbps link speed.
+-		 */
+-		if (speed == SPEED_1000)
+-			regmap_update_bits(priv_plat->peri_regmap,
+-					   MT8195_PERI_ETH_CTRL0,
+-					   MT8195_RGMII_TXC_PHASE_CTRL |
+-					   MT8195_DLY_GTXC_ENABLE |
+-					   MT8195_DLY_GTXC_INV |
+-					   MT8195_DLY_GTXC_STAGES,
+-					   MT8195_RGMII_TXC_PHASE_CTRL);
+-		else
+-			mt8195_set_delay(priv_plat);
+-	}
+-}
+-
+ static const struct mediatek_dwmac_variant mt8195_gmac_variant = {
+ 	.dwmac_set_phy_interface = mt8195_set_interface,
+ 	.dwmac_set_delay = mt8195_set_delay,
+-	.dwmac_fix_mac_speed = mt8195_fix_mac_speed,
+ 	.clk_list = mt8195_dwmac_clk_l,
+ 	.num_clks = ARRAY_SIZE(mt8195_dwmac_clk_l),
+ 	.dma_bit_mask = 35,
+@@ -619,8 +595,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
+ 	plat->bsp_priv = priv_plat;
+ 	plat->init = mediatek_dwmac_init;
+ 	plat->clks_config = mediatek_dwmac_clks_config;
+-	if (priv_plat->variant->dwmac_fix_mac_speed)
+-		plat->fix_mac_speed = priv_plat->variant->dwmac_fix_mac_speed;
+ 
+ 	plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
+ 					     sizeof(*plat->safety_feat_cfg),
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+index 4d11980dcd64d..9c91a3dc8e385 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+@@ -219,7 +219,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
+ 		}
+ 		writel(acr_value, ptpaddr + PTP_ACR);
+ 		mutex_unlock(&priv->aux_ts_lock);
+-		ret = 0;
++		/* wait for auxts fifo clear to finish */
++		ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
++					 !(acr_value & PTP_ACR_ATSFC),
++					 10, 10000);
+ 		break;
+ 
+ 	default:
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+index a83699de01ec3..fdd0c9abc1a10 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+@@ -79,7 +79,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ 	/* Apple ARM64 platforms have their own idea of board type, passed in
+ 	 * via the device tree. They also have an antenna SKU parameter
+ 	 */
+-	if (!of_property_read_string(np, "brcm,board-type", &prop))
++	err = of_property_read_string(np, "brcm,board-type", &prop);
++	if (!err)
+ 		settings->board_type = prop;
+ 
+ 	if (!of_property_read_string(np, "apple,antenna-sku", &prop))
+@@ -87,7 +88,7 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ 
+ 	/* Set board-type to the first string of the machine compatible prop */
+ 	root = of_find_node_by_path("/");
+-	if (root && !settings->board_type) {
++	if (root && err) {
+ 		char *board_type;
+ 		const char *tmp;
+ 
+diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c
+index 6f71ac72012ea..ed9c5e2cf3ad4 100644
+--- a/drivers/nfc/pn533/usb.c
++++ b/drivers/nfc/pn533/usb.c
+@@ -153,10 +153,17 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags)
+ 	return usb_submit_urb(phy->ack_urb, flags);
+ }
+ 
++struct pn533_out_arg {
++	struct pn533_usb_phy *phy;
++	struct completion done;
++};
++
+ static int pn533_usb_send_frame(struct pn533 *dev,
+ 				struct sk_buff *out)
+ {
+ 	struct pn533_usb_phy *phy = dev->phy;
++	struct pn533_out_arg arg;
++	void *cntx;
+ 	int rc;
+ 
+ 	if (phy->priv == NULL)
+@@ -168,10 +175,17 @@ static int pn533_usb_send_frame(struct pn533 *dev,
+ 	print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+ 			     out->data, out->len, false);
+ 
++	init_completion(&arg.done);
++	cntx = phy->out_urb->context;
++	phy->out_urb->context = &arg;
++
+ 	rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
+ 	if (rc)
+ 		return rc;
+ 
++	wait_for_completion(&arg.done);
++	phy->out_urb->context = cntx;
++
+ 	if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
+ 		/* request for response for sent packet directly */
+ 		rc = pn533_submit_urb_for_response(phy, GFP_KERNEL);
+@@ -408,7 +422,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy)
+ 	return arg.rc;
+ }
+ 
+-static void pn533_send_complete(struct urb *urb)
++static void pn533_out_complete(struct urb *urb)
++{
++	struct pn533_out_arg *arg = urb->context;
++	struct pn533_usb_phy *phy = arg->phy;
++
++	switch (urb->status) {
++	case 0:
++		break; /* success */
++	case -ECONNRESET:
++	case -ENOENT:
++		dev_dbg(&phy->udev->dev,
++			"The urb has been stopped (status %d)\n",
++			urb->status);
++		break;
++	case -ESHUTDOWN:
++	default:
++		nfc_err(&phy->udev->dev,
++			"Urb failure (status %d)\n",
++			urb->status);
++	}
++
++	complete(&arg->done);
++}
++
++static void pn533_ack_complete(struct urb *urb)
+ {
+ 	struct pn533_usb_phy *phy = urb->context;
+ 
+@@ -496,10 +534,10 @@ static int pn533_usb_probe(struct usb_interface *interface,
+ 
+ 	usb_fill_bulk_urb(phy->out_urb, phy->udev,
+ 			  usb_sndbulkpipe(phy->udev, out_endpoint),
+-			  NULL, 0, pn533_send_complete, phy);
++			  NULL, 0, pn533_out_complete, phy);
+ 	usb_fill_bulk_urb(phy->ack_urb, phy->udev,
+ 			  usb_sndbulkpipe(phy->udev, out_endpoint),
+-			  NULL, 0, pn533_send_complete, phy);
++			  NULL, 0, pn533_ack_complete, phy);
+ 
+ 	switch (id->driver_info) {
+ 	case PN533_DEVICE_STD:
+diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
+index 7e025b8948cbf..d09ed00701743 100644
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -351,6 +351,8 @@ static void nvme_ns_head_submit_bio(struct bio *bio)
+ 	 * pool from the original queue to allocate the bvecs from.
+ 	 */
+ 	bio = bio_split_to_limits(bio);
++	if (!bio)
++		return;
+ 
+ 	srcu_idx = srcu_read_lock(&head->srcu);
+ 	ns = nvme_find_path(head);
+diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
+index 6be8968717182..9bc6e3922e78e 100644
+--- a/drivers/pinctrl/pinctrl-amd.c
++++ b/drivers/pinctrl/pinctrl-amd.c
+@@ -628,13 +628,15 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
+ 		/* Each status bit covers four pins */
+ 		for (i = 0; i < 4; i++) {
+ 			regval = readl(regs + i);
+-			/* caused wake on resume context for shared IRQ */
+-			if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) {
++
++			if (regval & PIN_IRQ_PENDING)
+ 				dev_dbg(&gpio_dev->pdev->dev,
+-					"Waking due to GPIO %d: 0x%x",
++					"GPIO %d is active: 0x%x",
+ 					irqnr + i, regval);
++
++			/* caused wake on resume context for shared IRQ */
++			if (irq < 0 && (regval & BIT(WAKE_STS_OFF)))
+ 				return true;
+-			}
+ 
+ 			if (!(regval & PIN_IRQ_PENDING) ||
+ 			    !(regval & BIT(INTERRUPT_MASK_OFF)))
+diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
+index 43e7651991371..c6537a1b3a2ec 100644
+--- a/drivers/platform/surface/aggregator/controller.c
++++ b/drivers/platform/surface/aggregator/controller.c
+@@ -1700,8 +1700,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
+ 		return status;
+ 
+ 	status = ssam_request_sync_init(rqst, spec->flags);
+-	if (status)
++	if (status) {
++		ssam_request_sync_free(rqst);
+ 		return status;
++	}
+ 
+ 	ssam_request_sync_set_resp(rqst, rsp);
+ 
+diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
+index f5565570f16c7..69132976d297e 100644
+--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
++++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
+@@ -916,6 +916,20 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
+ 	if (sshp_parse_command(dev, data, &command, &command_data))
+ 		return;
+ 
++	/*
++	 * Check if the message was intended for us. If not, drop it.
++	 *
++	 * Note: We will need to change this to handle debug messages. On newer
++	 * generation devices, these seem to be sent to tid_out=0x03. We as
++	 * host can still receive them as they can be forwarded via an override
++	 * option on SAM, but doing so does not change tid_out=0x00.
++	 */
++	if (command->tid_out != 0x00) {
++		rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n",
++			 command->tid_out);
++		return;
++	}
++
+ 	if (ssh_rqid_is_event(get_unaligned_le16(&command->rqid)))
+ 		ssh_rtl_rx_event(rtl, command, &command_data);
+ 	else
+diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c
+index 439d282aafd19..8d924986381be 100644
+--- a/drivers/platform/x86/amd/pmc.c
++++ b/drivers/platform/x86/amd/pmc.c
+@@ -932,7 +932,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
+ 	if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
+ 		err = amd_pmc_s2d_init(dev);
+ 		if (err)
+-			return err;
++			goto err_pci_dev_put;
+ 	}
+ 
+ 	platform_set_drvdata(pdev, dev);
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 872efc1d5b36b..f051b21653d61 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -2436,6 +2436,9 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
+ 
+ 	*available = false;
+ 
++	if (asus->fan_type == FAN_TYPE_NONE)
++		return 0;
++
+ 	err = fan_curve_get_factory_default(asus, fan_dev);
+ 	if (err) {
+ 		return 0;
+diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c
+index c82b3d6867c5b..c517bd45dd32e 100644
+--- a/drivers/platform/x86/dell/dell-wmi-privacy.c
++++ b/drivers/platform/x86/dell/dell-wmi-privacy.c
+@@ -61,7 +61,7 @@ static const struct key_entry dell_wmi_keymap_type_0012[] = {
+ 	/* privacy mic mute */
+ 	{ KE_KEY, 0x0001, { KEY_MICMUTE } },
+ 	/* privacy camera mute */
+-	{ KE_SW,  0x0002, { SW_CAMERA_LENS_COVER } },
++	{ KE_VSW, 0x0002, { SW_CAMERA_LENS_COVER } },
+ 	{ KE_END, 0},
+ };
+ 
+@@ -115,11 +115,15 @@ bool dell_privacy_process_event(int type, int code, int status)
+ 
+ 	switch (code) {
+ 	case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */
+-	case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
+ 		priv->last_status = status;
+ 		sparse_keymap_report_entry(priv->input_dev, key, 1, true);
+ 		ret = true;
+ 		break;
++	case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
++		priv->last_status = status;
++		sparse_keymap_report_entry(priv->input_dev, key, !(status & CAMERA_STATUS), false);
++		ret = true;
++		break;
+ 	default:
+ 		dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code);
+ 	}
+@@ -292,7 +296,7 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
+ {
+ 	struct privacy_wmi_data *priv;
+ 	struct key_entry *keymap;
+-	int ret, i;
++	int ret, i, j;
+ 
+ 	ret = wmi_has_guid(DELL_PRIVACY_GUID);
+ 	if (!ret)
+@@ -304,6 +308,11 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
+ 
+ 	dev_set_drvdata(&wdev->dev, priv);
+ 	priv->wdev = wdev;
++
++	ret = get_current_status(priv->wdev);
++	if (ret)
++		return ret;
++
+ 	/* create evdev passing interface */
+ 	priv->input_dev = devm_input_allocate_device(&wdev->dev);
+ 	if (!priv->input_dev)
+@@ -318,9 +327,20 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
+ 	/* remap the keymap code with Dell privacy key type 0x12 as prefix
+ 	 * KEY_MICMUTE scancode will be reported as 0x120001
+ 	 */
+-	for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
+-		keymap[i] = dell_wmi_keymap_type_0012[i];
+-		keymap[i].code |= (0x0012 << 16);
++	for (i = 0, j = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
++		/*
++		 * Unlike keys where only presses matter, userspace may act
++		 * on switches in both of their positions. Only register
++		 * SW_CAMERA_LENS_COVER if it is actually there.
++		 */
++		if (dell_wmi_keymap_type_0012[i].type == KE_VSW &&
++		    dell_wmi_keymap_type_0012[i].sw.code == SW_CAMERA_LENS_COVER &&
++		    !(priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA)))
++			continue;
++
++		keymap[j] = dell_wmi_keymap_type_0012[i];
++		keymap[j].code |= (0x0012 << 16);
++		j++;
+ 	}
+ 	ret = sparse_keymap_setup(priv->input_dev, keymap, NULL);
+ 	kfree(keymap);
+@@ -331,11 +351,12 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
+ 	priv->input_dev->name = "Dell Privacy Driver";
+ 	priv->input_dev->id.bustype = BUS_HOST;
+ 
+-	ret = input_register_device(priv->input_dev);
+-	if (ret)
+-		return ret;
++	/* Report initial camera-cover status */
++	if (priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA))
++		input_report_switch(priv->input_dev, SW_CAMERA_LENS_COVER,
++				    !(priv->last_status & CAMERA_STATUS));
+ 
+-	ret = get_current_status(priv->wdev);
++	ret = input_register_device(priv->input_dev);
+ 	if (ret)
+ 		return ret;
+ 
+diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
+index fc3d47a759443..4e28c55f0ea52 100644
+--- a/drivers/platform/x86/ideapad-laptop.c
++++ b/drivers/platform/x86/ideapad-laptop.c
+@@ -1615,6 +1615,12 @@ static const struct dmi_system_id set_fn_lock_led_list[] = {
+ 			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"),
+ 		}
+ 	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"),
++		}
++	},
+ 	{}
+ };
+ 
+diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
+index b2342b3d78c72..74dc2cff799ee 100644
+--- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c
++++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
+@@ -181,6 +181,9 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
+ 		return PTR_ERR(int3472->regulator.gpio);
+ 	}
+ 
++	/* Ensure the pin is in output mode and non-active state */
++	gpiod_direction_output(int3472->regulator.gpio, 0);
++
+ 	cfg.dev = &int3472->adev->dev;
+ 	cfg.init_data = &init_data;
+ 	cfg.ena_gpiod = int3472->regulator.gpio;
+diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
+index 974a132db6516..c42c3faa2c32d 100644
+--- a/drivers/platform/x86/intel/int3472/discrete.c
++++ b/drivers/platform/x86/intel/int3472/discrete.c
+@@ -168,6 +168,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
+ 			return (PTR_ERR(gpio));
+ 
+ 		int3472->clock.ena_gpio = gpio;
++		/* Ensure the pin is in output mode and non-active state */
++		gpiod_direction_output(int3472->clock.ena_gpio, 0);
+ 		break;
+ 	case INT3472_GPIO_TYPE_PRIVACY_LED:
+ 		gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
+@@ -175,6 +177,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
+ 			return (PTR_ERR(gpio));
+ 
+ 		int3472->clock.led_gpio = gpio;
++		/* Ensure the pin is in output mode and non-active state */
++		gpiod_direction_output(int3472->clock.led_gpio, 0);
+ 		break;
+ 	default:
+ 		dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
+diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
+index 765fcaba4d121..5ff5aaf92b56e 100644
+--- a/drivers/platform/x86/sony-laptop.c
++++ b/drivers/platform/x86/sony-laptop.c
+@@ -1888,14 +1888,21 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
+ 		break;
+ 	}
+ 
+-	ret = sony_call_snc_handle(handle, probe_base, &result);
+-	if (ret)
+-		return ret;
++	/*
++	 * Only probe if there is a separate probe_base, otherwise the probe call
++	 * is equivalent to __sony_nc_kbd_backlight_mode_set(0), resulting in
++	 * the keyboard backlight being turned off.
++	 */
++	if (probe_base) {
++		ret = sony_call_snc_handle(handle, probe_base, &result);
++		if (ret)
++			return ret;
+ 
+-	if ((handle == 0x0137 && !(result & 0x02)) ||
+-			!(result & 0x01)) {
+-		dprintk("no backlight keyboard found\n");
+-		return 0;
++		if ((handle == 0x0137 && !(result & 0x02)) ||
++				!(result & 0x01)) {
++			dprintk("no backlight keyboard found\n");
++			return 0;
++		}
+ 	}
+ 
+ 	kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
+diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
+index a1d91736a03b8..4e95d2243161a 100644
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -10315,9 +10315,11 @@ static DEFINE_MUTEX(dytc_mutex);
+ static int dytc_capabilities;
+ static bool dytc_mmc_get_available;
+ 
+-static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
++static int convert_dytc_to_profile(int funcmode, int dytcmode,
++		enum platform_profile_option *profile)
+ {
+-	if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
++	switch (funcmode) {
++	case DYTC_FUNCTION_MMC:
+ 		switch (dytcmode) {
+ 		case DYTC_MODE_MMC_LOWPOWER:
+ 			*profile = PLATFORM_PROFILE_LOW_POWER;
+@@ -10333,8 +10335,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
+ 			return -EINVAL;
+ 		}
+ 		return 0;
+-	}
+-	if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
++	case DYTC_FUNCTION_PSC:
+ 		switch (dytcmode) {
+ 		case DYTC_MODE_PSC_LOWPOWER:
+ 			*profile = PLATFORM_PROFILE_LOW_POWER;
+@@ -10348,6 +10349,14 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
+ 		default: /* Unknown mode */
+ 			return -EINVAL;
+ 		}
++		return 0;
++	case DYTC_FUNCTION_AMT:
++		/* For now return balanced. It's the closest we have to 'auto' */
++		*profile =  PLATFORM_PROFILE_BALANCED;
++		return 0;
++	default:
++		/* Unknown function */
++		return -EOPNOTSUPP;
+ 	}
+ 	return 0;
+ }
+@@ -10496,6 +10505,7 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
+ 		err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
+ 		if (err)
+ 			goto unlock;
++
+ 		/* system supports AMT, activate it when on balanced */
+ 		if (dytc_capabilities & BIT(DYTC_FC_AMT))
+ 			dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED);
+@@ -10511,7 +10521,7 @@ static void dytc_profile_refresh(void)
+ {
+ 	enum platform_profile_option profile;
+ 	int output, err = 0;
+-	int perfmode;
++	int perfmode, funcmode;
+ 
+ 	mutex_lock(&dytc_mutex);
+ 	if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
+@@ -10526,8 +10536,9 @@ static void dytc_profile_refresh(void)
+ 	if (err)
+ 		return;
+ 
++	funcmode = (output >> DYTC_GET_FUNCTION_BIT) & 0xF;
+ 	perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
+-	convert_dytc_to_profile(perfmode, &profile);
++	convert_dytc_to_profile(funcmode, perfmode, &profile);
+ 	if (profile != dytc_current_profile) {
+ 		dytc_current_profile = profile;
+ 		platform_profile_notify();
+diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
+index e01b32d1fa17d..00828f5baa972 100644
+--- a/drivers/regulator/da9211-regulator.c
++++ b/drivers/regulator/da9211-regulator.c
+@@ -498,6 +498,12 @@ static int da9211_i2c_probe(struct i2c_client *i2c)
+ 
+ 	chip->chip_irq = i2c->irq;
+ 
++	ret = da9211_regulator_init(chip);
++	if (ret < 0) {
++		dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret);
++		return ret;
++	}
++
+ 	if (chip->chip_irq != 0) {
+ 		ret = devm_request_threaded_irq(chip->dev, chip->chip_irq, NULL,
+ 					da9211_irq_handler,
+@@ -512,11 +518,6 @@ static int da9211_i2c_probe(struct i2c_client *i2c)
+ 		dev_warn(chip->dev, "No IRQ configured\n");
+ 	}
+ 
+-	ret = da9211_regulator_init(chip);
+-
+-	if (ret < 0)
+-		dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret);
+-
+ 	return ret;
+ }
+ 
+diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
+index b392b9f5482e0..c0f85ffb2b62d 100644
+--- a/drivers/s390/block/dcssblk.c
++++ b/drivers/s390/block/dcssblk.c
+@@ -865,6 +865,8 @@ dcssblk_submit_bio(struct bio *bio)
+ 	unsigned long bytes_done;
+ 
+ 	bio = bio_split_to_limits(bio);
++	if (!bio)
++		return;
+ 
+ 	bytes_done = 0;
+ 	dev_info = bio->bi_bdev->bd_disk->private_data;
+diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
+index ef86ca46646b8..3bf8cf34e1c3f 100644
+--- a/drivers/scsi/mpi3mr/Makefile
++++ b/drivers/scsi/mpi3mr/Makefile
+@@ -1,5 +1,5 @@
+ # mpi3mr makefile
+-obj-m += mpi3mr.o
++obj-$(CONFIG_SCSI_MPI3MR) += mpi3mr.o
+ mpi3mr-y +=  mpi3mr_os.o     \
+ 		mpi3mr_fw.o \
+ 		mpi3mr_app.o \
+diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
+index 3c5b7e4227b25..55d6fb4526804 100644
+--- a/drivers/scsi/storvsc_drv.c
++++ b/drivers/scsi/storvsc_drv.c
+@@ -1823,6 +1823,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 	ret = storvsc_do_io(dev, cmd_request, get_cpu());
+ 	put_cpu();
+ 
++	if (ret)
++		scsi_dma_unmap(scmnd);
++
+ 	if (ret == -EAGAIN) {
+ 		/* no more space */
+ 		ret = SCSI_MLQUEUE_DEVICE_BUSY;
+diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
+index 7c23112dc923f..37809c6c027fc 100644
+--- a/drivers/tty/hvc/hvc_xen.c
++++ b/drivers/tty/hvc/hvc_xen.c
+@@ -52,17 +52,22 @@ static DEFINE_SPINLOCK(xencons_lock);
+ 
+ static struct xencons_info *vtermno_to_xencons(int vtermno)
+ {
+-	struct xencons_info *entry, *n, *ret = NULL;
++	struct xencons_info *entry, *ret = NULL;
++	unsigned long flags;
+ 
+-	if (list_empty(&xenconsoles))
+-			return NULL;
++	spin_lock_irqsave(&xencons_lock, flags);
++	if (list_empty(&xenconsoles)) {
++		spin_unlock_irqrestore(&xencons_lock, flags);
++		return NULL;
++	}
+ 
+-	list_for_each_entry_safe(entry, n, &xenconsoles, list) {
++	list_for_each_entry(entry, &xenconsoles, list) {
+ 		if (entry->vtermno == vtermno) {
+ 			ret  = entry;
+ 			break;
+ 		}
+ 	}
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 
+ 	return ret;
+ }
+@@ -223,7 +228,7 @@ static int xen_hvm_console_init(void)
+ {
+ 	int r;
+ 	uint64_t v = 0;
+-	unsigned long gfn;
++	unsigned long gfn, flags;
+ 	struct xencons_info *info;
+ 
+ 	if (!xen_hvm_domain())
+@@ -258,9 +263,9 @@ static int xen_hvm_console_init(void)
+ 		goto err;
+ 	info->vtermno = HVC_COOKIE;
+ 
+-	spin_lock(&xencons_lock);
++	spin_lock_irqsave(&xencons_lock, flags);
+ 	list_add_tail(&info->list, &xenconsoles);
+-	spin_unlock(&xencons_lock);
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 
+ 	return 0;
+ err:
+@@ -283,6 +288,7 @@ static int xencons_info_pv_init(struct xencons_info *info, int vtermno)
+ static int xen_pv_console_init(void)
+ {
+ 	struct xencons_info *info;
++	unsigned long flags;
+ 
+ 	if (!xen_pv_domain())
+ 		return -ENODEV;
+@@ -299,9 +305,9 @@ static int xen_pv_console_init(void)
+ 		/* already configured */
+ 		return 0;
+ 	}
+-	spin_lock(&xencons_lock);
++	spin_lock_irqsave(&xencons_lock, flags);
+ 	xencons_info_pv_init(info, HVC_COOKIE);
+-	spin_unlock(&xencons_lock);
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 
+ 	return 0;
+ }
+@@ -309,6 +315,7 @@ static int xen_pv_console_init(void)
+ static int xen_initial_domain_console_init(void)
+ {
+ 	struct xencons_info *info;
++	unsigned long flags;
+ 
+ 	if (!xen_initial_domain())
+ 		return -ENODEV;
+@@ -323,9 +330,9 @@ static int xen_initial_domain_console_init(void)
+ 	info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
+ 	info->vtermno = HVC_COOKIE;
+ 
+-	spin_lock(&xencons_lock);
++	spin_lock_irqsave(&xencons_lock, flags);
+ 	list_add_tail(&info->list, &xenconsoles);
+-	spin_unlock(&xencons_lock);
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 
+ 	return 0;
+ }
+@@ -380,10 +387,12 @@ static void xencons_free(struct xencons_info *info)
+ 
+ static int xen_console_remove(struct xencons_info *info)
+ {
++	unsigned long flags;
++
+ 	xencons_disconnect_backend(info);
+-	spin_lock(&xencons_lock);
++	spin_lock_irqsave(&xencons_lock, flags);
+ 	list_del(&info->list);
+-	spin_unlock(&xencons_lock);
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 	if (info->xbdev != NULL)
+ 		xencons_free(info);
+ 	else {
+@@ -464,6 +473,7 @@ static int xencons_probe(struct xenbus_device *dev,
+ {
+ 	int ret, devid;
+ 	struct xencons_info *info;
++	unsigned long flags;
+ 
+ 	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
+ 	if (devid == 0)
+@@ -482,9 +492,9 @@ static int xencons_probe(struct xenbus_device *dev,
+ 	ret = xencons_connect_backend(dev, info);
+ 	if (ret < 0)
+ 		goto error;
+-	spin_lock(&xencons_lock);
++	spin_lock_irqsave(&xencons_lock, flags);
+ 	list_add_tail(&info->list, &xenconsoles);
+-	spin_unlock(&xencons_lock);
++	spin_unlock_irqrestore(&xencons_lock, flags);
+ 
+ 	return 0;
+ 
+@@ -584,10 +594,12 @@ static int __init xen_hvc_init(void)
+ 
+ 	info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
+ 	if (IS_ERR(info->hvc)) {
++		unsigned long flags;
++
+ 		r = PTR_ERR(info->hvc);
+-		spin_lock(&xencons_lock);
++		spin_lock_irqsave(&xencons_lock, flags);
+ 		list_del(&info->list);
+-		spin_unlock(&xencons_lock);
++		spin_unlock_irqrestore(&xencons_lock, flags);
+ 		if (info->irq)
+ 			unbind_from_irqhandler(info->irq, NULL);
+ 		kfree(info);
+diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
+index d1db6be801560..b048357d21e36 100644
+--- a/drivers/ufs/core/ufshcd.c
++++ b/drivers/ufs/core/ufshcd.c
+@@ -6094,6 +6094,14 @@ void ufshcd_schedule_eh_work(struct ufs_hba *hba)
+ 	}
+ }
+ 
++static void ufshcd_force_error_recovery(struct ufs_hba *hba)
++{
++	spin_lock_irq(hba->host->host_lock);
++	hba->force_reset = true;
++	ufshcd_schedule_eh_work(hba);
++	spin_unlock_irq(hba->host->host_lock);
++}
++
+ static void ufshcd_clk_scaling_allow(struct ufs_hba *hba, bool allow)
+ {
+ 	down_write(&hba->clk_scaling_lock);
+@@ -9066,6 +9074,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+ 
+ 		if (!hba->dev_info.b_rpm_dev_flush_capable) {
+ 			ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
++			if (ret && pm_op != UFS_SHUTDOWN_PM) {
++				/*
++				 * If return err in suspend flow, IO will hang.
++				 * Trigger error handler and break suspend for
++				 * error recovery.
++				 */
++				ufshcd_force_error_recovery(hba);
++				ret = -EBUSY;
++			}
+ 			if (ret)
+ 				goto enable_scaling;
+ 		}
+@@ -9077,6 +9094,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+ 	 */
+ 	check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba);
+ 	ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops);
++	if (ret && pm_op != UFS_SHUTDOWN_PM) {
++		/*
++		 * If return err in suspend flow, IO will hang.
++		 * Trigger error handler and break suspend for
++		 * error recovery.
++		 */
++		ufshcd_force_error_recovery(hba);
++		ret = -EBUSY;
++	}
+ 	if (ret)
+ 		goto set_dev_active;
+ 
+diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
+index 6a11025e58502..444302afc673a 100644
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -2209,7 +2209,7 @@ static int elf_core_dump(struct coredump_params *cprm)
+ 	 * The number of segs are recored into ELF header as 16bit value.
+ 	 * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
+ 	 */
+-	segs = cprm->vma_count + elf_core_extra_phdrs();
++	segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
+ 
+ 	/* for notes section */
+ 	segs++;
+@@ -2249,7 +2249,7 @@ static int elf_core_dump(struct coredump_params *cprm)
+ 	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+ 
+ 	offset += cprm->vma_data_size;
+-	offset += elf_core_extra_data_size();
++	offset += elf_core_extra_data_size(cprm);
+ 	e_shoff = offset;
+ 
+ 	if (e_phnum == PN_XNUM) {
+diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
+index 9ce5e1f41c26f..069f12cc7634c 100644
+--- a/fs/binfmt_elf_fdpic.c
++++ b/fs/binfmt_elf_fdpic.c
+@@ -1509,7 +1509,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
+ 	tmp->next = thread_list;
+ 	thread_list = tmp;
+ 
+-	segs = cprm->vma_count + elf_core_extra_phdrs();
++	segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
+ 
+ 	/* for notes section */
+ 	segs++;
+@@ -1555,7 +1555,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
+ 	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+ 
+ 	offset += cprm->vma_data_size;
+-	offset += elf_core_extra_data_size();
++	offset += elf_core_extra_data_size(cprm);
+ 	e_shoff = offset;
+ 
+ 	if (e_phnum == PN_XNUM) {
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 7e7f712f97fd8..fde1c371605a1 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2609,11 +2609,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
+ 	INIT_LIST_HEAD(&tcon->pending_opens);
+ 	tcon->status = TID_GOOD;
+ 
+-	/* schedule query interfaces poll */
+ 	INIT_DELAYED_WORK(&tcon->query_interfaces,
+ 			  smb2_query_server_interfaces);
+-	queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
+-			   (SMB_INTERFACE_POLL_INTERVAL * HZ));
++	if (ses->server->dialect >= SMB30_PROT_ID &&
++	    (ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
++		/* schedule query interfaces poll */
++		queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
++				   (SMB_INTERFACE_POLL_INTERVAL * HZ));
++	}
+ 
+ 	spin_lock(&cifs_tcp_ses_lock);
+ 	list_add(&tcon->tcon_list, &ses->tcon_list);
+diff --git a/fs/cifs/link.c b/fs/cifs/link.c
+index bd374feeccaa1..a5a097a699837 100644
+--- a/fs/cifs/link.c
++++ b/fs/cifs/link.c
+@@ -428,6 +428,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+ 	oparms.disposition = FILE_CREATE;
+ 	oparms.fid = &fid;
+ 	oparms.reconnect = false;
++	oparms.mode = 0644;
+ 
+ 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
+ 		       NULL, NULL);
+diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
+index 50480751e521c..4cb364454e130 100644
+--- a/fs/cifs/smb1ops.c
++++ b/fs/cifs/smb1ops.c
+@@ -562,17 +562,20 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
+ 	if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+ 		rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
+ 					 cifs_remap(cifs_sb));
+-		if (!rc)
+-			move_cifs_info_to_smb2(&data->fi, &fi);
+ 		*adjustTZ = true;
+ 	}
+ 
+-	if (!rc && (le32_to_cpu(fi.Attributes) & ATTR_REPARSE)) {
++	if (!rc) {
+ 		int tmprc;
+ 		int oplock = 0;
+ 		struct cifs_fid fid;
+ 		struct cifs_open_parms oparms;
+ 
++		move_cifs_info_to_smb2(&data->fi, &fi);
++
++		if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE))
++			return 0;
++
+ 		oparms.tcon = tcon;
+ 		oparms.cifs_sb = cifs_sb;
+ 		oparms.desired_access = FILE_READ_ATTRIBUTES;
+@@ -716,17 +719,25 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
+ static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
+ 			  void *buf)
+ {
+-	FILE_ALL_INFO *fi = buf;
++	struct cifs_open_info_data *data = buf;
++	FILE_ALL_INFO fi = {};
++	int rc;
+ 
+ 	if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
+-		return SMBLegacyOpen(xid, oparms->tcon, oparms->path,
+-				     oparms->disposition,
+-				     oparms->desired_access,
+-				     oparms->create_options,
+-				     &oparms->fid->netfid, oplock, fi,
+-				     oparms->cifs_sb->local_nls,
+-				     cifs_remap(oparms->cifs_sb));
+-	return CIFS_open(xid, oparms, oplock, fi);
++		rc = SMBLegacyOpen(xid, oparms->tcon, oparms->path,
++				   oparms->disposition,
++				   oparms->desired_access,
++				   oparms->create_options,
++				   &oparms->fid->netfid, oplock, &fi,
++				   oparms->cifs_sb->local_nls,
++				   cifs_remap(oparms->cifs_sb));
++	else
++		rc = CIFS_open(xid, oparms, oplock, &fi);
++
++	if (!rc && data)
++		move_cifs_info_to_smb2(&data->fi, &fi);
++
++	return rc;
+ }
+ 
+ static void
+@@ -1050,7 +1061,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
+ 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ 	struct inode *newinode = NULL;
+ 	int rc = -EPERM;
+-	FILE_ALL_INFO *buf = NULL;
++	struct cifs_open_info_data buf = {};
+ 	struct cifs_io_parms io_parms;
+ 	__u32 oplock = 0;
+ 	struct cifs_fid fid;
+@@ -1082,14 +1093,14 @@ cifs_make_node(unsigned int xid, struct inode *inode,
+ 					    cifs_sb->local_nls,
+ 					    cifs_remap(cifs_sb));
+ 		if (rc)
+-			goto out;
++			return rc;
+ 
+ 		rc = cifs_get_inode_info_unix(&newinode, full_path,
+ 					      inode->i_sb, xid);
+ 
+ 		if (rc == 0)
+ 			d_instantiate(dentry, newinode);
+-		goto out;
++		return rc;
+ 	}
+ 
+ 	/*
+@@ -1097,19 +1108,13 @@ cifs_make_node(unsigned int xid, struct inode *inode,
+ 	 * support block and char device (no socket & fifo)
+ 	 */
+ 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
+-		goto out;
++		return rc;
+ 
+ 	if (!S_ISCHR(mode) && !S_ISBLK(mode))
+-		goto out;
++		return rc;
+ 
+ 	cifs_dbg(FYI, "sfu compat create special file\n");
+ 
+-	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+-	if (buf == NULL) {
+-		rc = -ENOMEM;
+-		goto out;
+-	}
+-
+ 	oparms.tcon = tcon;
+ 	oparms.cifs_sb = cifs_sb;
+ 	oparms.desired_access = GENERIC_WRITE;
+@@ -1124,21 +1129,21 @@ cifs_make_node(unsigned int xid, struct inode *inode,
+ 		oplock = REQ_OPLOCK;
+ 	else
+ 		oplock = 0;
+-	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
++	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf);
+ 	if (rc)
+-		goto out;
++		return rc;
+ 
+ 	/*
+ 	 * BB Do not bother to decode buf since no local inode yet to put
+ 	 * timestamps in, but we can reuse it safely.
+ 	 */
+ 
+-	pdev = (struct win_dev *)buf;
++	pdev = (struct win_dev *)&buf.fi;
+ 	io_parms.pid = current->tgid;
+ 	io_parms.tcon = tcon;
+ 	io_parms.offset = 0;
+ 	io_parms.length = sizeof(struct win_dev);
+-	iov[1].iov_base = buf;
++	iov[1].iov_base = &buf.fi;
+ 	iov[1].iov_len = sizeof(struct win_dev);
+ 	if (S_ISCHR(mode)) {
+ 		memcpy(pdev->type, "IntxCHR", 8);
+@@ -1157,8 +1162,8 @@ cifs_make_node(unsigned int xid, struct inode *inode,
+ 	d_drop(dentry);
+ 
+ 	/* FIXME: add code here to set EAs */
+-out:
+-	kfree(buf);
++
++	cifs_free_open_info(&buf);
+ 	return rc;
+ }
+ 
+diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
+index a5695748a89b1..4ac5b1bfaf781 100644
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -1479,8 +1479,11 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+ out_put_spnego_key:
+ 	key_invalidate(spnego_key);
+ 	key_put(spnego_key);
+-	if (rc)
++	if (rc) {
+ 		kfree_sensitive(ses->auth_key.response);
++		ses->auth_key.response = NULL;
++		ses->auth_key.len = 0;
++	}
+ out:
+ 	sess_data->result = rc;
+ 	sess_data->func = NULL;
+diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
+index ec3fceb92236e..ea6fb0e6b1655 100644
+--- a/fs/nfsd/filecache.c
++++ b/fs/nfsd/filecache.c
+@@ -33,7 +33,6 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
+ static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
+ static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
+ static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
+-static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed);
+ static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
+ 
+ struct nfsd_fcache_disposal {
+@@ -63,6 +62,7 @@ struct nfsd_file_lookup_key {
+ 	struct net			*net;
+ 	const struct cred		*cred;
+ 	unsigned char			need;
++	bool				gc;
+ 	enum nfsd_file_lookup_type	type;
+ };
+ 
+@@ -162,6 +162,8 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
+ 			return 1;
+ 		if (!nfsd_match_cred(nf->nf_cred, key->cred))
+ 			return 1;
++		if (!!test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc)
++			return 1;
+ 		if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
+ 			return 1;
+ 		break;
+@@ -297,56 +299,28 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)
+ 		nf->nf_flags = 0;
+ 		__set_bit(NFSD_FILE_HASHED, &nf->nf_flags);
+ 		__set_bit(NFSD_FILE_PENDING, &nf->nf_flags);
++		if (key->gc)
++			__set_bit(NFSD_FILE_GC, &nf->nf_flags);
+ 		nf->nf_inode = key->inode;
+-		/* nf_ref is pre-incremented for hash table */
+-		refcount_set(&nf->nf_ref, 2);
++		refcount_set(&nf->nf_ref, 1);
+ 		nf->nf_may = key->need;
+ 		nf->nf_mark = NULL;
+ 	}
+ 	return nf;
+ }
+ 
+-static bool
+-nfsd_file_free(struct nfsd_file *nf)
+-{
+-	s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
+-	bool flush = false;
+-
+-	this_cpu_inc(nfsd_file_releases);
+-	this_cpu_add(nfsd_file_total_age, age);
+-
+-	trace_nfsd_file_put_final(nf);
+-	if (nf->nf_mark)
+-		nfsd_file_mark_put(nf->nf_mark);
+-	if (nf->nf_file) {
+-		get_file(nf->nf_file);
+-		filp_close(nf->nf_file, NULL);
+-		fput(nf->nf_file);
+-		flush = true;
+-	}
+-
+-	/*
+-	 * If this item is still linked via nf_lru, that's a bug.
+-	 * WARN and leak it to preserve system stability.
+-	 */
+-	if (WARN_ON_ONCE(!list_empty(&nf->nf_lru)))
+-		return flush;
+-
+-	call_rcu(&nf->nf_rcu, nfsd_file_slab_free);
+-	return flush;
+-}
+-
+-static bool
+-nfsd_file_check_writeback(struct nfsd_file *nf)
++static void
++nfsd_file_fsync(struct nfsd_file *nf)
+ {
+ 	struct file *file = nf->nf_file;
+-	struct address_space *mapping;
++	int ret;
+ 
+ 	if (!file || !(file->f_mode & FMODE_WRITE))
+-		return false;
+-	mapping = file->f_mapping;
+-	return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||
+-		mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
++		return;
++	ret = vfs_fsync(file, 1);
++	trace_nfsd_file_fsync(nf, ret);
++	if (ret)
++		nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
+ }
+ 
+ static int
+@@ -359,31 +333,6 @@ nfsd_file_check_write_error(struct nfsd_file *nf)
+ 	return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err));
+ }
+ 
+-static void
+-nfsd_file_flush(struct nfsd_file *nf)
+-{
+-	struct file *file = nf->nf_file;
+-
+-	if (!file || !(file->f_mode & FMODE_WRITE))
+-		return;
+-	this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages);
+-	if (vfs_fsync(file, 1) != 0)
+-		nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
+-}
+-
+-static void nfsd_file_lru_add(struct nfsd_file *nf)
+-{
+-	set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
+-	if (list_lru_add(&nfsd_file_lru, &nf->nf_lru))
+-		trace_nfsd_file_lru_add(nf);
+-}
+-
+-static void nfsd_file_lru_remove(struct nfsd_file *nf)
+-{
+-	if (list_lru_del(&nfsd_file_lru, &nf->nf_lru))
+-		trace_nfsd_file_lru_del(nf);
+-}
+-
+ static void
+ nfsd_file_hash_remove(struct nfsd_file *nf)
+ {
+@@ -406,60 +355,76 @@ nfsd_file_unhash(struct nfsd_file *nf)
+ }
+ 
+ static void
+-nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
++nfsd_file_free(struct nfsd_file *nf)
+ {
+-	trace_nfsd_file_unhash_and_dispose(nf);
+-	if (nfsd_file_unhash(nf)) {
+-		/* caller must call nfsd_file_dispose_list() later */
+-		nfsd_file_lru_remove(nf);
+-		list_add(&nf->nf_lru, dispose);
++	s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
++
++	trace_nfsd_file_free(nf);
++
++	this_cpu_inc(nfsd_file_releases);
++	this_cpu_add(nfsd_file_total_age, age);
++
++	nfsd_file_unhash(nf);
++
++	/*
++	 * We call fsync here in order to catch writeback errors. It's not
++	 * strictly required by the protocol, but an nfsd_file could get
++	 * evicted from the cache before a COMMIT comes in. If another
++	 * task were to open that file in the interim and scrape the error,
++	 * then the client may never see it. By calling fsync here, we ensure
++	 * that writeback happens before the entry is freed, and that any
++	 * errors reported result in the write verifier changing.
++	 */
++	nfsd_file_fsync(nf);
++
++	if (nf->nf_mark)
++		nfsd_file_mark_put(nf->nf_mark);
++	if (nf->nf_file) {
++		get_file(nf->nf_file);
++		filp_close(nf->nf_file, NULL);
++		fput(nf->nf_file);
+ 	}
++
++	/*
++	 * If this item is still linked via nf_lru, that's a bug.
++	 * WARN and leak it to preserve system stability.
++	 */
++	if (WARN_ON_ONCE(!list_empty(&nf->nf_lru)))
++		return;
++
++	call_rcu(&nf->nf_rcu, nfsd_file_slab_free);
+ }
+ 
+-static void
+-nfsd_file_put_noref(struct nfsd_file *nf)
++static bool
++nfsd_file_check_writeback(struct nfsd_file *nf)
+ {
+-	trace_nfsd_file_put(nf);
++	struct file *file = nf->nf_file;
++	struct address_space *mapping;
+ 
+-	if (refcount_dec_and_test(&nf->nf_ref)) {
+-		WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags));
+-		nfsd_file_lru_remove(nf);
+-		nfsd_file_free(nf);
+-	}
++	if (!file || !(file->f_mode & FMODE_WRITE))
++		return false;
++	mapping = file->f_mapping;
++	return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||
++		mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
+ }
+ 
+-void
+-nfsd_file_put(struct nfsd_file *nf)
++static bool nfsd_file_lru_add(struct nfsd_file *nf)
+ {
+-	might_sleep();
+-
+-	nfsd_file_lru_add(nf);
+-	if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) {
+-		nfsd_file_flush(nf);
+-		nfsd_file_put_noref(nf);
+-	} else if (nf->nf_file) {
+-		nfsd_file_put_noref(nf);
+-		nfsd_file_schedule_laundrette();
+-	} else
+-		nfsd_file_put_noref(nf);
++	set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
++	if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) {
++		trace_nfsd_file_lru_add(nf);
++		return true;
++	}
++	return false;
+ }
+ 
+-/**
+- * nfsd_file_close - Close an nfsd_file
+- * @nf: nfsd_file to close
+- *
+- * If this is the final reference for @nf, free it immediately.
+- * This reflects an on-the-wire CLOSE or DELEGRETURN into the
+- * VFS and exported filesystem.
+- */
+-void nfsd_file_close(struct nfsd_file *nf)
++static bool nfsd_file_lru_remove(struct nfsd_file *nf)
+ {
+-	nfsd_file_put(nf);
+-	if (refcount_dec_if_one(&nf->nf_ref)) {
+-		nfsd_file_unhash(nf);
+-		nfsd_file_lru_remove(nf);
+-		nfsd_file_free(nf);
++	if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) {
++		trace_nfsd_file_lru_del(nf);
++		return true;
+ 	}
++	return false;
+ }
+ 
+ struct nfsd_file *
+@@ -470,36 +435,60 @@ nfsd_file_get(struct nfsd_file *nf)
+ 	return NULL;
+ }
+ 
+-static void
+-nfsd_file_dispose_list(struct list_head *dispose)
++/**
++ * nfsd_file_put - put the reference to a nfsd_file
++ * @nf: nfsd_file of which to put the reference
++ *
++ * Put a reference to a nfsd_file. In the non-GC case, we just put the
++ * reference immediately. In the GC case, if the reference would be
++ * the last one, the put it on the LRU instead to be cleaned up later.
++ */
++void
++nfsd_file_put(struct nfsd_file *nf)
+ {
+-	struct nfsd_file *nf;
++	might_sleep();
++	trace_nfsd_file_put(nf);
+ 
+-	while(!list_empty(dispose)) {
+-		nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
+-		list_del_init(&nf->nf_lru);
+-		nfsd_file_flush(nf);
+-		nfsd_file_put_noref(nf);
++	if (test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
++	    test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
++		/*
++		 * If this is the last reference (nf_ref == 1), then try to
++		 * transfer it to the LRU.
++		 */
++		if (refcount_dec_not_one(&nf->nf_ref))
++			return;
++
++		/* Try to add it to the LRU.  If that fails, decrement. */
++		if (nfsd_file_lru_add(nf)) {
++			/* If it's still hashed, we're done */
++			if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
++				nfsd_file_schedule_laundrette();
++				return;
++			}
++
++			/*
++			 * We're racing with unhashing, so try to remove it from
++			 * the LRU. If removal fails, then someone else already
++			 * has our reference.
++			 */
++			if (!nfsd_file_lru_remove(nf))
++				return;
++		}
+ 	}
++	if (refcount_dec_and_test(&nf->nf_ref))
++		nfsd_file_free(nf);
+ }
+ 
+ static void
+-nfsd_file_dispose_list_sync(struct list_head *dispose)
++nfsd_file_dispose_list(struct list_head *dispose)
+ {
+-	bool flush = false;
+ 	struct nfsd_file *nf;
+ 
+-	while(!list_empty(dispose)) {
++	while (!list_empty(dispose)) {
+ 		nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
+ 		list_del_init(&nf->nf_lru);
+-		nfsd_file_flush(nf);
+-		if (!refcount_dec_and_test(&nf->nf_ref))
+-			continue;
+-		if (nfsd_file_free(nf))
+-			flush = true;
++		nfsd_file_free(nf);
+ 	}
+-	if (flush)
+-		flush_delayed_fput();
+ }
+ 
+ static void
+@@ -569,21 +558,8 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
+ 	struct list_head *head = arg;
+ 	struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru);
+ 
+-	/*
+-	 * Do a lockless refcount check. The hashtable holds one reference, so
+-	 * we look to see if anything else has a reference, or if any have
+-	 * been put since the shrinker last ran. Those don't get unhashed and
+-	 * released.
+-	 *
+-	 * Note that in the put path, we set the flag and then decrement the
+-	 * counter. Here we check the counter and then test and clear the flag.
+-	 * That order is deliberate to ensure that we can do this locklessly.
+-	 */
+-	if (refcount_read(&nf->nf_ref) > 1) {
+-		list_lru_isolate(lru, &nf->nf_lru);
+-		trace_nfsd_file_gc_in_use(nf);
+-		return LRU_REMOVED;
+-	}
++	/* We should only be dealing with GC entries here */
++	WARN_ON_ONCE(!test_bit(NFSD_FILE_GC, &nf->nf_flags));
+ 
+ 	/*
+ 	 * Don't throw out files that are still undergoing I/O or
+@@ -594,40 +570,30 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
+ 		return LRU_SKIP;
+ 	}
+ 
++	/* If it was recently added to the list, skip it */
+ 	if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) {
+ 		trace_nfsd_file_gc_referenced(nf);
+ 		return LRU_ROTATE;
+ 	}
+ 
+-	if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
+-		trace_nfsd_file_gc_hashed(nf);
+-		return LRU_SKIP;
++	/*
++	 * Put the reference held on behalf of the LRU. If it wasn't the last
++	 * one, then just remove it from the LRU and ignore it.
++	 */
++	if (!refcount_dec_and_test(&nf->nf_ref)) {
++		trace_nfsd_file_gc_in_use(nf);
++		list_lru_isolate(lru, &nf->nf_lru);
++		return LRU_REMOVED;
+ 	}
+ 
++	/* Refcount went to zero. Unhash it and queue it to the dispose list */
++	nfsd_file_unhash(nf);
+ 	list_lru_isolate_move(lru, &nf->nf_lru, head);
+ 	this_cpu_inc(nfsd_file_evictions);
+ 	trace_nfsd_file_gc_disposed(nf);
+ 	return LRU_REMOVED;
+ }
+ 
+-/*
+- * Unhash items on @dispose immediately, then queue them on the
+- * disposal workqueue to finish releasing them in the background.
+- *
+- * cel: Note that between the time list_lru_shrink_walk runs and
+- * now, these items are in the hash table but marked unhashed.
+- * Why release these outside of lru_cb ? There's no lock ordering
+- * problem since lru_cb currently takes no lock.
+- */
+-static void nfsd_file_gc_dispose_list(struct list_head *dispose)
+-{
+-	struct nfsd_file *nf;
+-
+-	list_for_each_entry(nf, dispose, nf_lru)
+-		nfsd_file_hash_remove(nf);
+-	nfsd_file_dispose_list_delayed(dispose);
+-}
+-
+ static void
+ nfsd_file_gc(void)
+ {
+@@ -637,7 +603,7 @@ nfsd_file_gc(void)
+ 	ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb,
+ 			    &dispose, list_lru_count(&nfsd_file_lru));
+ 	trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
+-	nfsd_file_gc_dispose_list(&dispose);
++	nfsd_file_dispose_list_delayed(&dispose);
+ }
+ 
+ static void
+@@ -662,7 +628,7 @@ nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
+ 	ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
+ 				   nfsd_file_lru_cb, &dispose);
+ 	trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
+-	nfsd_file_gc_dispose_list(&dispose);
++	nfsd_file_dispose_list_delayed(&dispose);
+ 	return ret;
+ }
+ 
+@@ -672,72 +638,111 @@ static struct shrinker	nfsd_file_shrinker = {
+ 	.seeks = 1,
+ };
+ 
+-/*
+- * Find all cache items across all net namespaces that match @inode and
+- * move them to @dispose. The lookup is atomic wrt nfsd_file_acquire().
++/**
++ * nfsd_file_queue_for_close: try to close out any open nfsd_files for an inode
++ * @inode:   inode on which to close out nfsd_files
++ * @dispose: list on which to gather nfsd_files to close out
++ *
++ * An nfsd_file represents a struct file being held open on behalf of nfsd. An
++ * open file however can block other activity (such as leases), or cause
++ * undesirable behavior (e.g. spurious silly-renames when reexporting NFS).
++ *
++ * This function is intended to find open nfsd_files when this sort of
++ * conflicting access occurs and then attempt to close those files out.
++ *
++ * Populates the dispose list with entries that have already had their
++ * refcounts go to zero. The actual free of an nfsd_file can be expensive,
++ * so we leave it up to the caller whether it wants to wait or not.
+  */
+-static unsigned int
+-__nfsd_file_close_inode(struct inode *inode, struct list_head *dispose)
++static void
++nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
+ {
+ 	struct nfsd_file_lookup_key key = {
+ 		.type	= NFSD_FILE_KEY_INODE,
+ 		.inode	= inode,
+ 	};
+-	unsigned int count = 0;
+ 	struct nfsd_file *nf;
+ 
+ 	rcu_read_lock();
+ 	do {
++		int decrement = 1;
++
+ 		nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
+ 				       nfsd_file_rhash_params);
+ 		if (!nf)
+ 			break;
+-		nfsd_file_unhash_and_dispose(nf, dispose);
+-		count++;
++
++		/* If we raced with someone else unhashing, ignore it */
++		if (!nfsd_file_unhash(nf))
++			continue;
++
++		/* If we can't get a reference, ignore it */
++		if (!nfsd_file_get(nf))
++			continue;
++
++		/* Extra decrement if we remove from the LRU */
++		if (nfsd_file_lru_remove(nf))
++			++decrement;
++
++		/* If refcount goes to 0, then put on the dispose list */
++		if (refcount_sub_and_test(decrement, &nf->nf_ref)) {
++			list_add(&nf->nf_lru, dispose);
++			trace_nfsd_file_closing(nf);
++		}
+ 	} while (1);
+ 	rcu_read_unlock();
+-	return count;
+ }
+ 
+ /**
+- * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file
++ * nfsd_file_close_inode - attempt a delayed close of a nfsd_file
+  * @inode: inode of the file to attempt to remove
+  *
+- * Unhash and put, then flush and fput all cache items associated with @inode.
++ * Close out any open nfsd_files that can be reaped for @inode. The
++ * actual freeing is deferred to the dispose_list_delayed infrastructure.
++ *
++ * This is used by the fsnotify callbacks and setlease notifier.
+  */
+-void
+-nfsd_file_close_inode_sync(struct inode *inode)
++static void
++nfsd_file_close_inode(struct inode *inode)
+ {
+ 	LIST_HEAD(dispose);
+-	unsigned int count;
+ 
+-	count = __nfsd_file_close_inode(inode, &dispose);
+-	trace_nfsd_file_close_inode_sync(inode, count);
+-	nfsd_file_dispose_list_sync(&dispose);
++	nfsd_file_queue_for_close(inode, &dispose);
++	nfsd_file_dispose_list_delayed(&dispose);
+ }
+ 
+ /**
+- * nfsd_file_close_inode - attempt a delayed close of a nfsd_file
++ * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file
+  * @inode: inode of the file to attempt to remove
+  *
+- * Unhash and put all cache item associated with @inode.
++ * Close out any open nfsd_files that can be reaped for @inode. The
++ * nfsd_files are closed out synchronously.
++ *
++ * This is called from nfsd_rename and nfsd_unlink to avoid silly-renames
++ * when reexporting NFS.
+  */
+-static void
+-nfsd_file_close_inode(struct inode *inode)
++void
++nfsd_file_close_inode_sync(struct inode *inode)
+ {
++	struct nfsd_file *nf;
+ 	LIST_HEAD(dispose);
+-	unsigned int count;
+ 
+-	count = __nfsd_file_close_inode(inode, &dispose);
+-	trace_nfsd_file_close_inode(inode, count);
+-	nfsd_file_dispose_list_delayed(&dispose);
++	trace_nfsd_file_close(inode);
++
++	nfsd_file_queue_for_close(inode, &dispose);
++	while (!list_empty(&dispose)) {
++		nf = list_first_entry(&dispose, struct nfsd_file, nf_lru);
++		list_del_init(&nf->nf_lru);
++		nfsd_file_free(nf);
++	}
++	flush_delayed_fput();
+ }
+ 
+ /**
+  * nfsd_file_delayed_close - close unused nfsd_files
+  * @work: dummy
+  *
+- * Walk the LRU list and close any entries that have not been used since
++ * Walk the LRU list and destroy any entries that have not been used since
+  * the last scan.
+  */
+ static void
+@@ -759,7 +764,7 @@ nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg,
+ 
+ 	/* Only close files for F_SETLEASE leases */
+ 	if (fl->fl_flags & FL_LEASE)
+-		nfsd_file_close_inode_sync(file_inode(fl->fl_file));
++		nfsd_file_close_inode(file_inode(fl->fl_file));
+ 	return 0;
+ }
+ 
+@@ -880,6 +885,13 @@ out_err:
+ 	goto out;
+ }
+ 
++/**
++ * __nfsd_file_cache_purge: clean out the cache for shutdown
++ * @net: net-namespace to shut down the cache (may be NULL)
++ *
++ * Walk the nfsd_file cache and close out any that match @net. If @net is NULL,
++ * then close out everything. Called when an nfsd instance is being shut down.
++ */
+ static void
+ __nfsd_file_cache_purge(struct net *net)
+ {
+@@ -893,8 +905,11 @@ __nfsd_file_cache_purge(struct net *net)
+ 
+ 		nf = rhashtable_walk_next(&iter);
+ 		while (!IS_ERR_OR_NULL(nf)) {
+-			if (!net || nf->nf_net == net)
+-				nfsd_file_unhash_and_dispose(nf, &dispose);
++			if (!net || nf->nf_net == net) {
++				nfsd_file_unhash(nf);
++				nfsd_file_lru_remove(nf);
++				list_add(&nf->nf_lru, &dispose);
++			}
+ 			nf = rhashtable_walk_next(&iter);
+ 		}
+ 
+@@ -1000,7 +1015,6 @@ nfsd_file_cache_shutdown(void)
+ 		per_cpu(nfsd_file_acquisitions, i) = 0;
+ 		per_cpu(nfsd_file_releases, i) = 0;
+ 		per_cpu(nfsd_file_total_age, i) = 0;
+-		per_cpu(nfsd_file_pages_flushed, i) = 0;
+ 		per_cpu(nfsd_file_evictions, i) = 0;
+ 	}
+ }
+@@ -1034,12 +1048,14 @@ nfsd_file_is_cached(struct inode *inode)
+ 
+ static __be32
+ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-		     unsigned int may_flags, struct nfsd_file **pnf, bool open)
++		     unsigned int may_flags, struct file *file,
++		     struct nfsd_file **pnf, bool want_gc)
+ {
+ 	struct nfsd_file_lookup_key key = {
+ 		.type	= NFSD_FILE_KEY_FULL,
+ 		.need	= may_flags & NFSD_FILE_MAY_MASK,
+ 		.net	= SVC_NET(rqstp),
++		.gc	= want_gc,
+ 	};
+ 	bool open_retry = true;
+ 	struct nfsd_file *nf;
+@@ -1060,8 +1076,12 @@ retry:
+ 	if (nf)
+ 		nf = nfsd_file_get(nf);
+ 	rcu_read_unlock();
+-	if (nf)
++
++	if (nf) {
++		if (nfsd_file_lru_remove(nf))
++			WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref));
+ 		goto wait_for_construction;
++	}
+ 
+ 	nf = nfsd_file_alloc(&key, may_flags);
+ 	if (!nf) {
+@@ -1094,55 +1114,81 @@ wait_for_construction:
+ 			goto out;
+ 		}
+ 		open_retry = false;
+-		nfsd_file_put_noref(nf);
++		if (refcount_dec_and_test(&nf->nf_ref))
++			nfsd_file_free(nf);
+ 		goto retry;
+ 	}
+ 
+-	nfsd_file_lru_remove(nf);
+ 	this_cpu_inc(nfsd_file_cache_hits);
+ 
+ 	status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
+ out:
+ 	if (status == nfs_ok) {
+-		if (open)
+-			this_cpu_inc(nfsd_file_acquisitions);
++		this_cpu_inc(nfsd_file_acquisitions);
+ 		*pnf = nf;
+ 	} else {
+-		nfsd_file_put(nf);
++		if (refcount_dec_and_test(&nf->nf_ref))
++			nfsd_file_free(nf);
+ 		nf = NULL;
+ 	}
+ 
+ out_status:
+ 	put_cred(key.cred);
+-	if (open)
+-		trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
++	trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
+ 	return status;
+ 
+ open_file:
+ 	trace_nfsd_file_alloc(nf);
+ 	nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);
+ 	if (nf->nf_mark) {
+-		if (open) {
++		if (file) {
++			get_file(file);
++			nf->nf_file = file;
++			status = nfs_ok;
++			trace_nfsd_file_opened(nf, status);
++		} else {
+ 			status = nfsd_open_verified(rqstp, fhp, may_flags,
+ 						    &nf->nf_file);
+ 			trace_nfsd_file_open(nf, status);
+-		} else
+-			status = nfs_ok;
++		}
+ 	} else
+ 		status = nfserr_jukebox;
+ 	/*
+ 	 * If construction failed, or we raced with a call to unlink()
+ 	 * then unhash.
+ 	 */
+-	if (status != nfs_ok || key.inode->i_nlink == 0)
+-		if (nfsd_file_unhash(nf))
+-			nfsd_file_put_noref(nf);
++	if (status == nfs_ok && key.inode->i_nlink == 0)
++		status = nfserr_jukebox;
++	if (status != nfs_ok)
++		nfsd_file_unhash(nf);
+ 	clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags);
+ 	smp_mb__after_atomic();
+ 	wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);
+ 	goto out;
+ }
+ 
++/**
++ * nfsd_file_acquire_gc - Get a struct nfsd_file with an open file
++ * @rqstp: the RPC transaction being executed
++ * @fhp: the NFS filehandle of the file to be opened
++ * @may_flags: NFSD_MAY_ settings for the file
++ * @pnf: OUT: new or found "struct nfsd_file" object
++ *
++ * The nfsd_file object returned by this API is reference-counted
++ * and garbage-collected. The object is retained for a few
++ * seconds after the final nfsd_file_put() in case the caller
++ * wants to re-use it.
++ *
++ * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
++ * network byte order is returned.
++ */
++__be32
++nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
++		     unsigned int may_flags, struct nfsd_file **pnf)
++{
++	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
++}
++
+ /**
+  * nfsd_file_acquire - Get a struct nfsd_file with an open file
+  * @rqstp: the RPC transaction being executed
+@@ -1150,6 +1196,10 @@ open_file:
+  * @may_flags: NFSD_MAY_ settings for the file
+  * @pnf: OUT: new or found "struct nfsd_file" object
+  *
++ * The nfsd_file_object returned by this API is reference-counted
++ * but not garbage-collected. The object is unhashed after the
++ * final nfsd_file_put().
++ *
+  * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
+  * network byte order is returned.
+  */
+@@ -1157,24 +1207,30 @@ __be32
+ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 		  unsigned int may_flags, struct nfsd_file **pnf)
+ {
+-	return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true);
++	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
+ }
+ 
+ /**
+- * nfsd_file_create - Get a struct nfsd_file, do not open
++ * nfsd_file_acquire_opened - Get a struct nfsd_file using existing open file
+  * @rqstp: the RPC transaction being executed
+  * @fhp: the NFS filehandle of the file just created
+  * @may_flags: NFSD_MAY_ settings for the file
++ * @file: cached, already-open file (may be NULL)
+  * @pnf: OUT: new or found "struct nfsd_file" object
+  *
++ * Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist,
++ * and @file is non-NULL, use it to instantiate a new nfsd_file instead of
++ * opening a new one.
++ *
+  * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
+  * network byte order is returned.
+  */
+ __be32
+-nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-		 unsigned int may_flags, struct nfsd_file **pnf)
++nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
++			 unsigned int may_flags, struct file *file,
++			 struct nfsd_file **pnf)
+ {
+-	return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false);
++	return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
+ }
+ 
+ /*
+@@ -1184,7 +1240,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+  */
+ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
+ {
+-	unsigned long releases = 0, pages_flushed = 0, evictions = 0;
++	unsigned long releases = 0, evictions = 0;
+ 	unsigned long hits = 0, acquisitions = 0;
+ 	unsigned int i, count = 0, buckets = 0;
+ 	unsigned long lru = 0, total_age = 0;
+@@ -1212,7 +1268,6 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
+ 		releases += per_cpu(nfsd_file_releases, i);
+ 		total_age += per_cpu(nfsd_file_total_age, i);
+ 		evictions += per_cpu(nfsd_file_evictions, i);
+-		pages_flushed += per_cpu(nfsd_file_pages_flushed, i);
+ 	}
+ 
+ 	seq_printf(m, "total entries: %u\n", count);
+@@ -1226,6 +1281,5 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
+ 		seq_printf(m, "mean age (ms): %ld\n", total_age / releases);
+ 	else
+ 		seq_printf(m, "mean age (ms): -\n");
+-	seq_printf(m, "pages flushed: %lu\n", pages_flushed);
+ 	return 0;
+ }
+diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
+index 357832bac736b..41516a4263ea5 100644
+--- a/fs/nfsd/filecache.h
++++ b/fs/nfsd/filecache.h
+@@ -38,6 +38,7 @@ struct nfsd_file {
+ #define NFSD_FILE_HASHED	(0)
+ #define NFSD_FILE_PENDING	(1)
+ #define NFSD_FILE_REFERENCED	(2)
++#define NFSD_FILE_GC		(3)
+ 	unsigned long		nf_flags;
+ 	struct inode		*nf_inode;	/* don't deref */
+ 	refcount_t		nf_ref;
+@@ -52,13 +53,15 @@ void nfsd_file_cache_shutdown(void);
+ int nfsd_file_cache_start_net(struct net *net);
+ void nfsd_file_cache_shutdown_net(struct net *net);
+ void nfsd_file_put(struct nfsd_file *nf);
+-void nfsd_file_close(struct nfsd_file *nf);
+ struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
+ void nfsd_file_close_inode_sync(struct inode *inode);
+ bool nfsd_file_is_cached(struct inode *inode);
+-__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
++__be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 		  unsigned int may_flags, struct nfsd_file **nfp);
+-__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
++__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 		  unsigned int may_flags, struct nfsd_file **nfp);
++__be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
++		  unsigned int may_flags, struct file *file,
++		  struct nfsd_file **nfp);
+ int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
+ #endif /* _FS_NFSD_FILECACHE_H */
+diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
+index 923d9a80df92c..d01b29aba6623 100644
+--- a/fs/nfsd/nfs3proc.c
++++ b/fs/nfsd/nfs3proc.c
+@@ -13,6 +13,7 @@
+ #include "cache.h"
+ #include "xdr3.h"
+ #include "vfs.h"
++#include "filecache.h"
+ 
+ #define NFSDDBG_FACILITY		NFSDDBG_PROC
+ 
+@@ -763,6 +764,7 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
+ {
+ 	struct nfsd3_commitargs *argp = rqstp->rq_argp;
+ 	struct nfsd3_commitres *resp = rqstp->rq_resp;
++	struct nfsd_file *nf;
+ 
+ 	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
+ 				SVCFH_fmt(&argp->fh),
+@@ -770,8 +772,14 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
+ 				(unsigned long long) argp->offset);
+ 
+ 	fh_copy(&resp->fh, &argp->fh);
+-	resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
++	resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE |
++					    NFSD_MAY_NOT_BREAK_LEASE, &nf);
++	if (resp->status)
++		goto out;
++	resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset,
+ 				   argp->count, resp->verf);
++	nfsd_file_put(nf);
++out:
+ 	return rpc_success;
+ }
+ 
+diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
+index c7329523a10f1..30a08ec31a703 100644
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -731,10 +731,19 @@ nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 	     union nfsd4_op_u *u)
+ {
+ 	struct nfsd4_commit *commit = &u->commit;
++	struct nfsd_file *nf;
++	__be32 status;
+ 
+-	return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
++	status = nfsd_file_acquire(rqstp, &cstate->current_fh, NFSD_MAY_WRITE |
++				   NFSD_MAY_NOT_BREAK_LEASE, &nf);
++	if (status != nfs_ok)
++		return status;
++
++	status = nfsd_commit(rqstp, &cstate->current_fh, nf, commit->co_offset,
+ 			     commit->co_count,
+ 			     (__be32 *)commit->co_verf.data);
++	nfsd_file_put(nf);
++	return status;
+ }
+ 
+ static __be32
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 52b5552d0d70e..2247d107da90b 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -842,9 +842,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+ 			swap(f2, fp->fi_fds[O_RDWR]);
+ 		spin_unlock(&fp->fi_lock);
+ 		if (f1)
+-			nfsd_file_close(f1);
++			nfsd_file_put(f1);
+ 		if (f2)
+-			nfsd_file_close(f2);
++			nfsd_file_put(f2);
+ 	}
+ }
+ 
+@@ -5211,18 +5211,10 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
+ 	if (!fp->fi_fds[oflag]) {
+ 		spin_unlock(&fp->fi_lock);
+ 
+-		if (!open->op_filp) {
+-			status = nfsd_file_acquire(rqstp, cur_fh, access, &nf);
+-			if (status != nfs_ok)
+-				goto out_put_access;
+-		} else {
+-			status = nfsd_file_create(rqstp, cur_fh, access, &nf);
+-			if (status != nfs_ok)
+-				goto out_put_access;
+-			nf->nf_file = open->op_filp;
+-			open->op_filp = NULL;
+-			trace_nfsd_file_create(rqstp, access, nf);
+-		}
++		status = nfsd_file_acquire_opened(rqstp, cur_fh, access,
++						  open->op_filp, &nf);
++		if (status != nfs_ok)
++			goto out_put_access;
+ 
+ 		spin_lock(&fp->fi_lock);
+ 		if (!fp->fi_fds[oflag]) {
+diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
+index d4b6839bb459a..4eb4e1039c7f4 100644
+--- a/fs/nfsd/trace.h
++++ b/fs/nfsd/trace.h
+@@ -817,7 +817,8 @@ DEFINE_CLID_EVENT(confirmed_r);
+ 	__print_flags(val, "|",						\
+ 		{ 1 << NFSD_FILE_HASHED,	"HASHED" },		\
+ 		{ 1 << NFSD_FILE_PENDING,	"PENDING" },		\
+-		{ 1 << NFSD_FILE_REFERENCED,	"REFERENCED"})
++		{ 1 << NFSD_FILE_REFERENCED,	"REFERENCED" },		\
++		{ 1 << NFSD_FILE_GC,		"GC" })
+ 
+ DECLARE_EVENT_CLASS(nfsd_file_class,
+ 	TP_PROTO(struct nfsd_file *nf),
+@@ -849,10 +850,11 @@ DEFINE_EVENT(nfsd_file_class, name, \
+ 	TP_PROTO(struct nfsd_file *nf), \
+ 	TP_ARGS(nf))
+ 
+-DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final);
++DEFINE_NFSD_FILE_EVENT(nfsd_file_free);
+ DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash);
+ DEFINE_NFSD_FILE_EVENT(nfsd_file_put);
+-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose);
++DEFINE_NFSD_FILE_EVENT(nfsd_file_closing);
++DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_queue);
+ 
+ TRACE_EVENT(nfsd_file_alloc,
+ 	TP_PROTO(
+@@ -920,43 +922,6 @@ TRACE_EVENT(nfsd_file_acquire,
+ 	)
+ );
+ 
+-TRACE_EVENT(nfsd_file_create,
+-	TP_PROTO(
+-		const struct svc_rqst *rqstp,
+-		unsigned int may_flags,
+-		const struct nfsd_file *nf
+-	),
+-
+-	TP_ARGS(rqstp, may_flags, nf),
+-
+-	TP_STRUCT__entry(
+-		__field(const void *, nf_inode)
+-		__field(const void *, nf_file)
+-		__field(unsigned long, may_flags)
+-		__field(unsigned long, nf_flags)
+-		__field(unsigned long, nf_may)
+-		__field(unsigned int, nf_ref)
+-		__field(u32, xid)
+-	),
+-
+-	TP_fast_assign(
+-		__entry->nf_inode = nf->nf_inode;
+-		__entry->nf_file = nf->nf_file;
+-		__entry->may_flags = may_flags;
+-		__entry->nf_flags = nf->nf_flags;
+-		__entry->nf_may = nf->nf_may;
+-		__entry->nf_ref = refcount_read(&nf->nf_ref);
+-		__entry->xid = be32_to_cpu(rqstp->rq_xid);
+-	),
+-
+-	TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
+-		__entry->xid, __entry->nf_inode,
+-		show_nfsd_may_flags(__entry->may_flags),
+-		__entry->nf_ref, show_nf_flags(__entry->nf_flags),
+-		show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
+-	)
+-);
+-
+ TRACE_EVENT(nfsd_file_insert_err,
+ 	TP_PROTO(
+ 		const struct svc_rqst *rqstp,
+@@ -1018,8 +983,8 @@ TRACE_EVENT(nfsd_file_cons_err,
+ 	)
+ );
+ 
+-TRACE_EVENT(nfsd_file_open,
+-	TP_PROTO(struct nfsd_file *nf, __be32 status),
++DECLARE_EVENT_CLASS(nfsd_file_open_class,
++	TP_PROTO(const struct nfsd_file *nf, __be32 status),
+ 	TP_ARGS(nf, status),
+ 	TP_STRUCT__entry(
+ 		__field(void *, nf_inode)	/* cannot be dereferenced */
+@@ -1043,34 +1008,16 @@ TRACE_EVENT(nfsd_file_open,
+ 		__entry->nf_file)
+ )
+ 
+-DECLARE_EVENT_CLASS(nfsd_file_search_class,
+-	TP_PROTO(
+-		const struct inode *inode,
+-		unsigned int count
+-	),
+-	TP_ARGS(inode, count),
+-	TP_STRUCT__entry(
+-		__field(const struct inode *, inode)
+-		__field(unsigned int, count)
+-	),
+-	TP_fast_assign(
+-		__entry->inode = inode;
+-		__entry->count = count;
+-	),
+-	TP_printk("inode=%p count=%u",
+-		__entry->inode, __entry->count)
+-);
+-
+-#define DEFINE_NFSD_FILE_SEARCH_EVENT(name)				\
+-DEFINE_EVENT(nfsd_file_search_class, name,				\
++#define DEFINE_NFSD_FILE_OPEN_EVENT(name)					\
++DEFINE_EVENT(nfsd_file_open_class, name,					\
+ 	TP_PROTO(							\
+-		const struct inode *inode,				\
+-		unsigned int count					\
++		const struct nfsd_file *nf,				\
++		__be32 status						\
+ 	),								\
+-	TP_ARGS(inode, count))
++	TP_ARGS(nf, status))
+ 
+-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync);
+-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode);
++DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_open);
++DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_opened);
+ 
+ TRACE_EVENT(nfsd_file_is_cached,
+ 	TP_PROTO(
+@@ -1149,7 +1096,6 @@ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed);
+ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use);
+ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback);
+ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced);
+-DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed);
+ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed);
+ 
+ DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class,
+@@ -1181,6 +1127,53 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name,				\
+ DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
+ DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
+ 
++TRACE_EVENT(nfsd_file_close,
++	TP_PROTO(
++		const struct inode *inode
++	),
++	TP_ARGS(inode),
++	TP_STRUCT__entry(
++		__field(const void *, inode)
++	),
++	TP_fast_assign(
++		__entry->inode = inode;
++	),
++	TP_printk("inode=%p",
++		__entry->inode
++	)
++);
++
++TRACE_EVENT(nfsd_file_fsync,
++	TP_PROTO(
++		const struct nfsd_file *nf,
++		int ret
++	),
++	TP_ARGS(nf, ret),
++	TP_STRUCT__entry(
++		__field(void *, nf_inode)
++		__field(int, nf_ref)
++		__field(int, ret)
++		__field(unsigned long, nf_flags)
++		__field(unsigned char, nf_may)
++		__field(struct file *, nf_file)
++	),
++	TP_fast_assign(
++		__entry->nf_inode = nf->nf_inode;
++		__entry->nf_ref = refcount_read(&nf->nf_ref);
++		__entry->ret = ret;
++		__entry->nf_flags = nf->nf_flags;
++		__entry->nf_may = nf->nf_may;
++		__entry->nf_file = nf->nf_file;
++	),
++	TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p ret=%d",
++		__entry->nf_inode,
++		__entry->nf_ref,
++		show_nf_flags(__entry->nf_flags),
++		show_nfsd_may_flags(__entry->nf_may),
++		__entry->nf_file, __entry->ret
++	)
++);
++
+ #include "cache.h"
+ 
+ TRACE_DEFINE_ENUM(RC_DROPIT);
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 849a720ab43f0..2934ab1d9862b 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1085,7 +1085,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 	__be32 err;
+ 
+ 	trace_nfsd_read_start(rqstp, fhp, offset, *count);
+-	err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
++	err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_READ, &nf);
+ 	if (err)
+ 		return err;
+ 
+@@ -1117,7 +1117,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
+ 
+ 	trace_nfsd_write_start(rqstp, fhp, offset, *cnt);
+ 
+-	err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf);
++	err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_WRITE, &nf);
+ 	if (err)
+ 		goto out;
+ 
+@@ -1133,6 +1133,7 @@ out:
+  * nfsd_commit - Commit pending writes to stable storage
+  * @rqstp: RPC request being processed
+  * @fhp: NFS filehandle
++ * @nf: target file
+  * @offset: raw offset from beginning of file
+  * @count: raw count of bytes to sync
+  * @verf: filled in with the server's current write verifier
+@@ -1149,19 +1150,13 @@ out:
+  *   An nfsstat value in network byte order.
+  */
+ __be32
+-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
+-	    u32 count, __be32 *verf)
++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
++	    u64 offset, u32 count, __be32 *verf)
+ {
++	__be32			err = nfs_ok;
+ 	u64			maxbytes;
+ 	loff_t			start, end;
+ 	struct nfsd_net		*nn;
+-	struct nfsd_file	*nf;
+-	__be32			err;
+-
+-	err = nfsd_file_acquire(rqstp, fhp,
+-			NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
+-	if (err)
+-		goto out;
+ 
+ 	/*
+ 	 * Convert the client-provided (offset, count) range to a
+@@ -1202,8 +1197,6 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
+ 	} else
+ 		nfsd_copy_write_verifier(verf, nn);
+ 
+-	nfsd_file_put(nf);
+-out:
+ 	return err;
+ }
+ 
+diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
+index 120521bc7b247..9744b041105b5 100644
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -88,7 +88,8 @@ __be32		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
+ __be32		nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 				struct svc_fh *resfhp, struct nfsd_attrs *iap);
+ __be32		nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
+-				u64 offset, u32 count, __be32 *verf);
++				struct nfsd_file *nf, u64 offset, u32 count,
++				__be32 *verf);
+ #ifdef CONFIG_NFSD_V4
+ __be32		nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 			    char *name, void **bufp, int *lenp);
+diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
+index c09d72986968a..ab2d6266038a0 100644
+--- a/include/acpi/acpi_bus.h
++++ b/include/acpi/acpi_bus.h
+@@ -230,7 +230,8 @@ struct acpi_pnp_type {
+ 	u32 hardware_id:1;
+ 	u32 bus_address:1;
+ 	u32 platform_id:1;
+-	u32 reserved:29;
++	u32 backlight:1;
++	u32 reserved:28;
+ };
+ 
+ struct acpi_device_pnp {
+diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
+index 346a8b56cdc83..79e26b18bf0ef 100644
+--- a/include/linux/elfcore.h
++++ b/include/linux/elfcore.h
+@@ -114,14 +114,14 @@ static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_reg
+  * Dumping its extra ELF program headers includes all the other information
+  * a debugger needs to easily find how the gate DSO was being used.
+  */
+-extern Elf_Half elf_core_extra_phdrs(void);
++extern Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm);
+ extern int
+ elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset);
+ extern int
+ elf_core_write_extra_data(struct coredump_params *cprm);
+-extern size_t elf_core_extra_data_size(void);
++extern size_t elf_core_extra_data_size(struct coredump_params *cprm);
+ #else
+-static inline Elf_Half elf_core_extra_phdrs(void)
++static inline Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
+ {
+ 	return 0;
+ }
+@@ -136,7 +136,7 @@ static inline int elf_core_write_extra_data(struct coredump_params *cprm)
+ 	return 1;
+ }
+ 
+-static inline size_t elf_core_extra_data_size(void)
++static inline size_t elf_core_extra_data_size(struct coredump_params *cprm)
+ {
+ 	return 0;
+ }
+diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
+index 06cbad166225a..ad55470a9fb97 100644
+--- a/include/linux/mlx5/driver.h
++++ b/include/linux/mlx5/driver.h
+@@ -315,7 +315,7 @@ struct mlx5_cmd {
+ 	struct mlx5_cmd_debug dbg;
+ 	struct cmd_msg_cache cache[MLX5_NUM_COMMAND_CACHES];
+ 	int checksum_disabled;
+-	struct mlx5_cmd_stats *stats;
++	struct mlx5_cmd_stats stats[MLX5_CMD_OP_MAX];
+ };
+ 
+ struct mlx5_cmd_mailbox {
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 42218a1164f6d..f92bf7f7a7543 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -7,7 +7,6 @@
+ #define __LINUX_MTD_SPI_NOR_H
+ 
+ #include <linux/bitops.h>
+-#include <linux/mtd/cfi.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/spi/spi-mem.h>
+ 
+diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
+index 20c0ff54b7a0d..7d68a5cc58816 100644
+--- a/include/linux/tpm_eventlog.h
++++ b/include/linux/tpm_eventlog.h
+@@ -198,8 +198,8 @@ static __always_inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *ev
+ 	 * The loop below will unmap these fields if the log is larger than
+ 	 * one page, so save them here for reference:
+ 	 */
+-	count = READ_ONCE(event->count);
+-	event_type = READ_ONCE(event->event_type);
++	count = event->count;
++	event_type = event->event_type;
+ 
+ 	/* Verify that it's the log header */
+ 	if (event_header->pcr_idx != 0 ||
+diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
+index 3511095c2702b..42a40ad3fb622 100644
+--- a/include/uapi/linux/psci.h
++++ b/include/uapi/linux/psci.h
+@@ -58,7 +58,7 @@
+ 
+ #define PSCI_1_1_FN_SYSTEM_RESET2		PSCI_0_2_FN(18)
+ #define PSCI_1_1_FN_MEM_PROTECT			PSCI_0_2_FN(19)
+-#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE	PSCI_0_2_FN(19)
++#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE	PSCI_0_2_FN(20)
+ 
+ #define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND	PSCI_0_2_FN64(12)
+ #define PSCI_1_0_FN64_NODE_HW_STATE		PSCI_0_2_FN64(13)
+@@ -67,7 +67,7 @@
+ #define PSCI_1_0_FN64_STAT_COUNT		PSCI_0_2_FN64(17)
+ 
+ #define PSCI_1_1_FN64_SYSTEM_RESET2		PSCI_0_2_FN64(18)
+-#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE	PSCI_0_2_FN64(19)
++#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE	PSCI_0_2_FN64(20)
+ 
+ /* PSCI v0.2 power state encoding for CPU_SUSPEND function */
+ #define PSCI_0_2_POWER_STATE_ID_MASK		0xffff
+diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c
+index 2e04850a657b0..882bd56b01ed0 100644
+--- a/io_uring/fdinfo.c
++++ b/io_uring/fdinfo.c
+@@ -170,12 +170,11 @@ static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
+ 		xa_for_each(&ctx->personalities, index, cred)
+ 			io_uring_show_cred(m, index, cred);
+ 	}
+-	if (has_lock)
+-		mutex_unlock(&ctx->uring_lock);
+ 
+ 	seq_puts(m, "PollList:\n");
+ 	for (i = 0; i < (1U << ctx->cancel_table.hash_bits); i++) {
+ 		struct io_hash_bucket *hb = &ctx->cancel_table.hbs[i];
++		struct io_hash_bucket *hbl = &ctx->cancel_table_locked.hbs[i];
+ 		struct io_kiocb *req;
+ 
+ 		spin_lock(&hb->lock);
+@@ -183,8 +182,17 @@ static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
+ 			seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
+ 					task_work_pending(req->task));
+ 		spin_unlock(&hb->lock);
++
++		if (!has_lock)
++			continue;
++		hlist_for_each_entry(req, &hbl->list, hash_node)
++			seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
++					task_work_pending(req->task));
+ 	}
+ 
++	if (has_lock)
++		mutex_unlock(&ctx->uring_lock);
++
+ 	seq_puts(m, "CqOverflowList:\n");
+ 	spin_lock(&ctx->completion_lock);
+ 	list_for_each_entry(ocqe, &ctx->cq_overflow_list, list) {
+diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
+index 6f1d0e5df23ad..411bb2d1acd45 100644
+--- a/io_uring/io-wq.c
++++ b/io_uring/io-wq.c
+@@ -1230,6 +1230,12 @@ static void io_wq_cancel_tw_create(struct io_wq *wq)
+ 
+ 		worker = container_of(cb, struct io_worker, create_work);
+ 		io_worker_cancel_cb(worker);
++		/*
++		 * Only the worker continuation helper has worker allocated and
++		 * hence needs freeing.
++		 */
++		if (cb->func == create_worker_cont)
++			kfree(worker);
+ 	}
+ }
+ 
+diff --git a/io_uring/poll.c b/io_uring/poll.c
+index fded1445a803b..f2f9f174fc620 100644
+--- a/io_uring/poll.c
++++ b/io_uring/poll.c
+@@ -223,22 +223,23 @@ enum {
+ 	IOU_POLL_DONE = 0,
+ 	IOU_POLL_NO_ACTION = 1,
+ 	IOU_POLL_REMOVE_POLL_USE_RES = 2,
++	IOU_POLL_REISSUE = 3,
+ };
+ 
+ /*
+  * All poll tw should go through this. Checks for poll events, manages
+  * references, does rewait, etc.
+  *
+- * Returns a negative error on failure. IOU_POLL_NO_ACTION when no action require,
+- * which is either spurious wakeup or multishot CQE is served.
+- * IOU_POLL_DONE when it's done with the request, then the mask is stored in req->cqe.res.
+- * IOU_POLL_REMOVE_POLL_USE_RES indicates to remove multishot poll and that the result
+- * is stored in req->cqe.
++ * Returns a negative error on failure. IOU_POLL_NO_ACTION when no action
++ * require, which is either spurious wakeup or multishot CQE is served.
++ * IOU_POLL_DONE when it's done with the request, then the mask is stored in
++ * req->cqe.res. IOU_POLL_REMOVE_POLL_USE_RES indicates to remove multishot
++ * poll and that the result is stored in req->cqe.
+  */
+ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
+ {
+ 	struct io_ring_ctx *ctx = req->ctx;
+-	int v, ret;
++	int v;
+ 
+ 	/* req->task == current here, checking PF_EXITING is safe */
+ 	if (unlikely(req->task->flags & PF_EXITING))
+@@ -274,10 +275,15 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
+ 		if (!req->cqe.res) {
+ 			struct poll_table_struct pt = { ._key = req->apoll_events };
+ 			req->cqe.res = vfs_poll(req->file, &pt) & req->apoll_events;
++			/*
++			 * We got woken with a mask, but someone else got to
++			 * it first. The above vfs_poll() doesn't add us back
++			 * to the waitqueue, so if we get nothing back, we
++			 * should be safe and attempt a reissue.
++			 */
++			if (unlikely(!req->cqe.res))
++				return IOU_POLL_REISSUE;
+ 		}
+-
+-		if ((unlikely(!req->cqe.res)))
+-			continue;
+ 		if (req->apoll_events & EPOLLONESHOT)
+ 			return IOU_POLL_DONE;
+ 		if (io_is_uring_fops(req->file))
+@@ -294,7 +300,7 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
+ 				return IOU_POLL_REMOVE_POLL_USE_RES;
+ 			}
+ 		} else {
+-			ret = io_poll_issue(req, locked);
++			int ret = io_poll_issue(req, locked);
+ 			if (ret == IOU_STOP_MULTISHOT)
+ 				return IOU_POLL_REMOVE_POLL_USE_RES;
+ 			if (ret < 0)
+@@ -325,6 +331,11 @@ static void io_poll_task_func(struct io_kiocb *req, bool *locked)
+ 	if (ret == IOU_POLL_DONE) {
+ 		struct io_poll *poll = io_kiocb_to_cmd(req, struct io_poll);
+ 		req->cqe.res = mangle_poll(req->cqe.res & poll->events);
++	} else if (ret == IOU_POLL_REISSUE) {
++		io_poll_remove_entries(req);
++		io_poll_tw_hash_eject(req, locked);
++		io_req_task_submit(req, locked);
++		return;
+ 	} else if (ret != IOU_POLL_REMOVE_POLL_USE_RES) {
+ 		req->cqe.res = ret;
+ 		req_set_fail(req);
+@@ -350,7 +361,7 @@ static void io_apoll_task_func(struct io_kiocb *req, bool *locked)
+ 
+ 	if (ret == IOU_POLL_REMOVE_POLL_USE_RES)
+ 		io_req_complete_post(req);
+-	else if (ret == IOU_POLL_DONE)
++	else if (ret == IOU_POLL_DONE || ret == IOU_POLL_REISSUE)
+ 		io_req_task_submit(req, locked);
+ 	else
+ 		io_req_complete_failed(req, ret);
+@@ -549,6 +560,14 @@ static bool io_poll_can_finish_inline(struct io_kiocb *req,
+ 	return pt->owning || io_poll_get_ownership(req);
+ }
+ 
++static void io_poll_add_hash(struct io_kiocb *req)
++{
++	if (req->flags & REQ_F_HASH_LOCKED)
++		io_poll_req_insert_locked(req);
++	else
++		io_poll_req_insert(req);
++}
++
+ /*
+  * Returns 0 when it's handed over for polling. The caller owns the requests if
+  * it returns non-zero, but otherwise should not touch it. Negative values
+@@ -607,18 +626,17 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
+ 
+ 	if (mask &&
+ 	   ((poll->events & (EPOLLET|EPOLLONESHOT)) == (EPOLLET|EPOLLONESHOT))) {
+-		if (!io_poll_can_finish_inline(req, ipt))
++		if (!io_poll_can_finish_inline(req, ipt)) {
++			io_poll_add_hash(req);
+ 			return 0;
++		}
+ 		io_poll_remove_entries(req);
+ 		ipt->result_mask = mask;
+ 		/* no one else has access to the req, forget about the ref */
+ 		return 1;
+ 	}
+ 
+-	if (req->flags & REQ_F_HASH_LOCKED)
+-		io_poll_req_insert_locked(req);
+-	else
+-		io_poll_req_insert(req);
++	io_poll_add_hash(req);
+ 
+ 	if (mask && (poll->events & EPOLLET) &&
+ 	    io_poll_can_finish_inline(req, ipt)) {
+diff --git a/io_uring/rw.c b/io_uring/rw.c
+index bb47cc4da713c..6223472095d2c 100644
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -1055,7 +1055,11 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
+ 			continue;
+ 
+ 		req->cqe.flags = io_put_kbuf(req, 0);
+-		__io_fill_cqe_req(req->ctx, req);
++		if (unlikely(!__io_fill_cqe_req(ctx, req))) {
++			spin_lock(&ctx->completion_lock);
++			io_req_cqe_overflow(req);
++			spin_unlock(&ctx->completion_lock);
++		}
+ 	}
+ 
+ 	if (unlikely(!nr_events))
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index 535af9fbea7b8..172ec79b66f6c 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -2587,14 +2587,43 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
+ int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
+ 		      int node)
+ {
+-	if (!src->user_cpus_ptr)
++	cpumask_t *user_mask;
++	unsigned long flags;
++
++	/*
++	 * Always clear dst->user_cpus_ptr first as their user_cpus_ptr's
++	 * may differ by now due to racing.
++	 */
++	dst->user_cpus_ptr = NULL;
++
++	/*
++	 * This check is racy and losing the race is a valid situation.
++	 * It is not worth the extra overhead of taking the pi_lock on
++	 * every fork/clone.
++	 */
++	if (data_race(!src->user_cpus_ptr))
+ 		return 0;
+ 
+-	dst->user_cpus_ptr = kmalloc_node(cpumask_size(), GFP_KERNEL, node);
+-	if (!dst->user_cpus_ptr)
++	user_mask = kmalloc_node(cpumask_size(), GFP_KERNEL, node);
++	if (!user_mask)
+ 		return -ENOMEM;
+ 
+-	cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
++	/*
++	 * Use pi_lock to protect content of user_cpus_ptr
++	 *
++	 * Though unlikely, user_cpus_ptr can be reset to NULL by a concurrent
++	 * do_set_cpus_allowed().
++	 */
++	raw_spin_lock_irqsave(&src->pi_lock, flags);
++	if (src->user_cpus_ptr) {
++		swap(dst->user_cpus_ptr, user_mask);
++		cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
++	}
++	raw_spin_unlock_irqrestore(&src->pi_lock, flags);
++
++	if (unlikely(user_mask))
++		kfree(user_mask);
++
+ 	return 0;
+ }
+ 
+@@ -5469,7 +5498,9 @@ void scheduler_tick(void)
+ 	unsigned long thermal_pressure;
+ 	u64 resched_latency;
+ 
+-	arch_scale_freq_tick();
++	if (housekeeping_cpu(cpu, HK_TYPE_TICK))
++		arch_scale_freq_tick();
++
+ 	sched_clock_tick();
+ 
+ 	rq_lock(rq, &rf);
+diff --git a/mm/memblock.c b/mm/memblock.c
+index 511d4783dcf1d..fc3d8fbd2060d 100644
+--- a/mm/memblock.c
++++ b/mm/memblock.c
+@@ -1640,7 +1640,13 @@ void __init memblock_free_late(phys_addr_t base, phys_addr_t size)
+ 	end = PFN_DOWN(base + size);
+ 
+ 	for (; cursor < end; cursor++) {
+-		memblock_free_pages(pfn_to_page(cursor), cursor, 0);
++		/*
++		 * Reserved pages are always initialized by the end of
++		 * memblock_free_all() (by memmap_init() and, if deferred
++		 * initialization is enabled, memmap_init_reserved_pages()), so
++		 * these pages can be released directly to the buddy allocator.
++		 */
++		__free_pages_core(pfn_to_page(cursor), 0);
+ 		totalram_pages_inc();
+ 	}
+ }
+diff --git a/net/core/gro.c b/net/core/gro.c
+index bc9451743307b..1b4abfb9a7a13 100644
+--- a/net/core/gro.c
++++ b/net/core/gro.c
+@@ -489,45 +489,46 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
+ 
+ 	rcu_read_lock();
+ 	list_for_each_entry_rcu(ptype, head, list) {
+-		if (ptype->type != type || !ptype->callbacks.gro_receive)
+-			continue;
+-
+-		skb_set_network_header(skb, skb_gro_offset(skb));
+-		skb_reset_mac_len(skb);
+-		BUILD_BUG_ON(sizeof_field(struct napi_gro_cb, zeroed) != sizeof(u32));
+-		BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct napi_gro_cb, zeroed),
+-					 sizeof(u32))); /* Avoid slow unaligned acc */
+-		*(u32 *)&NAPI_GRO_CB(skb)->zeroed = 0;
+-		NAPI_GRO_CB(skb)->flush = skb_has_frag_list(skb);
+-		NAPI_GRO_CB(skb)->is_atomic = 1;
+-		NAPI_GRO_CB(skb)->count = 1;
+-		if (unlikely(skb_is_gso(skb))) {
+-			NAPI_GRO_CB(skb)->count = skb_shinfo(skb)->gso_segs;
+-			/* Only support TCP at the moment. */
+-			if (!skb_is_gso_tcp(skb))
+-				NAPI_GRO_CB(skb)->flush = 1;
+-		}
+-
+-		/* Setup for GRO checksum validation */
+-		switch (skb->ip_summed) {
+-		case CHECKSUM_COMPLETE:
+-			NAPI_GRO_CB(skb)->csum = skb->csum;
+-			NAPI_GRO_CB(skb)->csum_valid = 1;
+-			break;
+-		case CHECKSUM_UNNECESSARY:
+-			NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
+-			break;
+-		}
++		if (ptype->type == type && ptype->callbacks.gro_receive)
++			goto found_ptype;
++	}
++	rcu_read_unlock();
++	goto normal;
++
++found_ptype:
++	skb_set_network_header(skb, skb_gro_offset(skb));
++	skb_reset_mac_len(skb);
++	BUILD_BUG_ON(sizeof_field(struct napi_gro_cb, zeroed) != sizeof(u32));
++	BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct napi_gro_cb, zeroed),
++					sizeof(u32))); /* Avoid slow unaligned acc */
++	*(u32 *)&NAPI_GRO_CB(skb)->zeroed = 0;
++	NAPI_GRO_CB(skb)->flush = skb_has_frag_list(skb);
++	NAPI_GRO_CB(skb)->is_atomic = 1;
++	NAPI_GRO_CB(skb)->count = 1;
++	if (unlikely(skb_is_gso(skb))) {
++		NAPI_GRO_CB(skb)->count = skb_shinfo(skb)->gso_segs;
++		/* Only support TCP and non DODGY users. */
++		if (!skb_is_gso_tcp(skb) ||
++		    (skb_shinfo(skb)->gso_type & SKB_GSO_DODGY))
++			NAPI_GRO_CB(skb)->flush = 1;
++	}
+ 
+-		pp = INDIRECT_CALL_INET(ptype->callbacks.gro_receive,
+-					ipv6_gro_receive, inet_gro_receive,
+-					&gro_list->list, skb);
++	/* Setup for GRO checksum validation */
++	switch (skb->ip_summed) {
++	case CHECKSUM_COMPLETE:
++		NAPI_GRO_CB(skb)->csum = skb->csum;
++		NAPI_GRO_CB(skb)->csum_valid = 1;
++		break;
++	case CHECKSUM_UNNECESSARY:
++		NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
+ 		break;
+ 	}
+-	rcu_read_unlock();
+ 
+-	if (&ptype->list == head)
+-		goto normal;
++	pp = INDIRECT_CALL_INET(ptype->callbacks.gro_receive,
++				ipv6_gro_receive, inet_gro_receive,
++				&gro_list->list, skb);
++
++	rcu_read_unlock();
+ 
+ 	if (PTR_ERR(pp) == -EINPROGRESS) {
+ 		ret = GRO_CONSUMED;
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index 722de9dd0ff78..8ffeac7456567 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -505,6 +505,7 @@ csum_copy_err:
+ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+ 				     struct raw6_sock *rp)
+ {
++	struct ipv6_txoptions *opt;
+ 	struct sk_buff *skb;
+ 	int err = 0;
+ 	int offset;
+@@ -522,6 +523,9 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+ 
+ 	offset = rp->offset;
+ 	total_len = inet_sk(sk)->cork.base.length;
++	opt = inet6_sk(sk)->cork.opt;
++	total_len -= opt ? opt->opt_flen : 0;
++
+ 	if (offset >= total_len - 1) {
+ 		err = -EINVAL;
+ 		ip6_flush_pending_frames(sk);
+diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
+index a8ce04a4bb72a..e4fa00abde6a2 100644
+--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
++++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
+@@ -308,8 +308,8 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
+ 			return -IPSET_ERR_BITMAP_RANGE;
+ 
+ 		pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
+-		hosts = 2 << (32 - netmask - 1);
+-		elements = 2 << (netmask - mask_bits - 1);
++		hosts = 2U << (32 - netmask - 1);
++		elements = 2UL << (netmask - mask_bits - 1);
+ 	}
+ 	if (elements > IPSET_BITMAP_MAX_RANGE + 1)
+ 		return -IPSET_ERR_BITMAP_RANGE_SIZE;
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index 4edd899aeb9bb..d7de2ecb287eb 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -62,7 +62,7 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
+ 			return false;
+ 
+ 		if (offset + len > VLAN_ETH_HLEN + vlan_hlen)
+-			ethlen -= offset + len - VLAN_ETH_HLEN + vlan_hlen;
++			ethlen -= offset + len - VLAN_ETH_HLEN - vlan_hlen;
+ 
+ 		memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen);
+ 
+diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
+index 8ad25cc8ccd55..ea5959094adb0 100644
+--- a/net/sched/act_mpls.c
++++ b/net/sched/act_mpls.c
+@@ -132,6 +132,11 @@ static int valid_label(const struct nlattr *attr,
+ {
+ 	const u32 *label = nla_data(attr);
+ 
++	if (nla_len(attr) != sizeof(*label)) {
++		NL_SET_ERR_MSG_MOD(extack, "Invalid MPLS label length");
++		return -EINVAL;
++	}
++
+ 	if (*label & ~MPLS_LABEL_MASK || *label == MPLS_LABEL_IMPLNULL) {
+ 		NL_SET_ERR_MSG_MOD(extack, "MPLS label out of range");
+ 		return -EINVAL;
+@@ -143,7 +148,8 @@ static int valid_label(const struct nlattr *attr,
+ static const struct nla_policy mpls_policy[TCA_MPLS_MAX + 1] = {
+ 	[TCA_MPLS_PARMS]	= NLA_POLICY_EXACT_LEN(sizeof(struct tc_mpls)),
+ 	[TCA_MPLS_PROTO]	= { .type = NLA_U16 },
+-	[TCA_MPLS_LABEL]	= NLA_POLICY_VALIDATE_FN(NLA_U32, valid_label),
++	[TCA_MPLS_LABEL]	= NLA_POLICY_VALIDATE_FN(NLA_BINARY,
++							 valid_label),
+ 	[TCA_MPLS_TC]		= NLA_POLICY_RANGE(NLA_U8, 0, 7),
+ 	[TCA_MPLS_TTL]		= NLA_POLICY_MIN(NLA_U8, 1),
+ 	[TCA_MPLS_BOS]		= NLA_POLICY_RANGE(NLA_U8, 0, 1),
+diff --git a/net/tipc/node.c b/net/tipc/node.c
+index 49ddc484c4fe7..5e000fde80676 100644
+--- a/net/tipc/node.c
++++ b/net/tipc/node.c
+@@ -1179,8 +1179,9 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 	bool addr_match = false;
+ 	bool sign_match = false;
+ 	bool link_up = false;
++	bool link_is_reset = false;
+ 	bool accept_addr = false;
+-	bool reset = true;
++	bool reset = false;
+ 	char *if_name;
+ 	unsigned long intv;
+ 	u16 session;
+@@ -1200,14 +1201,14 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 	/* Prepare to validate requesting node's signature and media address */
+ 	l = le->link;
+ 	link_up = l && tipc_link_is_up(l);
++	link_is_reset = l && tipc_link_is_reset(l);
+ 	addr_match = l && !memcmp(&le->maddr, maddr, sizeof(*maddr));
+ 	sign_match = (signature == n->signature);
+ 
+ 	/* These three flags give us eight permutations: */
+ 
+ 	if (sign_match && addr_match && link_up) {
+-		/* All is fine. Do nothing. */
+-		reset = false;
++		/* All is fine. Ignore requests. */
+ 		/* Peer node is not a container/local namespace */
+ 		if (!n->peer_hash_mix)
+ 			n->peer_hash_mix = hash_mixes;
+@@ -1232,6 +1233,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 		 */
+ 		accept_addr = true;
+ 		*respond = true;
++		reset = true;
+ 	} else if (!sign_match && addr_match && link_up) {
+ 		/* Peer node rebooted. Two possibilities:
+ 		 *  - Delayed re-discovery; this link endpoint has already
+@@ -1263,6 +1265,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 		n->signature = signature;
+ 		accept_addr = true;
+ 		*respond = true;
++		reset = true;
+ 	}
+ 
+ 	if (!accept_addr)
+@@ -1291,6 +1294,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 		tipc_link_fsm_evt(l, LINK_RESET_EVT);
+ 		if (n->state == NODE_FAILINGOVER)
+ 			tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT);
++		link_is_reset = tipc_link_is_reset(l);
+ 		le->link = l;
+ 		n->link_cnt++;
+ 		tipc_node_calculate_timer(n, l);
+@@ -1303,7 +1307,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
+ 	memcpy(&le->maddr, maddr, sizeof(*maddr));
+ exit:
+ 	tipc_node_write_unlock(n);
+-	if (reset && l && !tipc_link_is_reset(l))
++	if (reset && !link_is_reset)
+ 		tipc_node_link_down(n, b->identity, false);
+ 	tipc_node_put(n);
+ }
+diff --git a/sound/core/control_led.c b/sound/core/control_led.c
+index f975cc85772bb..3cadd40100f3e 100644
+--- a/sound/core/control_led.c
++++ b/sound/core/control_led.c
+@@ -530,12 +530,11 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
+ 			  bool attach)
+ {
+ 	char buf2[256], *s, *os;
+-	size_t len = max(sizeof(s) - 1, count);
+ 	struct snd_ctl_elem_id id;
+ 	int err;
+ 
+-	strncpy(buf2, buf, len);
+-	buf2[len] = '\0';
++	if (strscpy(buf2, buf, sizeof(buf2)) < 0)
++		return -E2BIG;
+ 	memset(&id, 0, sizeof(id));
+ 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ 	s = buf2;
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 764eb07bbaff4..6fab7c8fc19ae 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -3564,6 +3564,15 @@ static void alc256_init(struct hda_codec *codec)
+ 	hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ 	bool hp_pin_sense;
+ 
++	if (spec->ultra_low_power) {
++		alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
++		alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
++		alc_update_coef_idx(codec, 0x08, 7<<4, 0);
++		alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
++		alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
++		msleep(30);
++	}
++
+ 	if (!hp_pin)
+ 		hp_pin = 0x21;
+ 
+@@ -3575,14 +3584,6 @@ static void alc256_init(struct hda_codec *codec)
+ 		msleep(2);
+ 
+ 	alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+-	if (spec->ultra_low_power) {
+-		alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
+-		alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
+-		alc_update_coef_idx(codec, 0x08, 7<<4, 0);
+-		alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
+-		alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+-		msleep(30);
+-	}
+ 
+ 	snd_hda_codec_write(codec, hp_pin, 0,
+ 			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+@@ -3713,6 +3714,13 @@ static void alc225_init(struct hda_codec *codec)
+ 	hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ 	bool hp1_pin_sense, hp2_pin_sense;
+ 
++	if (spec->ultra_low_power) {
++		alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
++		alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
++		alc_update_coef_idx(codec, 0x33, 1<<11, 0);
++		msleep(30);
++	}
++
+ 	if (spec->codec_variant != ALC269_TYPE_ALC287 &&
+ 		spec->codec_variant != ALC269_TYPE_ALC245)
+ 		/* required only at boot or S3 and S4 resume time */
+@@ -3734,12 +3742,6 @@ static void alc225_init(struct hda_codec *codec)
+ 		msleep(2);
+ 
+ 	alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+-	if (spec->ultra_low_power) {
+-		alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
+-		alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+-		alc_update_coef_idx(codec, 0x33, 1<<11, 0);
+-		msleep(30);
+-	}
+ 
+ 	if (hp1_pin_sense || spec->ultra_low_power)
+ 		snd_hda_codec_write(codec, hp_pin, 0,
+@@ -4644,6 +4646,16 @@ static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+ 	}
+ }
+ 
++static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
++				const struct hda_fixup *fix, int action)
++{
++	struct alc_spec *spec = codec->spec;
++
++	if (action == HDA_FIXUP_ACT_PRE_PROBE)
++		spec->micmute_led_polarity = 1;
++	alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
++}
++
+ static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+ 				const struct hda_fixup *fix, int action)
+ {
+@@ -4665,6 +4677,13 @@ static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
+ 	alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+ }
+ 
++static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
++				const struct hda_fixup *fix, int action)
++{
++	alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
++	alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
++}
++
+ static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
+ 				const struct hda_fixup *fix, int action)
+ {
+@@ -7106,6 +7125,7 @@ enum {
+ 	ALC285_FIXUP_ASUS_G533Z_PINS,
+ 	ALC285_FIXUP_HP_GPIO_LED,
+ 	ALC285_FIXUP_HP_MUTE_LED,
++	ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
+ 	ALC236_FIXUP_HP_GPIO_LED,
+ 	ALC236_FIXUP_HP_MUTE_LED,
+ 	ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
+@@ -8486,6 +8506,10 @@ static const struct hda_fixup alc269_fixups[] = {
+ 		.type = HDA_FIXUP_FUNC,
+ 		.v.func = alc285_fixup_hp_mute_led,
+ 	},
++	[ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
++		.type = HDA_FIXUP_FUNC,
++		.v.func = alc285_fixup_hp_spectre_x360_mute_led,
++	},
+ 	[ALC236_FIXUP_HP_GPIO_LED] = {
+ 		.type = HDA_FIXUP_FUNC,
+ 		.v.func = alc236_fixup_hp_gpio_led,
+@@ -9328,6 +9352,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ 	SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
+ 	SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+ 	SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
++	SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
+ 	SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ 	SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ 	SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
+diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
+index 644300e88b4c5..fcf4fbaed3c76 100644
+--- a/sound/soc/codecs/rt9120.c
++++ b/sound/soc/codecs/rt9120.c
+@@ -177,8 +177,20 @@ static int rt9120_codec_probe(struct snd_soc_component *comp)
+ 	return 0;
+ }
+ 
++static int rt9120_codec_suspend(struct snd_soc_component *comp)
++{
++	return pm_runtime_force_suspend(comp->dev);
++}
++
++static int rt9120_codec_resume(struct snd_soc_component *comp)
++{
++	return pm_runtime_force_resume(comp->dev);
++}
++
+ static const struct snd_soc_component_driver rt9120_component_driver = {
+ 	.probe = rt9120_codec_probe,
++	.suspend = rt9120_codec_suspend,
++	.resume = rt9120_codec_resume,
+ 	.controls = rt9120_snd_controls,
+ 	.num_controls = ARRAY_SIZE(rt9120_snd_controls),
+ 	.dapm_widgets = rt9120_dapm_widgets,
+diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
+index ca6a01a230af4..791d8738d1c0e 100644
+--- a/sound/soc/codecs/wm8904.c
++++ b/sound/soc/codecs/wm8904.c
+@@ -697,6 +697,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
+ 	int dcs_mask;
+ 	int dcs_l, dcs_r;
+ 	int dcs_l_reg, dcs_r_reg;
++	int an_out_reg;
+ 	int timeout;
+ 	int pwr_reg;
+ 
+@@ -712,6 +713,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
+ 		dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
+ 		dcs_r_reg = WM8904_DC_SERVO_8;
+ 		dcs_l_reg = WM8904_DC_SERVO_9;
++		an_out_reg = WM8904_ANALOGUE_OUT1_LEFT;
+ 		dcs_l = 0;
+ 		dcs_r = 1;
+ 		break;
+@@ -720,6 +722,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
+ 		dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
+ 		dcs_r_reg = WM8904_DC_SERVO_6;
+ 		dcs_l_reg = WM8904_DC_SERVO_7;
++		an_out_reg = WM8904_ANALOGUE_OUT2_LEFT;
+ 		dcs_l = 2;
+ 		dcs_r = 3;
+ 		break;
+@@ -792,6 +795,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
+ 		snd_soc_component_update_bits(component, reg,
+ 				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+ 				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
++
++		/* Update volume, requires PGA to be powered */
++		val = snd_soc_component_read(component, an_out_reg);
++		snd_soc_component_write(component, an_out_reg, val);
+ 		break;
+ 
+ 	case SND_SOC_DAPM_POST_PMU:
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
+index aa12d7e3dd2f9..ca49cc49c378c 100644
+--- a/sound/soc/intel/boards/Kconfig
++++ b/sound/soc/intel/boards/Kconfig
+@@ -558,6 +558,7 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
+ 	select SND_SOC_HDAC_HDMI
+ 	select SND_SOC_INTEL_HDA_DSP_COMMON
+ 	select SND_SOC_INTEL_SOF_MAXIM_COMMON
++	select SND_SOC_INTEL_SOF_REALTEK_COMMON
+ 	help
+ 	   This adds support for ASoC machine driver for SOF platforms
+ 	   with nau8825 codec.
+diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
+index 5585c217f78d3..009a41fbefa10 100644
+--- a/sound/soc/intel/boards/sof_nau8825.c
++++ b/sound/soc/intel/boards/sof_nau8825.c
+@@ -47,6 +47,7 @@
+ #define SOF_RT1019P_SPEAKER_AMP_PRESENT	BIT(14)
+ #define SOF_MAX98373_SPEAKER_AMP_PRESENT	BIT(15)
+ #define SOF_MAX98360A_SPEAKER_AMP_PRESENT	BIT(16)
++#define SOF_RT1015P_SPEAKER_AMP_PRESENT	BIT(17)
+ 
+ static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
+ 
+@@ -483,6 +484,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
+ 		} else if (sof_nau8825_quirk &
+ 				SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
+ 			max_98360a_dai_link(&links[id]);
++		} else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
++			sof_rt1015p_dai_link(&links[id]);
+ 		} else {
+ 			goto devm_err;
+ 		}
+@@ -576,6 +579,8 @@ static int sof_audio_probe(struct platform_device *pdev)
+ 
+ 	if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
+ 		max_98373_set_codec_conf(&sof_audio_card_nau8825);
++	else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
++		sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
+ 
+ 	if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
+ 		sof_audio_card_nau8825.num_links++;
+@@ -613,7 +618,7 @@ static const struct platform_device_id board_ids[] = {
+ 
+ 	},
+ 	{
+-		.name = "adl_rt1019p_nau8825",
++		.name = "adl_rt1019p_8825",
+ 		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ 					SOF_SPEAKER_AMP_PRESENT |
+ 					SOF_RT1019P_SPEAKER_AMP_PRESENT |
+@@ -621,7 +626,7 @@ static const struct platform_device_id board_ids[] = {
+ 					SOF_NAU8825_NUM_HDMIDEV(4)),
+ 	},
+ 	{
+-		.name = "adl_max98373_nau8825",
++		.name = "adl_max98373_8825",
+ 		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ 					SOF_SPEAKER_AMP_PRESENT |
+ 					SOF_MAX98373_SPEAKER_AMP_PRESENT |
+@@ -632,7 +637,7 @@ static const struct platform_device_id board_ids[] = {
+ 	},
+ 	{
+ 		/* The limitation of length of char array, shorten the name */
+-		.name = "adl_mx98360a_nau8825",
++		.name = "adl_mx98360a_8825",
+ 		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ 					SOF_SPEAKER_AMP_PRESENT |
+ 					SOF_MAX98360A_SPEAKER_AMP_PRESENT |
+@@ -642,6 +647,16 @@ static const struct platform_device_id board_ids[] = {
+ 					SOF_SSP_BT_OFFLOAD_PRESENT),
+ 
+ 	},
++	{
++		.name = "adl_rt1015p_8825",
++		.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
++					SOF_SPEAKER_AMP_PRESENT |
++					SOF_RT1015P_SPEAKER_AMP_PRESENT |
++					SOF_NAU8825_SSP_AMP(1) |
++					SOF_NAU8825_NUM_HDMIDEV(4) |
++					SOF_BT_OFFLOAD_SSP(2) |
++					SOF_SSP_BT_OFFLOAD_PRESENT),
++	},
+ 	{ }
+ };
+ MODULE_DEVICE_TABLE(platform, board_ids);
+@@ -663,3 +678,4 @@ MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
+ MODULE_LICENSE("GPL");
+ MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+ MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
++MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
+diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+index 9990d5502d264..68b4fa352354d 100644
+--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
++++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+@@ -430,6 +430,11 @@ static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
+ 	.codecs = {"10EC5682", "RTL5682"},
+ };
+ 
++static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
++	.num_codecs = 1,
++	.codecs = {"RTL1015"}
++};
++
+ static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
+ 	.num_codecs = 1,
+ 	.codecs = {"RTL1019"}
+@@ -469,21 +474,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
+ 	},
+ 	{
+ 		.id = "10508825",
+-		.drv_name = "adl_rt1019p_nau8825",
++		.drv_name = "adl_rt1019p_8825",
+ 		.machine_quirk = snd_soc_acpi_codec_list,
+ 		.quirk_data = &adl_rt1019p_amp,
+ 		.sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
+ 	},
+ 	{
+ 		.id = "10508825",
+-		.drv_name = "adl_max98373_nau8825",
++		.drv_name = "adl_max98373_8825",
+ 		.machine_quirk = snd_soc_acpi_codec_list,
+ 		.quirk_data = &adl_max98373_amp,
+ 		.sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
+ 	},
+ 	{
+ 		.id = "10508825",
+-		.drv_name = "adl_mx98360a_nau8825",
++		.drv_name = "adl_mx98360a_8825",
+ 		.machine_quirk = snd_soc_acpi_codec_list,
+ 		.quirk_data = &adl_max98360a_amp,
+ 		.sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
+@@ -495,6 +500,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
+ 		.quirk_data = &adl_rt1019p_amp,
+ 		.sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg",
+ 	},
++	{
++		.id = "10508825",
++		.drv_name = "adl_rt1015p_8825",
++		.machine_quirk = snd_soc_acpi_codec_list,
++		.quirk_data = &adl_rt1015p_amp,
++		.sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
++	},
+ 	{
+ 		.id = "10508825",
+ 		.drv_name = "sof_nau8825",
+diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
+index 96a6d4731e6fd..e7b00d1d9e99f 100644
+--- a/sound/soc/qcom/Kconfig
++++ b/sound/soc/qcom/Kconfig
+@@ -2,7 +2,6 @@
+ menuconfig SND_SOC_QCOM
+ 	tristate "ASoC support for QCOM platforms"
+ 	depends on ARCH_QCOM || COMPILE_TEST
+-	imply SND_SOC_QCOM_COMMON
+ 	help
+ 	  Say Y or M if you want to add support to use audio devices
+ 	  in Qualcomm Technologies SOC-based platforms.
+@@ -60,14 +59,16 @@ config SND_SOC_STORM
+ config SND_SOC_APQ8016_SBC
+ 	tristate "SoC Audio support for APQ8016 SBC platforms"
+ 	select SND_SOC_LPASS_APQ8016
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
+ 	help
+ 	  Support for Qualcomm Technologies LPASS audio block in
+ 	  APQ8016 SOC-based systems.
+ 	  Say Y if you want to use audio devices on MI2S.
+ 
+ config SND_SOC_QCOM_COMMON
+-	depends on SOUNDWIRE
++	tristate
++
++config SND_SOC_QCOM_SDW
+ 	tristate
+ 
+ config SND_SOC_QDSP6_COMMON
+@@ -144,7 +145,7 @@ config SND_SOC_MSM8996
+ 	depends on QCOM_APR
+ 	depends on COMMON_CLK
+ 	select SND_SOC_QDSP6
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
+ 	help
+ 	  Support for Qualcomm Technologies LPASS audio block in
+ 	  APQ8096 SoC-based systems.
+@@ -155,7 +156,7 @@ config SND_SOC_SDM845
+ 	depends on QCOM_APR && I2C && SOUNDWIRE
+ 	depends on COMMON_CLK
+ 	select SND_SOC_QDSP6
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
+ 	select SND_SOC_RT5663
+ 	select SND_SOC_MAX98927
+ 	imply SND_SOC_CROS_EC_CODEC
+@@ -169,7 +170,8 @@ config SND_SOC_SM8250
+ 	depends on QCOM_APR && SOUNDWIRE
+ 	depends on COMMON_CLK
+ 	select SND_SOC_QDSP6
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_SDW
+ 	help
+ 	  To add support for audio on Qualcomm Technologies Inc.
+ 	  SM8250 SoC-based systems.
+@@ -180,7 +182,8 @@ config SND_SOC_SC8280XP
+ 	depends on QCOM_APR && SOUNDWIRE
+ 	depends on COMMON_CLK
+ 	select SND_SOC_QDSP6
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_SDW
+ 	help
+ 	  To add support for audio on Qualcomm Technologies Inc.
+ 	  SC8280XP SoC-based systems.
+@@ -190,7 +193,7 @@ config SND_SOC_SC7180
+ 	tristate "SoC Machine driver for SC7180 boards"
+ 	depends on I2C && GPIOLIB
+ 	depends on SOUNDWIRE || SOUNDWIRE=n
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
+ 	select SND_SOC_LPASS_SC7180
+ 	select SND_SOC_MAX98357A
+ 	select SND_SOC_RT5682_I2C
+@@ -204,7 +207,7 @@ config SND_SOC_SC7180
+ config SND_SOC_SC7280
+ 	tristate "SoC Machine driver for SC7280 boards"
+ 	depends on I2C && SOUNDWIRE
+-	depends on SND_SOC_QCOM_COMMON
++	select SND_SOC_QCOM_COMMON
+ 	select SND_SOC_LPASS_SC7280
+ 	select SND_SOC_MAX98357A
+ 	select SND_SOC_WCD938X_SDW
+diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
+index 8b97172cf990f..254350d9dc069 100644
+--- a/sound/soc/qcom/Makefile
++++ b/sound/soc/qcom/Makefile
+@@ -28,6 +28,7 @@ snd-soc-sdm845-objs := sdm845.o
+ snd-soc-sm8250-objs := sm8250.o
+ snd-soc-sc8280xp-objs := sc8280xp.o
+ snd-soc-qcom-common-objs := common.o
++snd-soc-qcom-sdw-objs := sdw.o
+ 
+ obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
+ obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
+@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
+ obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+ obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
+ obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
++obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
+ 
+ #DSP lib
+ obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
+diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
+index 49c74c1662a3f..96fe80241fb41 100644
+--- a/sound/soc/qcom/common.c
++++ b/sound/soc/qcom/common.c
+@@ -180,120 +180,6 @@ err_put_np:
+ }
+ EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
+ 
+-int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+-			 struct sdw_stream_runtime *sruntime,
+-			 bool *stream_prepared)
+-{
+-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+-	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+-	int ret;
+-
+-	if (!sruntime)
+-		return 0;
+-
+-	switch (cpu_dai->id) {
+-	case WSA_CODEC_DMA_RX_0:
+-	case WSA_CODEC_DMA_RX_1:
+-	case RX_CODEC_DMA_RX_0:
+-	case RX_CODEC_DMA_RX_1:
+-	case TX_CODEC_DMA_TX_0:
+-	case TX_CODEC_DMA_TX_1:
+-	case TX_CODEC_DMA_TX_2:
+-	case TX_CODEC_DMA_TX_3:
+-		break;
+-	default:
+-		return 0;
+-	}
+-
+-	if (*stream_prepared) {
+-		sdw_disable_stream(sruntime);
+-		sdw_deprepare_stream(sruntime);
+-		*stream_prepared = false;
+-	}
+-
+-	ret = sdw_prepare_stream(sruntime);
+-	if (ret)
+-		return ret;
+-
+-	/**
+-	 * NOTE: there is a strict hw requirement about the ordering of port
+-	 * enables and actual WSA881x PA enable. PA enable should only happen
+-	 * after soundwire ports are enabled if not DC on the line is
+-	 * accumulated resulting in Click/Pop Noise
+-	 * PA enable/mute are handled as part of codec DAPM and digital mute.
+-	 */
+-
+-	ret = sdw_enable_stream(sruntime);
+-	if (ret) {
+-		sdw_deprepare_stream(sruntime);
+-		return ret;
+-	}
+-	*stream_prepared  = true;
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
+-
+-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+-			   struct snd_pcm_hw_params *params,
+-			   struct sdw_stream_runtime **psruntime)
+-{
+-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+-	struct snd_soc_dai *codec_dai;
+-	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+-	struct sdw_stream_runtime *sruntime;
+-	int i;
+-
+-	switch (cpu_dai->id) {
+-	case WSA_CODEC_DMA_RX_0:
+-	case RX_CODEC_DMA_RX_0:
+-	case RX_CODEC_DMA_RX_1:
+-	case TX_CODEC_DMA_TX_0:
+-	case TX_CODEC_DMA_TX_1:
+-	case TX_CODEC_DMA_TX_2:
+-	case TX_CODEC_DMA_TX_3:
+-		for_each_rtd_codec_dais(rtd, i, codec_dai) {
+-			sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
+-			if (sruntime != ERR_PTR(-ENOTSUPP))
+-				*psruntime = sruntime;
+-		}
+-		break;
+-	}
+-
+-	return 0;
+-
+-}
+-EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
+-
+-int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+-			 struct sdw_stream_runtime *sruntime, bool *stream_prepared)
+-{
+-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+-	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+-
+-	switch (cpu_dai->id) {
+-	case WSA_CODEC_DMA_RX_0:
+-	case WSA_CODEC_DMA_RX_1:
+-	case RX_CODEC_DMA_RX_0:
+-	case RX_CODEC_DMA_RX_1:
+-	case TX_CODEC_DMA_TX_0:
+-	case TX_CODEC_DMA_TX_1:
+-	case TX_CODEC_DMA_TX_2:
+-	case TX_CODEC_DMA_TX_3:
+-		if (sruntime && *stream_prepared) {
+-			sdw_disable_stream(sruntime);
+-			sdw_deprepare_stream(sruntime);
+-			*stream_prepared = false;
+-		}
+-		break;
+-	default:
+-		break;
+-	}
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
+-
+ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ 			    struct snd_soc_jack *jack, bool *jack_setup)
+ {
+diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
+index 3ef5bb6d12df7..d7f80ee5ae26a 100644
+--- a/sound/soc/qcom/common.h
++++ b/sound/soc/qcom/common.h
+@@ -5,19 +5,9 @@
+ #define __QCOM_SND_COMMON_H__
+ 
+ #include <sound/soc.h>
+-#include <linux/soundwire/sdw.h>
+ 
+ int qcom_snd_parse_of(struct snd_soc_card *card);
+ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ 			    struct snd_soc_jack *jack, bool *jack_setup);
+ 
+-int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+-			 struct sdw_stream_runtime *runtime,
+-			 bool *stream_prepared);
+-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+-			   struct snd_pcm_hw_params *params,
+-			   struct sdw_stream_runtime **psruntime);
+-int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+-			 struct sdw_stream_runtime *sruntime,
+-			 bool *stream_prepared);
+ #endif
+diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
+index 54353842dc07f..dbdaaa85ce481 100644
+--- a/sound/soc/qcom/lpass-cpu.c
++++ b/sound/soc/qcom/lpass-cpu.c
+@@ -1037,10 +1037,11 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
+ 					struct lpass_data *data)
+ {
+ 	struct device_node *node;
+-	int ret, id;
++	int ret, i, id;
+ 
+ 	/* Allow all channels by default for backwards compatibility */
+-	for (id = 0; id < data->variant->num_dai; id++) {
++	for (i = 0; i < data->variant->num_dai; i++) {
++		id = data->variant->dai_driver[i].id;
+ 		data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
+ 		data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
+ 	}
+diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
+index ade44ad7c585a..14d9fea33d16a 100644
+--- a/sound/soc/qcom/sc8280xp.c
++++ b/sound/soc/qcom/sc8280xp.c
+@@ -12,6 +12,7 @@
+ #include <linux/input-event-codes.h>
+ #include "qdsp6/q6afe.h"
+ #include "common.h"
++#include "sdw.h"
+ 
+ #define DRIVER_NAME		"sc8280xp"
+ 
+diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c
+new file mode 100644
+index 0000000000000..10249519a39e5
+--- /dev/null
++++ b/sound/soc/qcom/sdw.c
+@@ -0,0 +1,123 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018, Linaro Limited.
++// Copyright (c) 2018, The Linux Foundation. All rights reserved.
++
++#include <linux/module.h>
++#include <sound/soc.h>
++#include "qdsp6/q6afe.h"
++#include "sdw.h"
++
++int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
++			 struct sdw_stream_runtime *sruntime,
++			 bool *stream_prepared)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
++	int ret;
++
++	if (!sruntime)
++		return 0;
++
++	switch (cpu_dai->id) {
++	case WSA_CODEC_DMA_RX_0:
++	case WSA_CODEC_DMA_RX_1:
++	case RX_CODEC_DMA_RX_0:
++	case RX_CODEC_DMA_RX_1:
++	case TX_CODEC_DMA_TX_0:
++	case TX_CODEC_DMA_TX_1:
++	case TX_CODEC_DMA_TX_2:
++	case TX_CODEC_DMA_TX_3:
++		break;
++	default:
++		return 0;
++	}
++
++	if (*stream_prepared) {
++		sdw_disable_stream(sruntime);
++		sdw_deprepare_stream(sruntime);
++		*stream_prepared = false;
++	}
++
++	ret = sdw_prepare_stream(sruntime);
++	if (ret)
++		return ret;
++
++	/**
++	 * NOTE: there is a strict hw requirement about the ordering of port
++	 * enables and actual WSA881x PA enable. PA enable should only happen
++	 * after soundwire ports are enabled if not DC on the line is
++	 * accumulated resulting in Click/Pop Noise
++	 * PA enable/mute are handled as part of codec DAPM and digital mute.
++	 */
++
++	ret = sdw_enable_stream(sruntime);
++	if (ret) {
++		sdw_deprepare_stream(sruntime);
++		return ret;
++	}
++	*stream_prepared  = true;
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
++
++int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
++			   struct snd_pcm_hw_params *params,
++			   struct sdw_stream_runtime **psruntime)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_dai *codec_dai;
++	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
++	struct sdw_stream_runtime *sruntime;
++	int i;
++
++	switch (cpu_dai->id) {
++	case WSA_CODEC_DMA_RX_0:
++	case RX_CODEC_DMA_RX_0:
++	case RX_CODEC_DMA_RX_1:
++	case TX_CODEC_DMA_TX_0:
++	case TX_CODEC_DMA_TX_1:
++	case TX_CODEC_DMA_TX_2:
++	case TX_CODEC_DMA_TX_3:
++		for_each_rtd_codec_dais(rtd, i, codec_dai) {
++			sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
++			if (sruntime != ERR_PTR(-ENOTSUPP))
++				*psruntime = sruntime;
++		}
++		break;
++	}
++
++	return 0;
++
++}
++EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
++
++int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
++			 struct sdw_stream_runtime *sruntime, bool *stream_prepared)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
++
++	switch (cpu_dai->id) {
++	case WSA_CODEC_DMA_RX_0:
++	case WSA_CODEC_DMA_RX_1:
++	case RX_CODEC_DMA_RX_0:
++	case RX_CODEC_DMA_RX_1:
++	case TX_CODEC_DMA_TX_0:
++	case TX_CODEC_DMA_TX_1:
++	case TX_CODEC_DMA_TX_2:
++	case TX_CODEC_DMA_TX_3:
++		if (sruntime && *stream_prepared) {
++			sdw_disable_stream(sruntime);
++			sdw_deprepare_stream(sruntime);
++			*stream_prepared = false;
++		}
++		break;
++	default:
++		break;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
++MODULE_LICENSE("GPL v2");
+diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h
+new file mode 100644
+index 0000000000000..d74cbb84da138
+--- /dev/null
++++ b/sound/soc/qcom/sdw.h
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++// Copyright (c) 2018, The Linux Foundation. All rights reserved.
++
++#ifndef __QCOM_SND_SDW_H__
++#define __QCOM_SND_SDW_H__
++
++#include <linux/soundwire/sdw.h>
++
++int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
++			 struct sdw_stream_runtime *runtime,
++			 bool *stream_prepared);
++int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
++			   struct snd_pcm_hw_params *params,
++			   struct sdw_stream_runtime **psruntime);
++int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
++			 struct sdw_stream_runtime *sruntime,
++			 bool *stream_prepared);
++#endif
+diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
+index 8dbe9ef41b1c9..9626a9ef78c23 100644
+--- a/sound/soc/qcom/sm8250.c
++++ b/sound/soc/qcom/sm8250.c
+@@ -12,6 +12,7 @@
+ #include <linux/input-event-codes.h>
+ #include "qdsp6/q6afe.h"
+ #include "common.h"
++#include "sdw.h"
+ 
+ #define DRIVER_NAME		"sm8250"
+ #define MI2S_BCLK_RATE		1536000
+diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
+index 41ac7185b42b6..4727043fd7458 100644
+--- a/sound/usb/implicit.c
++++ b/sound/usb/implicit.c
+@@ -471,7 +471,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
+ 	subs = find_matching_substream(chip, stream, target->sync_ep,
+ 				       target->fmt_type);
+ 	if (!subs)
+-		return sync_fmt;
++		goto end;
+ 
+ 	high_score = 0;
+ 	list_for_each_entry(fp, &subs->fmt_list, list) {
+@@ -485,6 +485,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
+ 		}
+ 	}
+ 
++ end:
+ 	if (fixed_rate)
+ 		*fixed_rate = snd_usb_pcm_has_fixed_rate(subs);
+ 	return sync_fmt;
+diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
+index 99a66d0ef5b26..2c5765cbed2d6 100644
+--- a/sound/usb/pcm.c
++++ b/sound/usb/pcm.c
+@@ -160,9 +160,12 @@ find_substream_format(struct snd_usb_substream *subs,
+ bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs)
+ {
+ 	const struct audioformat *fp;
+-	struct snd_usb_audio *chip = subs->stream->chip;
++	struct snd_usb_audio *chip;
+ 	int rate = -1;
+ 
++	if (!subs)
++		return false;
++	chip = subs->stream->chip;
+ 	if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE))
+ 		return false;
+ 	list_for_each_entry(fp, &subs->fmt_list, list) {
+@@ -525,6 +528,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
+ 		if (snd_usb_endpoint_compatible(chip, subs->data_endpoint,
+ 						fmt, hw_params))
+ 			goto unlock;
++		if (stop_endpoints(subs, false))
++			sync_pending_stops(subs);
+ 		close_endpoints(chip, subs);
+ 	}
+ 
+@@ -935,8 +940,13 @@ get_sync_ep_from_substream(struct snd_usb_substream *subs)
+ 			continue;
+ 		/* for the implicit fb, check the sync ep as well */
+ 		ep = snd_usb_get_endpoint(chip, fp->sync_ep);
+-		if (ep && ep->cur_audiofmt)
+-			return ep;
++		if (ep && ep->cur_audiofmt) {
++			/* ditto, if the sync (data) ep is used by others,
++			 * this stream is restricted by the sync ep
++			 */
++			if (ep != subs->sync_endpoint || ep->opened > 1)
++				return ep;
++		}
+ 	}
+ 	return NULL;
+ }
+diff --git a/sound/usb/stream.c b/sound/usb/stream.c
+index f75601ca2d525..f10f4e6d3fb85 100644
+--- a/sound/usb/stream.c
++++ b/sound/usb/stream.c
+@@ -1222,6 +1222,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
+ 			if (err < 0)
+ 				return err;
+ 		}
++
++		/* try to set the interface... */
++		usb_set_interface(chip->dev, iface_no, 0);
++		snd_usb_init_pitch(chip, fp);
++		snd_usb_init_sample_rate(chip, fp, fp->rate_max);
++		usb_set_interface(chip->dev, iface_no, altno);
+ 	}
+ 	return 0;
+ }
+diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
+index 5fc5b8029bff9..7380093ba9e7d 100644
+--- a/tools/include/nolibc/arch-mips.h
++++ b/tools/include/nolibc/arch-mips.h
+@@ -192,6 +192,7 @@ struct sys_stat_struct {
+ __asm__ (".section .text\n"
+     ".weak __start\n"
+     ".set nomips16\n"
++    ".set push\n"
+     ".set    noreorder\n"
+     ".option pic0\n"
+     ".ent __start\n"
+@@ -210,6 +211,7 @@ __asm__ (".section .text\n"
+     "li $v0, 4001\n"              // NR_exit == 4001
+     "syscall\n"
+     ".end __start\n"
++    ".set pop\n"
+     "");
+ 
+ #endif // _NOLIBC_ARCH_MIPS_H
+diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
+index ba04771cb3a34..a3bdd9803f8cb 100644
+--- a/tools/include/nolibc/arch-riscv.h
++++ b/tools/include/nolibc/arch-riscv.h
+@@ -11,13 +11,13 @@
+ #define O_RDONLY            0
+ #define O_WRONLY            1
+ #define O_RDWR              2
+-#define O_CREAT         0x100
+-#define O_EXCL          0x200
+-#define O_NOCTTY        0x400
+-#define O_TRUNC        0x1000
+-#define O_APPEND       0x2000
+-#define O_NONBLOCK     0x4000
+-#define O_DIRECTORY  0x200000
++#define O_CREAT          0x40
++#define O_EXCL           0x80
++#define O_NOCTTY        0x100
++#define O_TRUNC         0x200
++#define O_APPEND        0x400
++#define O_NONBLOCK      0x800
++#define O_DIRECTORY   0x10000
+ 
+ struct sys_stat_struct {
+ 	unsigned long	st_dev;		/* Device.  */
+diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
+index ebfab2ca17024..40dd52acc48ae 100644
+--- a/tools/perf/builtin-kmem.c
++++ b/tools/perf/builtin-kmem.c
+@@ -26,6 +26,7 @@
+ #include "util/string2.h"
+ 
+ #include <linux/kernel.h>
++#include <linux/numa.h>
+ #include <linux/rbtree.h>
+ #include <linux/string.h>
+ #include <linux/zalloc.h>
+@@ -184,22 +185,33 @@ static int evsel__process_alloc_event(struct evsel *evsel, struct perf_sample *s
+ 	total_allocated += bytes_alloc;
+ 
+ 	nr_allocs++;
+-	return 0;
+-}
+ 
+-static int evsel__process_alloc_node_event(struct evsel *evsel, struct perf_sample *sample)
+-{
+-	int ret = evsel__process_alloc_event(evsel, sample);
++	/*
++	 * Commit 11e9734bcb6a ("mm/slab_common: unify NUMA and UMA
++	 * version of tracepoints") adds the field "node" into the
++	 * tracepoints 'kmalloc' and 'kmem_cache_alloc'.
++	 *
++	 * The legacy tracepoints 'kmalloc_node' and 'kmem_cache_alloc_node'
++	 * also contain the field "node".
++	 *
++	 * If the tracepoint contains the field "node" the tool stats the
++	 * cross allocation.
++	 */
++	if (evsel__field(evsel, "node")) {
++		int node1, node2;
+ 
+-	if (!ret) {
+-		int node1 = cpu__get_node((struct perf_cpu){.cpu = sample->cpu}),
+-		    node2 = evsel__intval(evsel, sample, "node");
++		node1 = cpu__get_node((struct perf_cpu){.cpu = sample->cpu});
++		node2 = evsel__intval(evsel, sample, "node");
+ 
+-		if (node1 != node2)
++		/*
++		 * If the field "node" is NUMA_NO_NODE (-1), we don't take it
++		 * as a cross allocation.
++		 */
++		if ((node2 != NUMA_NO_NODE) && (node1 != node2))
+ 			nr_cross_allocs++;
+ 	}
+ 
+-	return ret;
++	return 0;
+ }
+ 
+ static int ptr_cmp(void *, void *);
+@@ -1368,8 +1380,8 @@ static int __cmd_kmem(struct perf_session *session)
+ 		/* slab allocator */
+ 		{ "kmem:kmalloc",		evsel__process_alloc_event, },
+ 		{ "kmem:kmem_cache_alloc",	evsel__process_alloc_event, },
+-		{ "kmem:kmalloc_node",		evsel__process_alloc_node_event, },
+-		{ "kmem:kmem_cache_alloc_node", evsel__process_alloc_node_event, },
++		{ "kmem:kmalloc_node",		evsel__process_alloc_event, },
++		{ "kmem:kmem_cache_alloc_node", evsel__process_alloc_event, },
+ 		{ "kmem:kfree",			evsel__process_free_event, },
+ 		{ "kmem:kmem_cache_free",	evsel__process_free_event, },
+ 		/* page allocator */
+@@ -1823,6 +1835,19 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
+ 	return 0;
+ }
+ 
++static bool slab_legacy_tp_is_exposed(void)
++{
++	/*
++	 * The tracepoints "kmem:kmalloc_node" and
++	 * "kmem:kmem_cache_alloc_node" have been removed on the latest
++	 * kernel, if the tracepoint "kmem:kmalloc_node" is existed it
++	 * means the tool is running on an old kernel, we need to
++	 * rollback to support these legacy tracepoints.
++	 */
++	return IS_ERR(trace_event__tp_format("kmem", "kmalloc_node")) ?
++		false : true;
++}
++
+ static int __cmd_record(int argc, const char **argv)
+ {
+ 	const char * const record_args[] = {
+@@ -1830,22 +1855,28 @@ static int __cmd_record(int argc, const char **argv)
+ 	};
+ 	const char * const slab_events[] = {
+ 	"-e", "kmem:kmalloc",
+-	"-e", "kmem:kmalloc_node",
+ 	"-e", "kmem:kfree",
+ 	"-e", "kmem:kmem_cache_alloc",
+-	"-e", "kmem:kmem_cache_alloc_node",
+ 	"-e", "kmem:kmem_cache_free",
+ 	};
++	const char * const slab_legacy_events[] = {
++	"-e", "kmem:kmalloc_node",
++	"-e", "kmem:kmem_cache_alloc_node",
++	};
+ 	const char * const page_events[] = {
+ 	"-e", "kmem:mm_page_alloc",
+ 	"-e", "kmem:mm_page_free",
+ 	};
+ 	unsigned int rec_argc, i, j;
+ 	const char **rec_argv;
++	unsigned int slab_legacy_tp_exposed = slab_legacy_tp_is_exposed();
+ 
+ 	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
+-	if (kmem_slab)
++	if (kmem_slab) {
+ 		rec_argc += ARRAY_SIZE(slab_events);
++		if (slab_legacy_tp_exposed)
++			rec_argc += ARRAY_SIZE(slab_legacy_events);
++	}
+ 	if (kmem_page)
+ 		rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */
+ 
+@@ -1860,6 +1891,10 @@ static int __cmd_record(int argc, const char **argv)
+ 	if (kmem_slab) {
+ 		for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++)
+ 			rec_argv[i] = strdup(slab_events[j]);
++		if (slab_legacy_tp_exposed) {
++			for (j = 0; j < ARRAY_SIZE(slab_legacy_events); j++, i++)
++				rec_argv[i] = strdup(slab_legacy_events[j]);
++		}
+ 	}
+ 	if (kmem_page) {
+ 		rec_argv[i++] = strdup("-g");
+diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
+index 3dcf6aed1ef71..97b17f8941dc0 100644
+--- a/tools/perf/builtin-trace.c
++++ b/tools/perf/builtin-trace.c
+@@ -17,7 +17,9 @@
+ #include "util/record.h"
+ #include <traceevent/event-parse.h>
+ #include <api/fs/tracing_path.h>
++#ifdef HAVE_LIBBPF_SUPPORT
+ #include <bpf/bpf.h>
++#endif
+ #include "util/bpf_map.h"
+ #include "util/rlimit.h"
+ #include "builtin.h"
+diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
+index 46ada5ec3f9a2..47062f459ccd6 100644
+--- a/tools/perf/util/auxtrace.c
++++ b/tools/perf/util/auxtrace.c
+@@ -2610,7 +2610,7 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
+ 				*size = sym->start - *start;
+ 			if (idx > 0) {
+ 				if (*size)
+-					return 1;
++					return 0;
+ 			} else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
+ 				print_duplicate_syms(dso, sym_name);
+ 				return -EINVAL;
+diff --git a/tools/perf/util/bpf_counter.h b/tools/perf/util/bpf_counter.h
+index 4dbf26408b692..c6d21c07b14cd 100644
+--- a/tools/perf/util/bpf_counter.h
++++ b/tools/perf/util/bpf_counter.h
+@@ -4,9 +4,12 @@
+ 
+ #include <linux/list.h>
+ #include <sys/resource.h>
++
++#ifdef HAVE_LIBBPF_SUPPORT
+ #include <bpf/bpf.h>
+ #include <bpf/btf.h>
+ #include <bpf/libbpf.h>
++#endif
+ 
+ struct evsel;
+ struct target;
+@@ -87,6 +90,8 @@ static inline void set_max_rlimit(void)
+ 	setrlimit(RLIMIT_MEMLOCK, &rinf);
+ }
+ 
++#ifdef HAVE_BPF_SKEL
++
+ static inline __u32 bpf_link_get_id(int fd)
+ {
+ 	struct bpf_link_info link_info = { .id = 0, };
+@@ -127,5 +132,6 @@ static inline int bperf_trigger_reading(int prog_fd, int cpu)
+ 
+ 	return bpf_prog_test_run_opts(prog_fd, &opts);
+ }
++#endif /* HAVE_BPF_SKEL */
+ 
+ #endif /* __PERF_BPF_COUNTER_H */
+diff --git a/tools/testing/memblock/internal.h b/tools/testing/memblock/internal.h
+index fdb7f5db73082..85973e55489e7 100644
+--- a/tools/testing/memblock/internal.h
++++ b/tools/testing/memblock/internal.h
+@@ -15,6 +15,10 @@ bool mirrored_kernelcore = false;
+ 
+ struct page {};
+ 
++void __free_pages_core(struct page *page, unsigned int order)
++{
++}
++
+ void memblock_free_pages(struct page *page, unsigned long pfn,
+ 			 unsigned int order)
+ {
+diff --git a/tools/testing/selftests/net/af_unix/test_unix_oob.c b/tools/testing/selftests/net/af_unix/test_unix_oob.c
+index b57e91e1c3f28..532459a15067c 100644
+--- a/tools/testing/selftests/net/af_unix/test_unix_oob.c
++++ b/tools/testing/selftests/net/af_unix/test_unix_oob.c
+@@ -124,7 +124,7 @@ void producer(struct sockaddr_un *consumer_addr)
+ 
+ 	wait_for_signal(pipefd[0]);
+ 	if (connect(cfd, (struct sockaddr *)consumer_addr,
+-		     sizeof(struct sockaddr)) != 0) {
++		     sizeof(*consumer_addr)) != 0) {
+ 		perror("Connect failed");
+ 		kill(0, SIGTERM);
+ 		exit(1);
+diff --git a/tools/testing/selftests/net/l2_tos_ttl_inherit.sh b/tools/testing/selftests/net/l2_tos_ttl_inherit.sh
+index dca1e6f777a89..f11756e7df2f9 100755
+--- a/tools/testing/selftests/net/l2_tos_ttl_inherit.sh
++++ b/tools/testing/selftests/net/l2_tos_ttl_inherit.sh
+@@ -12,19 +12,27 @@
+ # In addition this script also checks if forcing a specific field in the
+ # outer header is working.
+ 
++# Return 4 by default (Kselftest SKIP code)
++ERR=4
++
+ if [ "$(id -u)" != "0" ]; then
+ 	echo "Please run as root."
+-	exit 0
++	exit $ERR
+ fi
+ if ! which tcpdump > /dev/null 2>&1; then
+ 	echo "No tcpdump found. Required for this test."
+-	exit 0
++	exit $ERR
+ fi
+ 
+ expected_tos="0x00"
+ expected_ttl="0"
+ failed=false
+ 
++readonly NS0=$(mktemp -u ns0-XXXXXXXX)
++readonly NS1=$(mktemp -u ns1-XXXXXXXX)
++
++RUN_NS0="ip netns exec ${NS0}"
++
+ get_random_tos() {
+ 	# Get a random hex tos value between 0x00 and 0xfc, a multiple of 4
+ 	echo "0x$(tr -dc '0-9a-f' < /dev/urandom | head -c 1)\
+@@ -61,7 +69,6 @@ setup() {
+ 	local vlan="$5"
+ 	local test_tos="0x00"
+ 	local test_ttl="0"
+-	local ns="ip netns exec testing"
+ 
+ 	# We don't want a test-tos of 0x00,
+ 	# because this is the value that we get when no tos is set.
+@@ -94,14 +101,15 @@ setup() {
+ 	printf "│%7s │%6s │%6s │%13s │%13s │%6s │" \
+ 	"$type" "$outer" "$inner" "$tos" "$ttl" "$vlan"
+ 
+-	# Create 'testing' netns, veth pair and connect main ns with testing ns
+-	ip netns add testing
+-	ip link add type veth
+-	ip link set veth1 netns testing
+-	ip link set veth0 up
+-	$ns ip link set veth1 up
+-	ip addr flush dev veth0
+-	$ns ip addr flush dev veth1
++	# Create netns NS0 and NS1 and connect them with a veth pair
++	ip netns add "${NS0}"
++	ip netns add "${NS1}"
++	ip link add name veth0 netns "${NS0}" type veth \
++		peer name veth1 netns "${NS1}"
++	ip -netns "${NS0}" link set dev veth0 up
++	ip -netns "${NS1}" link set dev veth1 up
++	ip -netns "${NS0}" address flush dev veth0
++	ip -netns "${NS1}" address flush dev veth1
+ 
+ 	local local_addr1=""
+ 	local local_addr2=""
+@@ -127,51 +135,59 @@ setup() {
+ 		if [ "$type" = "gre" ]; then
+ 			type="gretap"
+ 		fi
+-		ip addr add 198.18.0.1/24 dev veth0
+-		$ns ip addr add 198.18.0.2/24 dev veth1
+-		ip link add name tep0 type $type $local_addr1 remote \
+-		198.18.0.2 tos $test_tos ttl $test_ttl $vxlan $geneve
+-		$ns ip link add name tep1 type $type $local_addr2 remote \
+-		198.18.0.1 tos $test_tos ttl $test_ttl $vxlan $geneve
++		ip -netns "${NS0}" address add 198.18.0.1/24 dev veth0
++		ip -netns "${NS1}" address add 198.18.0.2/24 dev veth1
++		ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \
++			remote 198.18.0.2 tos $test_tos ttl $test_ttl         \
++			$vxlan $geneve
++		ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \
++			remote 198.18.0.1 tos $test_tos ttl $test_ttl         \
++			$vxlan $geneve
+ 	elif [ "$outer" = "6" ]; then
+ 		if [ "$type" = "gre" ]; then
+ 			type="ip6gretap"
+ 		fi
+-		ip addr add fdd1:ced0:5d88:3fce::1/64 dev veth0
+-		$ns ip addr add fdd1:ced0:5d88:3fce::2/64 dev veth1
+-		ip link add name tep0 type $type $local_addr1 \
+-		remote fdd1:ced0:5d88:3fce::2 tos $test_tos ttl $test_ttl \
+-		$vxlan $geneve
+-		$ns ip link add name tep1 type $type $local_addr2 \
+-		remote fdd1:ced0:5d88:3fce::1 tos $test_tos ttl $test_ttl \
+-		$vxlan $geneve
++		ip -netns "${NS0}" address add fdd1:ced0:5d88:3fce::1/64 \
++			dev veth0 nodad
++		ip -netns "${NS1}" address add fdd1:ced0:5d88:3fce::2/64 \
++			dev veth1 nodad
++		ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \
++			remote fdd1:ced0:5d88:3fce::2 tos $test_tos           \
++			ttl $test_ttl $vxlan $geneve
++		ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \
++			remote fdd1:ced0:5d88:3fce::1 tos $test_tos           \
++			ttl $test_ttl $vxlan $geneve
+ 	fi
+ 
+ 	# Bring L2-tunnel link up and create VLAN on top
+-	ip link set tep0 up
+-	$ns ip link set tep1 up
+-	ip addr flush dev tep0
+-	$ns ip addr flush dev tep1
++	ip -netns "${NS0}" link set tep0 up
++	ip -netns "${NS1}" link set tep1 up
++	ip -netns "${NS0}" address flush dev tep0
++	ip -netns "${NS1}" address flush dev tep1
+ 	local parent
+ 	if $vlan; then
+ 		parent="vlan99-"
+-		ip link add link tep0 name ${parent}0 type vlan id 99
+-		$ns ip link add link tep1 name ${parent}1 type vlan id 99
+-		ip link set ${parent}0 up
+-		$ns ip link set ${parent}1 up
+-		ip addr flush dev ${parent}0
+-		$ns ip addr flush dev ${parent}1
++		ip -netns "${NS0}" link add link tep0 name ${parent}0 \
++			type vlan id 99
++		ip -netns "${NS1}" link add link tep1 name ${parent}1 \
++			type vlan id 99
++		ip -netns "${NS0}" link set dev ${parent}0 up
++		ip -netns "${NS1}" link set dev ${parent}1 up
++		ip -netns "${NS0}" address flush dev ${parent}0
++		ip -netns "${NS1}" address flush dev ${parent}1
+ 	else
+ 		parent="tep"
+ 	fi
+ 
+ 	# Assign inner IPv4/IPv6 addresses
+ 	if [ "$inner" = "4" ] || [ "$inner" = "other" ]; then
+-		ip addr add 198.19.0.1/24 brd + dev ${parent}0
+-		$ns ip addr add 198.19.0.2/24 brd + dev ${parent}1
++		ip -netns "${NS0}" address add 198.19.0.1/24 brd + dev ${parent}0
++		ip -netns "${NS1}" address add 198.19.0.2/24 brd + dev ${parent}1
+ 	elif [ "$inner" = "6" ]; then
+-		ip addr add fdd4:96cf:4eae:443b::1/64 dev ${parent}0
+-		$ns ip addr add fdd4:96cf:4eae:443b::2/64 dev ${parent}1
++		ip -netns "${NS0}" address add fdd4:96cf:4eae:443b::1/64 \
++			dev ${parent}0 nodad
++		ip -netns "${NS1}" address add fdd4:96cf:4eae:443b::2/64 \
++			dev ${parent}1 nodad
+ 	fi
+ }
+ 
+@@ -192,10 +208,10 @@ verify() {
+ 		ping_dst="198.19.0.3" # Generates ARPs which are not IPv4/IPv6
+ 	fi
+ 	if [ "$tos_ttl" = "inherit" ]; then
+-		ping -i 0.1 $ping_dst -Q "$expected_tos" -t "$expected_ttl" \
+-		2>/dev/null 1>&2 & ping_pid="$!"
++		${RUN_NS0} ping -i 0.1 $ping_dst -Q "$expected_tos"          \
++			 -t "$expected_ttl" 2>/dev/null 1>&2 & ping_pid="$!"
+ 	else
+-		ping -i 0.1 $ping_dst 2>/dev/null 1>&2 & ping_pid="$!"
++		${RUN_NS0} ping -i 0.1 $ping_dst 2>/dev/null 1>&2 & ping_pid="$!"
+ 	fi
+ 	local tunnel_type_offset tunnel_type_proto req_proto_offset req_offset
+ 	if [ "$type" = "gre" ]; then
+@@ -216,10 +232,12 @@ verify() {
+ 				req_proto_offset="$((req_proto_offset + 4))"
+ 				req_offset="$((req_offset + 4))"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip[$req_proto_offset] = 0x01 and \
+-			ip[$req_offset] = 0x08 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip[$req_proto_offset] = 0x01 and              \
++				ip[$req_offset] = 0x08 2>/dev/null            \
++				| head -n 1)"
+ 		elif [ "$inner" = "6" ]; then
+ 			req_proto_offset="44"
+ 			req_offset="78"
+@@ -231,10 +249,12 @@ verify() {
+ 				req_proto_offset="$((req_proto_offset + 4))"
+ 				req_offset="$((req_offset + 4))"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip[$req_proto_offset] = 0x3a and \
+-			ip[$req_offset] = 0x80 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip[$req_proto_offset] = 0x3a and              \
++				ip[$req_offset] = 0x80 2>/dev/null            \
++				| head -n 1)"
+ 		elif [ "$inner" = "other" ]; then
+ 			req_proto_offset="36"
+ 			req_offset="45"
+@@ -250,11 +270,13 @@ verify() {
+ 				expected_tos="0x00"
+ 				expected_ttl="64"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip[$req_proto_offset] = 0x08 and \
+-			ip[$((req_proto_offset + 1))] = 0x06 and \
+-			ip[$req_offset] = 0x01 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip[$req_proto_offset] = 0x08 and              \
++				ip[$((req_proto_offset + 1))] = 0x06 and      \
++				ip[$req_offset] = 0x01 2>/dev/null            \
++				| head -n 1)"
+ 		fi
+ 	elif [ "$outer" = "6" ]; then
+ 		if [ "$type" = "gre" ]; then
+@@ -273,10 +295,12 @@ verify() {
+ 				req_proto_offset="$((req_proto_offset + 4))"
+ 				req_offset="$((req_offset + 4))"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip6[$req_proto_offset] = 0x01 and \
+-			ip6[$req_offset] = 0x08 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip6[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip6[$req_proto_offset] = 0x01 and             \
++				ip6[$req_offset] = 0x08 2>/dev/null           \
++				| head -n 1)"
+ 		elif [ "$inner" = "6" ]; then
+ 			local req_proto_offset="72"
+ 			local req_offset="106"
+@@ -288,10 +312,12 @@ verify() {
+ 				req_proto_offset="$((req_proto_offset + 4))"
+ 				req_offset="$((req_offset + 4))"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip6[$req_proto_offset] = 0x3a and \
+-			ip6[$req_offset] = 0x80 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip6[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip6[$req_proto_offset] = 0x3a and             \
++				ip6[$req_offset] = 0x80 2>/dev/null           \
++				| head -n 1)"
+ 		elif [ "$inner" = "other" ]; then
+ 			local req_proto_offset="64"
+ 			local req_offset="73"
+@@ -307,15 +333,17 @@ verify() {
+ 				expected_tos="0x00"
+ 				expected_ttl="64"
+ 			fi
+-			out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
+-			ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+-			ip6[$req_proto_offset] = 0x08 and \
+-			ip6[$((req_proto_offset + 1))] = 0x06 and \
+-			ip6[$req_offset] = 0x01 2>/dev/null | head -n 1)"
++			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
++				-i veth0 -n                                   \
++				ip6[$tunnel_type_offset] = $tunnel_type_proto and \
++				ip6[$req_proto_offset] = 0x08 and             \
++				ip6[$((req_proto_offset + 1))] = 0x06 and     \
++				ip6[$req_offset] = 0x01 2>/dev/null           \
++				| head -n 1)"
+ 		fi
+ 	fi
+ 	kill -9 $ping_pid
+-	wait $ping_pid 2>/dev/null
++	wait $ping_pid 2>/dev/null || true
+ 	result="FAIL"
+ 	if [ "$outer" = "4" ]; then
+ 		captured_ttl="$(get_field "ttl" "$out")"
+@@ -351,11 +379,35 @@ verify() {
+ }
+ 
+ cleanup() {
+-	ip link del veth0 2>/dev/null
+-	ip netns del testing 2>/dev/null
+-	ip link del tep0 2>/dev/null
++	ip netns del "${NS0}" 2>/dev/null
++	ip netns del "${NS1}" 2>/dev/null
+ }
+ 
++exit_handler() {
++	# Don't exit immediately if one of the intermediate commands fails.
++	# We might be called at the end of the script, when the network
++	# namespaces have already been deleted. So cleanup() may fail, but we
++	# still need to run until 'exit $ERR' or the script won't return the
++	# correct error code.
++	set +e
++
++	cleanup
++
++	exit $ERR
++}
++
++# Restore the default SIGINT handler (just in case) and exit.
++# The exit handler will take care of cleaning everything up.
++interrupted() {
++	trap - INT
++
++	exit $ERR
++}
++
++set -e
++trap exit_handler EXIT
++trap interrupted INT
++
+ printf "┌────────┬───────┬───────┬──────────────┬"
+ printf "──────────────┬───────┬────────┐\n"
+ for type in gre vxlan geneve; do
+@@ -385,6 +437,10 @@ done
+ printf "└────────┴───────┴───────┴──────────────┴"
+ printf "──────────────┴───────┴────────┘\n"
+ 
++# All tests done.
++# Set ERR appropriately: it will be returned by the exit handler.
+ if $failed; then
+-	exit 1
++	ERR=1
++else
++	ERR=0
+ fi
+diff --git a/tools/testing/selftests/netfilter/nft_trans_stress.sh b/tools/testing/selftests/netfilter/nft_trans_stress.sh
+index a7f62ad4f6611..2ffba45a78bf4 100755
+--- a/tools/testing/selftests/netfilter/nft_trans_stress.sh
++++ b/tools/testing/selftests/netfilter/nft_trans_stress.sh
+@@ -10,12 +10,20 @@
+ ksft_skip=4
+ 
+ testns=testns-$(mktemp -u "XXXXXXXX")
++tmp=""
+ 
+ tables="foo bar baz quux"
+ global_ret=0
+ eret=0
+ lret=0
+ 
++cleanup() {
++	ip netns pids "$testns" | xargs kill 2>/dev/null
++	ip netns del "$testns"
++
++	rm -f "$tmp"
++}
++
+ check_result()
+ {
+ 	local r=$1
+@@ -43,6 +51,7 @@ if [ $? -ne 0 ];then
+ 	exit $ksft_skip
+ fi
+ 
++trap cleanup EXIT
+ tmp=$(mktemp)
+ 
+ for table in $tables; do
+@@ -139,11 +148,4 @@ done
+ 
+ check_result $lret "add/delete with nftrace enabled"
+ 
+-pkill -9 ping
+-
+-wait
+-
+-rm -f "$tmp"
+-ip netns del "$testns"
+-
+ exit $global_ret
+diff --git a/tools/testing/selftests/netfilter/settings b/tools/testing/selftests/netfilter/settings
+new file mode 100644
+index 0000000000000..6091b45d226ba
+--- /dev/null
++++ b/tools/testing/selftests/netfilter/settings
+@@ -0,0 +1 @@
++timeout=120


             reply	other threads:[~2023-01-18 11:30 UTC|newest]

Thread overview: 161+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-18 11:29 Mike Pagano [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-09-30 16:04 [gentoo-commits] proj/linux-patches:6.1 commit in: / Mike Pagano
2024-09-18 18:04 Mike Pagano
2024-09-12 12:35 Mike Pagano
2024-09-08 11:06 Mike Pagano
2024-09-04 13:52 Mike Pagano
2024-08-29 16:49 Mike Pagano
2024-08-19 10:43 Mike Pagano
2024-08-14 15:06 Mike Pagano
2024-08-14 14:11 Mike Pagano
2024-08-11 13:32 Mike Pagano
2024-08-11 13:29 Mike Pagano
2024-08-10 15:45 Mike Pagano
2024-08-03 15:28 Mike Pagano
2024-07-27 13:47 Mike Pagano
2024-07-25 12:15 Mike Pagano
2024-07-25 12:09 Mike Pagano
2024-07-18 12:15 Mike Pagano
2024-07-15 11:16 Mike Pagano
2024-07-11 11:49 Mike Pagano
2024-07-05 11:07 Mike Pagano
2024-06-27 13:10 Mike Pagano
2024-06-27 12:33 Mike Pagano
2024-06-21 14:07 Mike Pagano
2024-06-16 14:33 Mike Pagano
2024-06-12 10:16 Mike Pagano
2024-05-25 15:16 Mike Pagano
2024-05-17 11:36 Mike Pagano
2024-05-05 18:10 Mike Pagano
2024-05-02 15:01 Mike Pagano
2024-04-29 11:30 Mike Pagano
2024-04-29 11:27 Mike Pagano
2024-04-27 22:45 Mike Pagano
2024-04-27 17:06 Mike Pagano
2024-04-18  3:05 Alice Ferrazzi
2024-04-13 13:07 Mike Pagano
2024-04-10 15:10 Mike Pagano
2024-04-03 13:54 Mike Pagano
2024-03-27 11:24 Mike Pagano
2024-03-15 22:00 Mike Pagano
2024-03-06 18:07 Mike Pagano
2024-03-01 13:07 Mike Pagano
2024-02-23 13:19 Mike Pagano
2024-02-23 12:37 Mike Pagano
2024-02-16 19:00 Mike Pagano
2024-02-05 21:01 Mike Pagano
2024-02-01  1:23 Mike Pagano
2024-01-26  0:09 Mike Pagano
2024-01-20 11:45 Mike Pagano
2024-01-15 18:47 Mike Pagano
2024-01-10 17:16 Mike Pagano
2024-01-05 14:54 Mike Pagano
2024-01-05 14:50 Mike Pagano
2024-01-04 16:10 Mike Pagano
2024-01-01 13:46 Mike Pagano
2023-12-20 16:56 Mike Pagano
2023-12-13 18:27 Mike Pagano
2023-12-11 14:20 Mike Pagano
2023-12-08 10:55 Mike Pagano
2023-12-03 11:16 Mike Pagano
2023-12-01 10:36 Mike Pagano
2023-11-28 17:51 Mike Pagano
2023-11-20 11:23 Mike Pagano
2023-11-08 14:02 Mike Pagano
2023-11-02 11:10 Mike Pagano
2023-10-25 11:36 Mike Pagano
2023-10-22 22:53 Mike Pagano
2023-10-19 22:30 Mike Pagano
2023-10-18 20:04 Mike Pagano
2023-10-15 17:40 Mike Pagano
2023-10-10 22:56 Mike Pagano
2023-10-06 13:18 Mike Pagano
2023-10-05 14:23 Mike Pagano
2023-09-23 11:03 Mike Pagano
2023-09-23 10:16 Mike Pagano
2023-09-19 13:20 Mike Pagano
2023-09-15 18:04 Mike Pagano
2023-09-13 11:19 Mike Pagano
2023-09-13 11:05 Mike Pagano
2023-09-06 22:16 Mike Pagano
2023-09-02  9:56 Mike Pagano
2023-08-30 14:42 Mike Pagano
2023-08-27 21:41 Mike Pagano
2023-08-26 15:19 Mike Pagano
2023-08-26 15:00 Mike Pagano
2023-08-23 18:08 Mike Pagano
2023-08-16 18:32 Mike Pagano
2023-08-16 18:32 Mike Pagano
2023-08-11 11:55 Mike Pagano
2023-08-08 18:40 Mike Pagano
2023-08-03 11:54 Mike Pagano
2023-08-03 11:48 Mike Pagano
2023-07-27 11:48 Mike Pagano
2023-07-24 20:27 Mike Pagano
2023-07-23 15:14 Mike Pagano
2023-07-19 17:05 Mike Pagano
2023-07-05 20:34 Mike Pagano
2023-07-05 20:28 Mike Pagano
2023-07-04 13:15 Mike Pagano
2023-07-01 18:27 Mike Pagano
2023-06-28 10:26 Mike Pagano
2023-06-21 14:54 Alice Ferrazzi
2023-06-14 10:17 Mike Pagano
2023-06-09 12:02 Mike Pagano
2023-06-09 11:29 Mike Pagano
2023-06-05 11:48 Mike Pagano
2023-06-02 15:07 Mike Pagano
2023-05-30 16:51 Mike Pagano
2023-05-24 17:05 Mike Pagano
2023-05-17 10:57 Mike Pagano
2023-05-11 16:08 Mike Pagano
2023-05-11 14:49 Mike Pagano
2023-05-10 17:54 Mike Pagano
2023-05-10 16:18 Mike Pagano
2023-04-30 23:50 Alice Ferrazzi
2023-04-26 13:19 Mike Pagano
2023-04-20 11:16 Alice Ferrazzi
2023-04-13 16:09 Mike Pagano
2023-04-06 10:41 Alice Ferrazzi
2023-03-30 20:52 Mike Pagano
2023-03-30 11:21 Alice Ferrazzi
2023-03-22 14:15 Alice Ferrazzi
2023-03-21 13:32 Mike Pagano
2023-03-17 10:43 Mike Pagano
2023-03-13 11:30 Alice Ferrazzi
2023-03-11 14:09 Mike Pagano
2023-03-11 11:19 Mike Pagano
2023-03-10 12:57 Mike Pagano
2023-03-10 12:47 Mike Pagano
2023-03-06 17:30 Mike Pagano
2023-03-03 13:01 Mike Pagano
2023-03-03 12:28 Mike Pagano
2023-02-27 16:59 Mike Pagano
2023-02-26 18:24 Mike Pagano
2023-02-26 18:16 Mike Pagano
2023-02-25 11:02 Alice Ferrazzi
2023-02-24  3:03 Alice Ferrazzi
2023-02-22 13:46 Alice Ferrazzi
2023-02-14 18:35 Mike Pagano
2023-02-13 13:38 Mike Pagano
2023-02-09 12:52 Mike Pagano
2023-02-09 12:49 Mike Pagano
2023-02-09 12:47 Mike Pagano
2023-02-09 12:40 Mike Pagano
2023-02-09 12:34 Mike Pagano
2023-02-06 12:46 Mike Pagano
2023-02-02 19:02 Mike Pagano
2023-02-01  8:05 Alice Ferrazzi
2023-01-24  7:19 Alice Ferrazzi
2023-01-22 14:59 Mike Pagano
2023-01-14 13:48 Mike Pagano
2023-01-12 15:25 Mike Pagano
2023-01-12 12:16 Mike Pagano
2023-01-07 11:10 Mike Pagano
2023-01-04 11:37 Mike Pagano
2022-12-31 15:28 Mike Pagano
2022-12-21 19:05 Alice Ferrazzi
2022-12-16 20:25 Mike Pagano
2022-12-16 19:44 Mike Pagano
2022-12-11 23:32 Mike Pagano
2022-12-11 14:28 Mike Pagano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1674041384.3a4f90d35a846c31efef8d7280e2ca565d778f07.mpagano@gentoo \
    --to=mpagano@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox