diff options
author | Mike Pagano <mpagano@gentoo.org> | 2023-01-18 06:29:44 -0500 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2023-01-18 06:29:44 -0500 |
commit | 3a4f90d35a846c31efef8d7280e2ca565d778f07 (patch) | |
tree | 2055a77c1391ca0dc38fb0227039ae1c7ddc36b1 | |
parent | Linux patch 6.1.6 (diff) | |
download | linux-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_README | 4 | ||||
-rw-r--r-- | 1006_linux-6.1.7.patch | 10521 |
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, ¤t_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 >->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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(>->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 = >->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(>->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(>->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 = >->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 = >->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(>->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(>->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 |