summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2023-01-18 06:29:44 -0500
committerMike Pagano <mpagano@gentoo.org>2023-01-18 06:29:44 -0500
commit3a4f90d35a846c31efef8d7280e2ca565d778f07 (patch)
tree2055a77c1391ca0dc38fb0227039ae1c7ddc36b1
parentLinux patch 6.1.6 (diff)
downloadlinux-patches-3a4f90d35a846c31efef8d7280e2ca565d778f07.tar.gz
linux-patches-3a4f90d35a846c31efef8d7280e2ca565d778f07.tar.bz2
linux-patches-3a4f90d35a846c31efef8d7280e2ca565d778f07.zip
Linux patch 6.1.76.1-9
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1006_linux-6.1.7.patch10521
2 files changed, 10525 insertions, 0 deletions
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