From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 3F7FF15802C for ; Thu, 19 Dec 2024 18:07:43 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 7B80EE08C4; Thu, 19 Dec 2024 18:07:42 +0000 (UTC) Received: from smtp.gentoo.org (dev.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id EFB97E08C4 for ; Thu, 19 Dec 2024 18:07:32 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 6296933BE3B for ; Thu, 19 Dec 2024 18:07:29 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 05774AED for ; Thu, 19 Dec 2024 18:07:28 +0000 (UTC) From: "Mike Pagano" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Pagano" Message-ID: <1734631630.1d0712601fc0cfb16d2abc9bf8d0e34c43b6afe4.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.12 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1005_linux-6.12.6.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: 1d0712601fc0cfb16d2abc9bf8d0e34c43b6afe4 X-VCS-Branch: 6.12 Date: Thu, 19 Dec 2024 18:07:28 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: a55f1032-2c65-4b87-9526-e1a190a6f253 X-Archives-Hash: 21b51db39549ca4cea2eaea71ee56d57 commit: 1d0712601fc0cfb16d2abc9bf8d0e34c43b6afe4 Author: Mike Pagano gentoo org> AuthorDate: Thu Dec 19 18:07:10 2024 +0000 Commit: Mike Pagano gentoo org> CommitDate: Thu Dec 19 18:07:10 2024 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=1d071260 Linuxpatch 6.12.6 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1005_linux-6.12.6.patch | 8402 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 8406 insertions(+) diff --git a/0000_README b/0000_README index a2c9782d..1bb8df77 100644 --- a/0000_README +++ b/0000_README @@ -63,6 +63,10 @@ Patch: 1004_linux-6.12.5.patch From: https://www.kernel.org Desc: Linux 6.12.5 +Patch: 1005_linux-6.12.6.patch +From: https://www.kernel.org +Desc: Linux 6.12.6 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ Desc: Enable link security restrictions by default. diff --git a/1005_linux-6.12.6.patch b/1005_linux-6.12.6.patch new file mode 100644 index 00000000..e9bbd96e --- /dev/null +++ b/1005_linux-6.12.6.patch @@ -0,0 +1,8402 @@ +diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst +index eacf8983e23074..dcbb6f6caf6de3 100644 +--- a/Documentation/networking/ip-sysctl.rst ++++ b/Documentation/networking/ip-sysctl.rst +@@ -2170,6 +2170,12 @@ nexthop_compat_mode - BOOLEAN + understands the new API, this sysctl can be disabled to achieve full + performance benefits of the new API by disabling the nexthop expansion + and extraneous notifications. ++ ++ Note that as a backward-compatible mode, dumping of modern features ++ might be incomplete or wrong. For example, resilient groups will not be ++ shown as such, but rather as just a list of next hops. Also weights that ++ do not fit into 8 bits will show incorrectly. ++ + Default: true (backward compat mode) + + fib_notify_on_flag_change - INTEGER +diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst +index 53d1996460abfc..12f429359a823e 100644 +--- a/Documentation/power/runtime_pm.rst ++++ b/Documentation/power/runtime_pm.rst +@@ -347,7 +347,9 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: + + `int pm_runtime_resume_and_get(struct device *dev);` + - run pm_runtime_resume(dev) and if successful, increment the device's +- usage counter; return the result of pm_runtime_resume ++ usage counter; returns 0 on success (whether or not the device's ++ runtime PM status was already 'active') or the error code from ++ pm_runtime_resume() on failure. + + `int pm_request_idle(struct device *dev);` + - submit a request to execute the subsystem-level idle callback for the +diff --git a/Makefile b/Makefile +index f158bfe6407ac9..c10952585c14b0 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 12 +-SUBLEVEL = 5 ++SUBLEVEL = 6 + EXTRAVERSION = + NAME = Baby Opossum Posse + +diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c +index ff8c4e1b847ed4..fbed433283c9b9 100644 +--- a/arch/arm64/kvm/sys_regs.c ++++ b/arch/arm64/kvm/sys_regs.c +@@ -1535,6 +1535,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_DF2); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR); ++ val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac); + break; + case SYS_ID_AA64PFR2_EL1: + /* We only expose FPMR */ +@@ -1724,6 +1725,13 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, + + val &= ~ID_AA64PFR0_EL1_AMU_MASK; + ++ /* ++ * MPAM is disabled by default as KVM also needs a set of PARTID to ++ * program the MPAMVPMx_EL2 PARTID remapping registers with. But some ++ * older kernels let the guest see the ID bit. ++ */ ++ val &= ~ID_AA64PFR0_EL1_MPAM_MASK; ++ + return val; + } + +@@ -1834,6 +1842,42 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu, + return set_id_reg(vcpu, rd, val); + } + ++static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, ++ const struct sys_reg_desc *rd, u64 user_val) ++{ ++ u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); ++ u64 mpam_mask = ID_AA64PFR0_EL1_MPAM_MASK; ++ ++ /* ++ * Commit 011e5f5bf529f ("arm64/cpufeature: Add remaining feature bits ++ * in ID_AA64PFR0 register") exposed the MPAM field of AA64PFR0_EL1 to ++ * guests, but didn't add trap handling. KVM doesn't support MPAM and ++ * always returns an UNDEF for these registers. The guest must see 0 ++ * for this field. ++ * ++ * But KVM must also accept values from user-space that were provided ++ * by KVM. On CPUs that support MPAM, permit user-space to write ++ * the sanitizied value to ID_AA64PFR0_EL1.MPAM, but ignore this field. ++ */ ++ if ((hw_val & mpam_mask) == (user_val & mpam_mask)) ++ user_val &= ~ID_AA64PFR0_EL1_MPAM_MASK; ++ ++ return set_id_reg(vcpu, rd, user_val); ++} ++ ++static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, ++ const struct sys_reg_desc *rd, u64 user_val) ++{ ++ u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1); ++ u64 mpam_mask = ID_AA64PFR1_EL1_MPAM_frac_MASK; ++ ++ /* See set_id_aa64pfr0_el1 for comment about MPAM */ ++ if ((hw_val & mpam_mask) == (user_val & mpam_mask)) ++ user_val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK; ++ ++ return set_id_reg(vcpu, rd, user_val); ++} ++ + /* + * cpufeature ID register user accessors + * +@@ -2377,7 +2421,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { + { SYS_DESC(SYS_ID_AA64PFR0_EL1), + .access = access_id_reg, + .get_user = get_id_reg, +- .set_user = set_id_reg, ++ .set_user = set_id_aa64pfr0_el1, + .reset = read_sanitised_id_aa64pfr0_el1, + .val = ~(ID_AA64PFR0_EL1_AMU | + ID_AA64PFR0_EL1_MPAM | +@@ -2385,7 +2429,12 @@ static const struct sys_reg_desc sys_reg_descs[] = { + ID_AA64PFR0_EL1_RAS | + ID_AA64PFR0_EL1_AdvSIMD | + ID_AA64PFR0_EL1_FP), }, +- ID_WRITABLE(ID_AA64PFR1_EL1, ~(ID_AA64PFR1_EL1_PFAR | ++ { SYS_DESC(SYS_ID_AA64PFR1_EL1), ++ .access = access_id_reg, ++ .get_user = get_id_reg, ++ .set_user = set_id_aa64pfr1_el1, ++ .reset = kvm_read_sanitised_id_reg, ++ .val = ~(ID_AA64PFR1_EL1_PFAR | + ID_AA64PFR1_EL1_DF2 | + ID_AA64PFR1_EL1_MTEX | + ID_AA64PFR1_EL1_THE | +@@ -2397,7 +2446,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { + ID_AA64PFR1_EL1_RES0 | + ID_AA64PFR1_EL1_MPAM_frac | + ID_AA64PFR1_EL1_RAS_frac | +- ID_AA64PFR1_EL1_MTE)), ++ ID_AA64PFR1_EL1_MTE), }, + ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR), + ID_UNALLOCATED(4,3), + ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0), +diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h +index 7388edd88986f9..d08bf7fb3aee61 100644 +--- a/arch/riscv/include/asm/kfence.h ++++ b/arch/riscv/include/asm/kfence.h +@@ -22,7 +22,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) + else + set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT)); + +- flush_tlb_kernel_range(addr, addr + PAGE_SIZE); ++ preempt_disable(); ++ local_flush_tlb_kernel_range(addr, addr + PAGE_SIZE); ++ preempt_enable(); + + return true; + } +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index 26c886db4fb3d1..2b3c152d3c91f5 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -227,7 +227,7 @@ static void __init init_resources(void) + static void __init parse_dtb(void) + { + /* Early scan of device tree from init memory */ +- if (early_init_dt_scan(dtb_early_va, __pa(dtb_early_va))) { ++ if (early_init_dt_scan(dtb_early_va, dtb_early_pa)) { + const char *name = of_flat_dt_get_machine_name(); + + if (name) { +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 0e8c20adcd98df..fc53ce748c8049 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -1566,7 +1566,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd) + pmd_clear(pmd); + } + +-static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) ++static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemmap) + { + struct page *page = pud_page(*pud); + struct ptdesc *ptdesc = page_ptdesc(page); +@@ -1579,7 +1579,8 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) + return; + } + +- pagetable_pmd_dtor(ptdesc); ++ if (!is_vmemmap) ++ pagetable_pmd_dtor(ptdesc); + if (PageReserved(page)) + free_reserved_page(page); + else +@@ -1703,7 +1704,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un + remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap); + + if (pgtable_l4_enabled) +- free_pmd_table(pmd_base, pudp); ++ free_pmd_table(pmd_base, pudp, is_vmemmap); + } + } + +diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c +index fa5ea65de0d0fa..6188650707ab27 100644 +--- a/arch/x86/events/intel/ds.c ++++ b/arch/x86/events/intel/ds.c +@@ -1468,7 +1468,7 @@ void intel_pmu_pebs_enable(struct perf_event *event) + * hence we need to drain when changing said + * size. + */ +- intel_pmu_drain_large_pebs(cpuc); ++ intel_pmu_drain_pebs_buffer(); + adaptive_pebs_record_size_update(); + wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg); + cpuc->active_pebs_data_cfg = pebs_data_cfg; +diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h +index 4a686f0e5dbf6d..2d776635aa539e 100644 +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -212,6 +212,8 @@ static inline unsigned long long l1tf_pfn_limit(void) + return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT); + } + ++void init_cpu_devs(void); ++void get_cpu_vendor(struct cpuinfo_x86 *c); + extern void early_cpu_init(void); + extern void identify_secondary_cpu(struct cpuinfo_x86 *); + extern void print_cpu_info(struct cpuinfo_x86 *); +diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h +index 125c407e2abe6d..41502bd2afd646 100644 +--- a/arch/x86/include/asm/static_call.h ++++ b/arch/x86/include/asm/static_call.h +@@ -65,4 +65,19 @@ + + extern bool __static_call_fixup(void *tramp, u8 op, void *dest); + ++extern void __static_call_update_early(void *tramp, void *func); ++ ++#define static_call_update_early(name, _func) \ ++({ \ ++ typeof(&STATIC_CALL_TRAMP(name)) __F = (_func); \ ++ if (static_call_initialized) { \ ++ __static_call_update(&STATIC_CALL_KEY(name), \ ++ STATIC_CALL_TRAMP_ADDR(name), __F);\ ++ } else { \ ++ WRITE_ONCE(STATIC_CALL_KEY(name).func, _func); \ ++ __static_call_update_early(STATIC_CALL_TRAMP_ADDR(name),\ ++ __F); \ ++ } \ ++}) ++ + #endif /* _ASM_STATIC_CALL_H */ +diff --git a/arch/x86/include/asm/sync_core.h b/arch/x86/include/asm/sync_core.h +index ab7382f92aff27..96bda43538ee70 100644 +--- a/arch/x86/include/asm/sync_core.h ++++ b/arch/x86/include/asm/sync_core.h +@@ -8,7 +8,7 @@ + #include + + #ifdef CONFIG_X86_32 +-static inline void iret_to_self(void) ++static __always_inline void iret_to_self(void) + { + asm volatile ( + "pushfl\n\t" +@@ -19,7 +19,7 @@ static inline void iret_to_self(void) + : ASM_CALL_CONSTRAINT : : "memory"); + } + #else +-static inline void iret_to_self(void) ++static __always_inline void iret_to_self(void) + { + unsigned int tmp; + +@@ -55,7 +55,7 @@ static inline void iret_to_self(void) + * Like all of Linux's memory ordering operations, this is a + * compiler barrier as well. + */ +-static inline void sync_core(void) ++static __always_inline void sync_core(void) + { + /* + * The SERIALIZE instruction is the most straightforward way to +diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h +index a2dd24947eb85a..97771b9d33af30 100644 +--- a/arch/x86/include/asm/xen/hypercall.h ++++ b/arch/x86/include/asm/xen/hypercall.h +@@ -39,9 +39,11 @@ + #include + #include + #include ++#include + + #include + ++#include + #include + #include + #include +@@ -86,11 +88,20 @@ struct xen_dm_op_buf; + * there aren't more than 5 arguments...) + */ + +-extern struct { char _entry[32]; } hypercall_page[]; ++void xen_hypercall_func(void); ++DECLARE_STATIC_CALL(xen_hypercall, xen_hypercall_func); + +-#define __HYPERCALL "call hypercall_page+%c[offset]" +-#define __HYPERCALL_ENTRY(x) \ +- [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0])) ++#ifdef MODULE ++#define __ADDRESSABLE_xen_hypercall ++#else ++#define __ADDRESSABLE_xen_hypercall __ADDRESSABLE_ASM_STR(__SCK__xen_hypercall) ++#endif ++ ++#define __HYPERCALL \ ++ __ADDRESSABLE_xen_hypercall \ ++ "call __SCT__xen_hypercall" ++ ++#define __HYPERCALL_ENTRY(x) "a" (x) + + #ifdef CONFIG_X86_32 + #define __HYPERCALL_RETREG "eax" +@@ -148,7 +159,7 @@ extern struct { char _entry[32]; } hypercall_page[]; + __HYPERCALL_0ARG(); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_0PARAM \ +- : __HYPERCALL_ENTRY(name) \ ++ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ + : __HYPERCALL_CLOBBER0); \ + (type)__res; \ + }) +@@ -159,7 +170,7 @@ extern struct { char _entry[32]; } hypercall_page[]; + __HYPERCALL_1ARG(a1); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_1PARAM \ +- : __HYPERCALL_ENTRY(name) \ ++ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ + : __HYPERCALL_CLOBBER1); \ + (type)__res; \ + }) +@@ -170,7 +181,7 @@ extern struct { char _entry[32]; } hypercall_page[]; + __HYPERCALL_2ARG(a1, a2); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_2PARAM \ +- : __HYPERCALL_ENTRY(name) \ ++ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ + : __HYPERCALL_CLOBBER2); \ + (type)__res; \ + }) +@@ -181,7 +192,7 @@ extern struct { char _entry[32]; } hypercall_page[]; + __HYPERCALL_3ARG(a1, a2, a3); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_3PARAM \ +- : __HYPERCALL_ENTRY(name) \ ++ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ + : __HYPERCALL_CLOBBER3); \ + (type)__res; \ + }) +@@ -192,7 +203,7 @@ extern struct { char _entry[32]; } hypercall_page[]; + __HYPERCALL_4ARG(a1, a2, a3, a4); \ + asm volatile (__HYPERCALL \ + : __HYPERCALL_4PARAM \ +- : __HYPERCALL_ENTRY(name) \ ++ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ + : __HYPERCALL_CLOBBER4); \ + (type)__res; \ + }) +@@ -206,12 +217,9 @@ xen_single_call(unsigned int call, + __HYPERCALL_DECLS; + __HYPERCALL_5ARG(a1, a2, a3, a4, a5); + +- if (call >= PAGE_SIZE / sizeof(hypercall_page[0])) +- return -EINVAL; +- +- asm volatile(CALL_NOSPEC ++ asm volatile(__HYPERCALL + : __HYPERCALL_5PARAM +- : [thunk_target] "a" (&hypercall_page[call]) ++ : __HYPERCALL_ENTRY(call) + : __HYPERCALL_CLOBBER5); + + return (long)__res; +diff --git a/arch/x86/kernel/callthunks.c b/arch/x86/kernel/callthunks.c +index 4656474567533b..f17d166078823c 100644 +--- a/arch/x86/kernel/callthunks.c ++++ b/arch/x86/kernel/callthunks.c +@@ -142,11 +142,6 @@ static bool skip_addr(void *dest) + if (dest >= (void *)relocate_kernel && + dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE) + return true; +-#endif +-#ifdef CONFIG_XEN +- if (dest >= (void *)hypercall_page && +- dest < (void*)hypercall_page + PAGE_SIZE) +- return true; + #endif + return false; + } +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index b17bcf9b67eed4..f439763f45ae6f 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -868,7 +868,7 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c) + tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); + } + +-static void get_cpu_vendor(struct cpuinfo_x86 *c) ++void get_cpu_vendor(struct cpuinfo_x86 *c) + { + char *v = c->x86_vendor_id; + int i; +@@ -1652,15 +1652,11 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) + detect_nopl(); + } + +-void __init early_cpu_init(void) ++void __init init_cpu_devs(void) + { + const struct cpu_dev *const *cdev; + int count = 0; + +-#ifdef CONFIG_PROCESSOR_SELECT +- pr_info("KERNEL supported cpus:\n"); +-#endif +- + for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) { + const struct cpu_dev *cpudev = *cdev; + +@@ -1668,20 +1664,30 @@ void __init early_cpu_init(void) + break; + cpu_devs[count] = cpudev; + count++; ++ } ++} + ++void __init early_cpu_init(void) ++{ + #ifdef CONFIG_PROCESSOR_SELECT +- { +- unsigned int j; +- +- for (j = 0; j < 2; j++) { +- if (!cpudev->c_ident[j]) +- continue; +- pr_info(" %s %s\n", cpudev->c_vendor, +- cpudev->c_ident[j]); +- } +- } ++ unsigned int i, j; ++ ++ pr_info("KERNEL supported cpus:\n"); + #endif ++ ++ init_cpu_devs(); ++ ++#ifdef CONFIG_PROCESSOR_SELECT ++ for (i = 0; i < X86_VENDOR_NUM && cpu_devs[i]; i++) { ++ for (j = 0; j < 2; j++) { ++ if (!cpu_devs[i]->c_ident[j]) ++ continue; ++ pr_info(" %s %s\n", cpu_devs[i]->c_vendor, ++ cpu_devs[i]->c_ident[j]); ++ } + } ++#endif ++ + early_identify_cpu(&boot_cpu_data); + } + +diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c +index 4eefaac64c6cba..9eed0c144dad51 100644 +--- a/arch/x86/kernel/static_call.c ++++ b/arch/x86/kernel/static_call.c +@@ -172,6 +172,15 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail) + } + EXPORT_SYMBOL_GPL(arch_static_call_transform); + ++noinstr void __static_call_update_early(void *tramp, void *func) ++{ ++ BUG_ON(system_state != SYSTEM_BOOTING); ++ BUG_ON(!early_boot_irqs_disabled); ++ BUG_ON(static_call_initialized); ++ __text_gen_insn(tramp, JMP32_INSN_OPCODE, tramp, func, JMP32_INSN_SIZE); ++ sync_core(); ++} ++ + #ifdef CONFIG_MITIGATION_RETHUNK + /* + * This is called by apply_returns() to fix up static call trampolines, +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 84e5adbd0925cb..b4f3784f27e956 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -2,6 +2,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -21,7 +22,8 @@ + + #include "xen-ops.h" + +-EXPORT_SYMBOL_GPL(hypercall_page); ++DEFINE_STATIC_CALL(xen_hypercall, xen_hypercall_hvm); ++EXPORT_STATIC_CALL_TRAMP(xen_hypercall); + + /* + * Pointer to the xen_vcpu_info structure or +@@ -68,6 +70,66 @@ EXPORT_SYMBOL(xen_start_flags); + */ + struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; + ++static __ref void xen_get_vendor(void) ++{ ++ init_cpu_devs(); ++ cpu_detect(&boot_cpu_data); ++ get_cpu_vendor(&boot_cpu_data); ++} ++ ++void xen_hypercall_setfunc(void) ++{ ++ if (static_call_query(xen_hypercall) != xen_hypercall_hvm) ++ return; ++ ++ if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || ++ boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) ++ static_call_update(xen_hypercall, xen_hypercall_amd); ++ else ++ static_call_update(xen_hypercall, xen_hypercall_intel); ++} ++ ++/* ++ * Evaluate processor vendor in order to select the correct hypercall ++ * function for HVM/PVH guests. ++ * Might be called very early in boot before vendor has been set by ++ * early_cpu_init(). ++ */ ++noinstr void *__xen_hypercall_setfunc(void) ++{ ++ void (*func)(void); ++ ++ /* ++ * Xen is supported only on CPUs with CPUID, so testing for ++ * X86_FEATURE_CPUID is a test for early_cpu_init() having been ++ * run. ++ * ++ * Note that __xen_hypercall_setfunc() is noinstr only due to a nasty ++ * dependency chain: it is being called via the xen_hypercall static ++ * call when running as a PVH or HVM guest. Hypercalls need to be ++ * noinstr due to PV guests using hypercalls in noinstr code. So we ++ * the PV guest requirement is not of interest here (xen_get_vendor() ++ * calls noinstr functions, and static_call_update_early() might do ++ * so, too). ++ */ ++ instrumentation_begin(); ++ ++ if (!boot_cpu_has(X86_FEATURE_CPUID)) ++ xen_get_vendor(); ++ ++ if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || ++ boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) ++ func = xen_hypercall_amd; ++ else ++ func = xen_hypercall_intel; ++ ++ static_call_update_early(xen_hypercall, func); ++ ++ instrumentation_end(); ++ ++ return func; ++} ++ + static int xen_cpu_up_online(unsigned int cpu) + { + xen_init_lock_cpu(cpu); +diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c +index 24d2957a4726d8..fe57ff85d004ba 100644 +--- a/arch/x86/xen/enlighten_hvm.c ++++ b/arch/x86/xen/enlighten_hvm.c +@@ -106,15 +106,8 @@ static void __init init_hvm_pv_info(void) + /* PVH set up hypercall page in xen_prepare_pvh(). */ + if (xen_pvh_domain()) + pv_info.name = "Xen PVH"; +- else { +- u64 pfn; +- uint32_t msr; +- ++ else + pv_info.name = "Xen HVM"; +- msr = cpuid_ebx(base + 2); +- pfn = __pa(hypercall_page); +- wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); +- } + + xen_setup_features(); + +@@ -300,6 +293,10 @@ static uint32_t __init xen_platform_hvm(void) + if (xen_pv_domain()) + return 0; + ++ /* Set correct hypercall function. */ ++ if (xen_domain) ++ xen_hypercall_setfunc(); ++ + if (xen_pvh_domain() && nopv) { + /* Guest booting via the Xen-PVH boot entry goes here */ + pr_info("\"nopv\" parameter is ignored in PVH guest\n"); +diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c +index d6818c6cafda16..a8eb7e0c473cf6 100644 +--- a/arch/x86/xen/enlighten_pv.c ++++ b/arch/x86/xen/enlighten_pv.c +@@ -1341,6 +1341,9 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si) + + xen_domain_type = XEN_PV_DOMAIN; + xen_start_flags = xen_start_info->flags; ++ /* Interrupts are guaranteed to be off initially. */ ++ early_boot_irqs_disabled = true; ++ static_call_update_early(xen_hypercall, xen_hypercall_pv); + + xen_setup_features(); + +@@ -1431,7 +1434,6 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si) + WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_pv, xen_cpu_dead_pv)); + + local_irq_disable(); +- early_boot_irqs_disabled = true; + + xen_raw_console_write("mapping kernel into physical memory\n"); + xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, +diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c +index bf68c329fc013e..0e3d930bcb89e8 100644 +--- a/arch/x86/xen/enlighten_pvh.c ++++ b/arch/x86/xen/enlighten_pvh.c +@@ -129,17 +129,10 @@ static void __init pvh_arch_setup(void) + + void __init xen_pvh_init(struct boot_params *boot_params) + { +- u32 msr; +- u64 pfn; +- + xen_pvh = 1; + xen_domain_type = XEN_HVM_DOMAIN; + xen_start_flags = pvh_start_info.flags; + +- msr = cpuid_ebx(xen_cpuid_base() + 2); +- pfn = __pa(hypercall_page); +- wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); +- + x86_init.oem.arch_setup = pvh_arch_setup; + x86_init.oem.banner = xen_banner; + +diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S +index 83189cf5cdce93..b518f36d1ca2e7 100644 +--- a/arch/x86/xen/xen-asm.S ++++ b/arch/x86/xen/xen-asm.S +@@ -20,9 +20,32 @@ + + #include + #include ++#include + #include <../entry/calling.h> + + .pushsection .noinstr.text, "ax" ++/* ++ * PV hypercall interface to the hypervisor. ++ * ++ * Called via inline asm(), so better preserve %rcx and %r11. ++ * ++ * Input: ++ * %eax: hypercall number ++ * %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall ++ * Output: %rax ++ */ ++SYM_FUNC_START(xen_hypercall_pv) ++ ANNOTATE_NOENDBR ++ push %rcx ++ push %r11 ++ UNWIND_HINT_SAVE ++ syscall ++ UNWIND_HINT_RESTORE ++ pop %r11 ++ pop %rcx ++ RET ++SYM_FUNC_END(xen_hypercall_pv) ++ + /* + * Disabling events is simply a matter of making the event mask + * non-zero. +@@ -176,7 +199,6 @@ SYM_CODE_START(xen_early_idt_handler_array) + SYM_CODE_END(xen_early_idt_handler_array) + __FINIT + +-hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 + /* + * Xen64 iret frame: + * +@@ -186,17 +208,28 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 + * cs + * rip <-- standard iret frame + * +- * flags ++ * flags <-- xen_iret must push from here on + * +- * rcx } +- * r11 }<-- pushed by hypercall page +- * rsp->rax } ++ * rcx ++ * r11 ++ * rsp->rax + */ ++.macro xen_hypercall_iret ++ pushq $0 /* Flags */ ++ push %rcx ++ push %r11 ++ push %rax ++ mov $__HYPERVISOR_iret, %eax ++ syscall /* Do the IRET. */ ++#ifdef CONFIG_MITIGATION_SLS ++ int3 ++#endif ++.endm ++ + SYM_CODE_START(xen_iret) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR +- pushq $0 +- jmp hypercall_iret ++ xen_hypercall_iret + SYM_CODE_END(xen_iret) + + /* +@@ -301,8 +334,7 @@ SYM_CODE_START(xen_entry_SYSENTER_compat) + ENDBR + lea 16(%rsp), %rsp /* strip %rcx, %r11 */ + mov $-ENOSYS, %rax +- pushq $0 +- jmp hypercall_iret ++ xen_hypercall_iret + SYM_CODE_END(xen_entry_SYSENTER_compat) + SYM_CODE_END(xen_entry_SYSCALL_compat) + +diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S +index 758bcd47b72d32..721a57700a3b05 100644 +--- a/arch/x86/xen/xen-head.S ++++ b/arch/x86/xen/xen-head.S +@@ -6,9 +6,11 @@ + + #include + #include ++#include + + #include + #include ++#include + #include + #include + #include +@@ -20,28 +22,6 @@ + #include + #include + +-.pushsection .noinstr.text, "ax" +- .balign PAGE_SIZE +-SYM_CODE_START(hypercall_page) +- .rept (PAGE_SIZE / 32) +- UNWIND_HINT_FUNC +- ANNOTATE_NOENDBR +- ANNOTATE_UNRET_SAFE +- ret +- /* +- * Xen will write the hypercall page, and sort out ENDBR. +- */ +- .skip 31, 0xcc +- .endr +- +-#define HYPERCALL(n) \ +- .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \ +- .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32 +-#include +-#undef HYPERCALL +-SYM_CODE_END(hypercall_page) +-.popsection +- + #ifdef CONFIG_XEN_PV + __INIT + SYM_CODE_START(startup_xen) +@@ -87,6 +67,87 @@ SYM_CODE_END(xen_cpu_bringup_again) + #endif + #endif + ++ .pushsection .noinstr.text, "ax" ++/* ++ * Xen hypercall interface to the hypervisor. ++ * ++ * Input: ++ * %eax: hypercall number ++ * 32-bit: ++ * %ebx, %ecx, %edx, %esi, %edi: args 1..5 for the hypercall ++ * 64-bit: ++ * %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall ++ * Output: %[er]ax ++ */ ++SYM_FUNC_START(xen_hypercall_hvm) ++ ENDBR ++ FRAME_BEGIN ++ /* Save all relevant registers (caller save and arguments). */ ++#ifdef CONFIG_X86_32 ++ push %eax ++ push %ebx ++ push %ecx ++ push %edx ++ push %esi ++ push %edi ++#else ++ push %rax ++ push %rcx ++ push %rdx ++ push %rdi ++ push %rsi ++ push %r11 ++ push %r10 ++ push %r9 ++ push %r8 ++#ifdef CONFIG_FRAME_POINTER ++ pushq $0 /* Dummy push for stack alignment. */ ++#endif ++#endif ++ /* Set the vendor specific function. */ ++ call __xen_hypercall_setfunc ++ /* Set ZF = 1 if AMD, Restore saved registers. */ ++#ifdef CONFIG_X86_32 ++ lea xen_hypercall_amd, %ebx ++ cmp %eax, %ebx ++ pop %edi ++ pop %esi ++ pop %edx ++ pop %ecx ++ pop %ebx ++ pop %eax ++#else ++ lea xen_hypercall_amd(%rip), %rbx ++ cmp %rax, %rbx ++#ifdef CONFIG_FRAME_POINTER ++ pop %rax /* Dummy pop. */ ++#endif ++ pop %r8 ++ pop %r9 ++ pop %r10 ++ pop %r11 ++ pop %rsi ++ pop %rdi ++ pop %rdx ++ pop %rcx ++ pop %rax ++#endif ++ /* Use correct hypercall function. */ ++ jz xen_hypercall_amd ++ jmp xen_hypercall_intel ++SYM_FUNC_END(xen_hypercall_hvm) ++ ++SYM_FUNC_START(xen_hypercall_amd) ++ vmmcall ++ RET ++SYM_FUNC_END(xen_hypercall_amd) ++ ++SYM_FUNC_START(xen_hypercall_intel) ++ vmcall ++ RET ++SYM_FUNC_END(xen_hypercall_intel) ++ .popsection ++ + ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") + ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") + ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") +@@ -115,7 +176,6 @@ SYM_CODE_END(xen_cpu_bringup_again) + #else + # define FEATURES_DOM0 0 + #endif +- ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, _ASM_PTR hypercall_page) + ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES, + .long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0) + ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") +diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h +index e1b782e823e6b4..63c13a2ccf556a 100644 +--- a/arch/x86/xen/xen-ops.h ++++ b/arch/x86/xen/xen-ops.h +@@ -326,4 +326,13 @@ static inline void xen_smp_intr_free_pv(unsigned int cpu) {} + static inline void xen_smp_count_cpus(void) { } + #endif /* CONFIG_SMP */ + ++#ifdef CONFIG_XEN_PV ++void xen_hypercall_pv(void); ++#endif ++void xen_hypercall_hvm(void); ++void xen_hypercall_amd(void); ++void xen_hypercall_intel(void); ++void xen_hypercall_setfunc(void); ++void *__xen_hypercall_setfunc(void); ++ + #endif /* XEN_OPS_H */ +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index e68c725cf8d975..45a395862fbc88 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -1324,10 +1324,14 @@ void blkcg_unpin_online(struct cgroup_subsys_state *blkcg_css) + struct blkcg *blkcg = css_to_blkcg(blkcg_css); + + do { ++ struct blkcg *parent; ++ + if (!refcount_dec_and_test(&blkcg->online_pin)) + break; ++ ++ parent = blkcg_parent(blkcg); + blkcg_destroy_blkgs(blkcg); +- blkcg = blkcg_parent(blkcg); ++ blkcg = parent; + } while (blkcg); + } + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 384aa15e8260bd..a5894ec9696e7e 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1098,7 +1098,14 @@ static void __propagate_weights(struct ioc_gq *iocg, u32 active, u32 inuse, + inuse = DIV64_U64_ROUND_UP(active * iocg->child_inuse_sum, + iocg->child_active_sum); + } else { +- inuse = clamp_t(u32, inuse, 1, active); ++ /* ++ * It may be tempting to turn this into a clamp expression with ++ * a lower limit of 1 but active may be 0, which cannot be used ++ * as an upper limit in that situation. This expression allows ++ * active to clamp inuse unless it is 0, in which case inuse ++ * becomes 1. ++ */ ++ inuse = min(inuse, active) ?: 1; + } + + iocg->last_inuse = iocg->inuse; +diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c +index 156e9bb07abf1a..cd5ea6eaa76b09 100644 +--- a/block/blk-mq-sysfs.c ++++ b/block/blk-mq-sysfs.c +@@ -275,15 +275,13 @@ void blk_mq_sysfs_unregister_hctxs(struct request_queue *q) + struct blk_mq_hw_ctx *hctx; + unsigned long i; + +- mutex_lock(&q->sysfs_dir_lock); ++ lockdep_assert_held(&q->sysfs_dir_lock); ++ + if (!q->mq_sysfs_init_done) +- goto unlock; ++ return; + + queue_for_each_hw_ctx(q, hctx, i) + blk_mq_unregister_hctx(hctx); +- +-unlock: +- mutex_unlock(&q->sysfs_dir_lock); + } + + int blk_mq_sysfs_register_hctxs(struct request_queue *q) +@@ -292,9 +290,10 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q) + unsigned long i; + int ret = 0; + +- mutex_lock(&q->sysfs_dir_lock); ++ lockdep_assert_held(&q->sysfs_dir_lock); ++ + if (!q->mq_sysfs_init_done) +- goto unlock; ++ return ret; + + queue_for_each_hw_ctx(q, hctx, i) { + ret = blk_mq_register_hctx(hctx); +@@ -302,8 +301,5 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q) + break; + } + +-unlock: +- mutex_unlock(&q->sysfs_dir_lock); +- + return ret; + } +diff --git a/block/blk-mq.c b/block/blk-mq.c +index b4fba7b398e5bc..cc1b3202383840 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -43,6 +43,7 @@ + + static DEFINE_PER_CPU(struct llist_head, blk_cpu_done); + static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd); ++static DEFINE_MUTEX(blk_mq_cpuhp_lock); + + static void blk_mq_insert_request(struct request *rq, blk_insert_t flags); + static void blk_mq_request_bypass_insert(struct request *rq, +@@ -3740,13 +3741,91 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node) + return 0; + } + +-static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) ++static void __blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) + { +- if (!(hctx->flags & BLK_MQ_F_STACKING)) ++ lockdep_assert_held(&blk_mq_cpuhp_lock); ++ ++ if (!(hctx->flags & BLK_MQ_F_STACKING) && ++ !hlist_unhashed(&hctx->cpuhp_online)) { + cpuhp_state_remove_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, + &hctx->cpuhp_online); +- cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, +- &hctx->cpuhp_dead); ++ INIT_HLIST_NODE(&hctx->cpuhp_online); ++ } ++ ++ if (!hlist_unhashed(&hctx->cpuhp_dead)) { ++ cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, ++ &hctx->cpuhp_dead); ++ INIT_HLIST_NODE(&hctx->cpuhp_dead); ++ } ++} ++ ++static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) ++{ ++ mutex_lock(&blk_mq_cpuhp_lock); ++ __blk_mq_remove_cpuhp(hctx); ++ mutex_unlock(&blk_mq_cpuhp_lock); ++} ++ ++static void __blk_mq_add_cpuhp(struct blk_mq_hw_ctx *hctx) ++{ ++ lockdep_assert_held(&blk_mq_cpuhp_lock); ++ ++ if (!(hctx->flags & BLK_MQ_F_STACKING) && ++ hlist_unhashed(&hctx->cpuhp_online)) ++ cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, ++ &hctx->cpuhp_online); ++ ++ if (hlist_unhashed(&hctx->cpuhp_dead)) ++ cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, ++ &hctx->cpuhp_dead); ++} ++ ++static void __blk_mq_remove_cpuhp_list(struct list_head *head) ++{ ++ struct blk_mq_hw_ctx *hctx; ++ ++ lockdep_assert_held(&blk_mq_cpuhp_lock); ++ ++ list_for_each_entry(hctx, head, hctx_list) ++ __blk_mq_remove_cpuhp(hctx); ++} ++ ++/* ++ * Unregister cpuhp callbacks from exited hw queues ++ * ++ * Safe to call if this `request_queue` is live ++ */ ++static void blk_mq_remove_hw_queues_cpuhp(struct request_queue *q) ++{ ++ LIST_HEAD(hctx_list); ++ ++ spin_lock(&q->unused_hctx_lock); ++ list_splice_init(&q->unused_hctx_list, &hctx_list); ++ spin_unlock(&q->unused_hctx_lock); ++ ++ mutex_lock(&blk_mq_cpuhp_lock); ++ __blk_mq_remove_cpuhp_list(&hctx_list); ++ mutex_unlock(&blk_mq_cpuhp_lock); ++ ++ spin_lock(&q->unused_hctx_lock); ++ list_splice(&hctx_list, &q->unused_hctx_list); ++ spin_unlock(&q->unused_hctx_lock); ++} ++ ++/* ++ * Register cpuhp callbacks from all hw queues ++ * ++ * Safe to call if this `request_queue` is live ++ */ ++static void blk_mq_add_hw_queues_cpuhp(struct request_queue *q) ++{ ++ struct blk_mq_hw_ctx *hctx; ++ unsigned long i; ++ ++ mutex_lock(&blk_mq_cpuhp_lock); ++ queue_for_each_hw_ctx(q, hctx, i) ++ __blk_mq_add_cpuhp(hctx); ++ mutex_unlock(&blk_mq_cpuhp_lock); + } + + /* +@@ -3797,8 +3876,6 @@ static void blk_mq_exit_hctx(struct request_queue *q, + if (set->ops->exit_hctx) + set->ops->exit_hctx(hctx, hctx_idx); + +- blk_mq_remove_cpuhp(hctx); +- + xa_erase(&q->hctx_table, hctx_idx); + + spin_lock(&q->unused_hctx_lock); +@@ -3815,6 +3892,7 @@ static void blk_mq_exit_hw_queues(struct request_queue *q, + queue_for_each_hw_ctx(q, hctx, i) { + if (i == nr_queue) + break; ++ blk_mq_remove_cpuhp(hctx); + blk_mq_exit_hctx(q, set, hctx, i); + } + } +@@ -3878,6 +3956,8 @@ blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set, + INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn); + spin_lock_init(&hctx->lock); + INIT_LIST_HEAD(&hctx->dispatch); ++ INIT_HLIST_NODE(&hctx->cpuhp_dead); ++ INIT_HLIST_NODE(&hctx->cpuhp_online); + hctx->queue = q; + hctx->flags = set->flags & ~BLK_MQ_F_TAG_QUEUE_SHARED; + +@@ -4382,7 +4462,8 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, + unsigned long i, j; + + /* protect against switching io scheduler */ +- mutex_lock(&q->sysfs_lock); ++ lockdep_assert_held(&q->sysfs_lock); ++ + for (i = 0; i < set->nr_hw_queues; i++) { + int old_node; + int node = blk_mq_get_hctx_node(set, i); +@@ -4415,7 +4496,12 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, + + xa_for_each_start(&q->hctx_table, j, hctx, j) + blk_mq_exit_hctx(q, set, hctx, j); +- mutex_unlock(&q->sysfs_lock); ++ ++ /* unregister cpuhp callbacks for exited hctxs */ ++ blk_mq_remove_hw_queues_cpuhp(q); ++ ++ /* register cpuhp for new initialized hctxs */ ++ blk_mq_add_hw_queues_cpuhp(q); + } + + int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, +@@ -4441,10 +4527,14 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, + + xa_init(&q->hctx_table); + ++ mutex_lock(&q->sysfs_lock); ++ + blk_mq_realloc_hw_ctxs(set, q); + if (!q->nr_hw_queues) + goto err_hctxs; + ++ mutex_unlock(&q->sysfs_lock); ++ + INIT_WORK(&q->timeout_work, blk_mq_timeout_work); + blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ); + +@@ -4463,6 +4553,7 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, + return 0; + + err_hctxs: ++ mutex_unlock(&q->sysfs_lock); + blk_mq_release(q); + err_exit: + q->mq_ops = NULL; +@@ -4843,12 +4934,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head, + return false; + + /* q->elevator needs protection from ->sysfs_lock */ +- mutex_lock(&q->sysfs_lock); ++ lockdep_assert_held(&q->sysfs_lock); + + /* the check has to be done with holding sysfs_lock */ + if (!q->elevator) { + kfree(qe); +- goto unlock; ++ goto out; + } + + INIT_LIST_HEAD(&qe->node); +@@ -4858,9 +4949,7 @@ static bool blk_mq_elv_switch_none(struct list_head *head, + __elevator_get(qe->type); + list_add(&qe->node, head); + elevator_disable(q); +-unlock: +- mutex_unlock(&q->sysfs_lock); +- ++out: + return true; + } + +@@ -4889,11 +4978,9 @@ static void blk_mq_elv_switch_back(struct list_head *head, + list_del(&qe->node); + kfree(qe); + +- mutex_lock(&q->sysfs_lock); + elevator_switch(q, t); + /* drop the reference acquired in blk_mq_elv_switch_none */ + elevator_put(t); +- mutex_unlock(&q->sysfs_lock); + } + + static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, +@@ -4913,8 +5000,11 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, + if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues) + return; + +- list_for_each_entry(q, &set->tag_list, tag_set_list) ++ list_for_each_entry(q, &set->tag_list, tag_set_list) { ++ mutex_lock(&q->sysfs_dir_lock); ++ mutex_lock(&q->sysfs_lock); + blk_mq_freeze_queue(q); ++ } + /* + * Switch IO scheduler to 'none', cleaning up the data associated + * with the previous scheduler. We will switch back once we are done +@@ -4970,8 +5060,11 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, + list_for_each_entry(q, &set->tag_list, tag_set_list) + blk_mq_elv_switch_back(&head, q); + +- list_for_each_entry(q, &set->tag_list, tag_set_list) ++ list_for_each_entry(q, &set->tag_list, tag_set_list) { + blk_mq_unfreeze_queue(q); ++ mutex_unlock(&q->sysfs_lock); ++ mutex_unlock(&q->sysfs_dir_lock); ++ } + + /* Free the excess tags when nr_hw_queues shrink. */ + for (i = set->nr_hw_queues; i < prev_nr_hw_queues; i++) +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index 207577145c54f4..42c2cb97d778af 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -690,11 +690,11 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, + return res; + } + +- blk_mq_freeze_queue(q); + mutex_lock(&q->sysfs_lock); ++ blk_mq_freeze_queue(q); + res = entry->store(disk, page, length); +- mutex_unlock(&q->sysfs_lock); + blk_mq_unfreeze_queue(q); ++ mutex_unlock(&q->sysfs_lock); + return res; + } + +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index 0b1184176ce77a..767bcbce74facb 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include "blk.h" +@@ -41,7 +41,6 @@ static const char *const zone_cond_name[] = { + /* + * Per-zone write plug. + * @node: hlist_node structure for managing the plug using a hash table. +- * @link: To list the plug in the zone write plug error list of the disk. + * @ref: Zone write plug reference counter. A zone write plug reference is + * always at least 1 when the plug is hashed in the disk plug hash table. + * The reference is incremented whenever a new BIO needing plugging is +@@ -63,8 +62,7 @@ static const char *const zone_cond_name[] = { + */ + struct blk_zone_wplug { + struct hlist_node node; +- struct list_head link; +- atomic_t ref; ++ refcount_t ref; + spinlock_t lock; + unsigned int flags; + unsigned int zone_no; +@@ -80,8 +78,8 @@ struct blk_zone_wplug { + * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged, + * that is, that write BIOs are being throttled due to a write BIO already + * being executed or the zone write plug bio list is not empty. +- * - BLK_ZONE_WPLUG_ERROR: Indicates that a write error happened which will be +- * recovered with a report zone to update the zone write pointer offset. ++ * - BLK_ZONE_WPLUG_NEED_WP_UPDATE: Indicates that we lost track of a zone ++ * write pointer offset and need to update it. + * - BLK_ZONE_WPLUG_UNHASHED: Indicates that the zone write plug was removed + * from the disk hash table and that the initial reference to the zone + * write plug set when the plug was first added to the hash table has been +@@ -91,11 +89,9 @@ struct blk_zone_wplug { + * freed once all remaining references from BIOs or functions are dropped. + */ + #define BLK_ZONE_WPLUG_PLUGGED (1U << 0) +-#define BLK_ZONE_WPLUG_ERROR (1U << 1) ++#define BLK_ZONE_WPLUG_NEED_WP_UPDATE (1U << 1) + #define BLK_ZONE_WPLUG_UNHASHED (1U << 2) + +-#define BLK_ZONE_WPLUG_BUSY (BLK_ZONE_WPLUG_PLUGGED | BLK_ZONE_WPLUG_ERROR) +- + /** + * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX. + * @zone_cond: BLK_ZONE_COND_XXX. +@@ -115,6 +111,30 @@ const char *blk_zone_cond_str(enum blk_zone_cond zone_cond) + } + EXPORT_SYMBOL_GPL(blk_zone_cond_str); + ++struct disk_report_zones_cb_args { ++ struct gendisk *disk; ++ report_zones_cb user_cb; ++ void *user_data; ++}; ++ ++static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, ++ struct blk_zone *zone); ++ ++static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx, ++ void *data) ++{ ++ struct disk_report_zones_cb_args *args = data; ++ struct gendisk *disk = args->disk; ++ ++ if (disk->zone_wplugs_hash) ++ disk_zone_wplug_sync_wp_offset(disk, zone); ++ ++ if (!args->user_cb) ++ return 0; ++ ++ return args->user_cb(zone, idx, args->user_data); ++} ++ + /** + * blkdev_report_zones - Get zones information + * @bdev: Target block device +@@ -139,6 +159,11 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector, + { + struct gendisk *disk = bdev->bd_disk; + sector_t capacity = get_capacity(disk); ++ struct disk_report_zones_cb_args args = { ++ .disk = disk, ++ .user_cb = cb, ++ .user_data = data, ++ }; + + if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones)) + return -EOPNOTSUPP; +@@ -146,7 +171,8 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector, + if (!nr_zones || sector >= capacity) + return 0; + +- return disk->fops->report_zones(disk, sector, nr_zones, cb, data); ++ return disk->fops->report_zones(disk, sector, nr_zones, ++ disk_report_zones_cb, &args); + } + EXPORT_SYMBOL_GPL(blkdev_report_zones); + +@@ -417,7 +443,7 @@ static struct blk_zone_wplug *disk_get_zone_wplug(struct gendisk *disk, + + hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[idx], node) { + if (zwplug->zone_no == zno && +- atomic_inc_not_zero(&zwplug->ref)) { ++ refcount_inc_not_zero(&zwplug->ref)) { + rcu_read_unlock(); + return zwplug; + } +@@ -438,9 +464,9 @@ static void disk_free_zone_wplug_rcu(struct rcu_head *rcu_head) + + static inline void disk_put_zone_wplug(struct blk_zone_wplug *zwplug) + { +- if (atomic_dec_and_test(&zwplug->ref)) { ++ if (refcount_dec_and_test(&zwplug->ref)) { + WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list)); +- WARN_ON_ONCE(!list_empty(&zwplug->link)); ++ WARN_ON_ONCE(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED); + WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)); + + call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu); +@@ -454,8 +480,8 @@ static inline bool disk_should_remove_zone_wplug(struct gendisk *disk, + if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) + return false; + +- /* If the zone write plug is still busy, it cannot be removed. */ +- if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) ++ /* If the zone write plug is still plugged, it cannot be removed. */ ++ if (zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) + return false; + + /* +@@ -469,7 +495,7 @@ static inline bool disk_should_remove_zone_wplug(struct gendisk *disk, + * taken when the plug was allocated and another reference taken by the + * caller context). + */ +- if (atomic_read(&zwplug->ref) > 2) ++ if (refcount_read(&zwplug->ref) > 2) + return false; + + /* We can remove zone write plugs for zones that are empty or full. */ +@@ -538,12 +564,11 @@ static struct blk_zone_wplug *disk_get_and_lock_zone_wplug(struct gendisk *disk, + return NULL; + + INIT_HLIST_NODE(&zwplug->node); +- INIT_LIST_HEAD(&zwplug->link); +- atomic_set(&zwplug->ref, 2); ++ refcount_set(&zwplug->ref, 2); + spin_lock_init(&zwplug->lock); + zwplug->flags = 0; + zwplug->zone_no = zno; +- zwplug->wp_offset = sector & (disk->queue->limits.chunk_sectors - 1); ++ zwplug->wp_offset = bdev_offset_from_zone_start(disk->part0, sector); + bio_list_init(&zwplug->bio_list); + INIT_WORK(&zwplug->bio_work, blk_zone_wplug_bio_work); + zwplug->disk = disk; +@@ -587,124 +612,81 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) + } + + /* +- * Abort (fail) all plugged BIOs of a zone write plug that are not aligned +- * with the assumed write pointer location of the zone when the BIO will +- * be unplugged. ++ * Set a zone write plug write pointer offset to the specified value. ++ * This aborts all plugged BIOs, which is fine as this function is called for ++ * a zone reset operation, a zone finish operation or if the zone needs a wp ++ * update from a report zone after a write error. + */ +-static void disk_zone_wplug_abort_unaligned(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) +-{ +- unsigned int wp_offset = zwplug->wp_offset; +- struct bio_list bl = BIO_EMPTY_LIST; +- struct bio *bio; +- +- while ((bio = bio_list_pop(&zwplug->bio_list))) { +- if (disk_zone_is_full(disk, zwplug->zone_no, wp_offset) || +- (bio_op(bio) != REQ_OP_ZONE_APPEND && +- bio_offset_from_zone_start(bio) != wp_offset)) { +- blk_zone_wplug_bio_io_error(zwplug, bio); +- continue; +- } +- +- wp_offset += bio_sectors(bio); +- bio_list_add(&bl, bio); +- } +- +- bio_list_merge(&zwplug->bio_list, &bl); +-} +- +-static inline void disk_zone_wplug_set_error(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) ++static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug, ++ unsigned int wp_offset) + { +- unsigned long flags; ++ lockdep_assert_held(&zwplug->lock); + +- if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) +- return; ++ /* Update the zone write pointer and abort all plugged BIOs. */ ++ zwplug->flags &= ~BLK_ZONE_WPLUG_NEED_WP_UPDATE; ++ zwplug->wp_offset = wp_offset; ++ disk_zone_wplug_abort(zwplug); + + /* +- * At this point, we already have a reference on the zone write plug. +- * However, since we are going to add the plug to the disk zone write +- * plugs work list, increase its reference count. This reference will +- * be dropped in disk_zone_wplugs_work() once the error state is +- * handled, or in disk_zone_wplug_clear_error() if the zone is reset or +- * finished. ++ * The zone write plug now has no BIO plugged: remove it from the ++ * hash table so that it cannot be seen. The plug will be freed ++ * when the last reference is dropped. + */ +- zwplug->flags |= BLK_ZONE_WPLUG_ERROR; +- atomic_inc(&zwplug->ref); +- +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); +- list_add_tail(&zwplug->link, &disk->zone_wplugs_err_list); +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); ++ if (disk_should_remove_zone_wplug(disk, zwplug)) ++ disk_remove_zone_wplug(disk, zwplug); + } + +-static inline void disk_zone_wplug_clear_error(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) ++static unsigned int blk_zone_wp_offset(struct blk_zone *zone) + { +- unsigned long flags; +- +- if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR)) +- return; +- +- /* +- * We are racing with the error handling work which drops the reference +- * on the zone write plug after handling the error state. So remove the +- * plug from the error list and drop its reference count only if the +- * error handling has not yet started, that is, if the zone write plug +- * is still listed. +- */ +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); +- if (!list_empty(&zwplug->link)) { +- list_del_init(&zwplug->link); +- zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR; +- disk_put_zone_wplug(zwplug); ++ switch (zone->cond) { ++ case BLK_ZONE_COND_IMP_OPEN: ++ case BLK_ZONE_COND_EXP_OPEN: ++ case BLK_ZONE_COND_CLOSED: ++ return zone->wp - zone->start; ++ case BLK_ZONE_COND_FULL: ++ return zone->len; ++ case BLK_ZONE_COND_EMPTY: ++ return 0; ++ case BLK_ZONE_COND_NOT_WP: ++ case BLK_ZONE_COND_OFFLINE: ++ case BLK_ZONE_COND_READONLY: ++ default: ++ /* ++ * Conventional, offline and read-only zones do not have a valid ++ * write pointer. ++ */ ++ return UINT_MAX; + } +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); + } + +-/* +- * Set a zone write plug write pointer offset to either 0 (zone reset case) +- * or to the zone size (zone finish case). This aborts all plugged BIOs, which +- * is fine to do as doing a zone reset or zone finish while writes are in-flight +- * is a mistake from the user which will most likely cause all plugged BIOs to +- * fail anyway. +- */ +-static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, +- struct blk_zone_wplug *zwplug, +- unsigned int wp_offset) ++static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, ++ struct blk_zone *zone) + { ++ struct blk_zone_wplug *zwplug; + unsigned long flags; + +- spin_lock_irqsave(&zwplug->lock, flags); +- +- /* +- * Make sure that a BIO completion or another zone reset or finish +- * operation has not already removed the plug from the hash table. +- */ +- if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) { +- spin_unlock_irqrestore(&zwplug->lock, flags); ++ zwplug = disk_get_zone_wplug(disk, zone->start); ++ if (!zwplug) + return; +- } + +- /* Update the zone write pointer and abort all plugged BIOs. */ +- zwplug->wp_offset = wp_offset; +- disk_zone_wplug_abort(zwplug); ++ spin_lock_irqsave(&zwplug->lock, flags); ++ if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) ++ disk_zone_wplug_set_wp_offset(disk, zwplug, ++ blk_zone_wp_offset(zone)); ++ spin_unlock_irqrestore(&zwplug->lock, flags); + +- /* +- * Updating the write pointer offset puts back the zone +- * in a good state. So clear the error flag and decrement the +- * error count if we were in error state. +- */ +- disk_zone_wplug_clear_error(disk, zwplug); ++ disk_put_zone_wplug(zwplug); ++} + +- /* +- * The zone write plug now has no BIO plugged: remove it from the +- * hash table so that it cannot be seen. The plug will be freed +- * when the last reference is dropped. +- */ +- if (disk_should_remove_zone_wplug(disk, zwplug)) +- disk_remove_zone_wplug(disk, zwplug); ++static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector) ++{ ++ struct disk_report_zones_cb_args args = { ++ .disk = disk, ++ }; + +- spin_unlock_irqrestore(&zwplug->lock, flags); ++ return disk->fops->report_zones(disk, sector, 1, ++ disk_report_zones_cb, &args); + } + + static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, +@@ -713,6 +695,7 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, + struct gendisk *disk = bio->bi_bdev->bd_disk; + sector_t sector = bio->bi_iter.bi_sector; + struct blk_zone_wplug *zwplug; ++ unsigned long flags; + + /* Conventional zones cannot be reset nor finished. */ + if (disk_zone_is_conv(disk, sector)) { +@@ -720,6 +703,15 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, + return true; + } + ++ /* ++ * No-wait reset or finish BIOs do not make much sense as the callers ++ * issue these as blocking operations in most cases. To avoid issues ++ * the BIO execution potentially failing with BLK_STS_AGAIN, warn about ++ * REQ_NOWAIT being set and ignore that flag. ++ */ ++ if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) ++ bio->bi_opf &= ~REQ_NOWAIT; ++ + /* + * If we have a zone write plug, set its write pointer offset to 0 + * (reset case) or to the zone size (finish case). This will abort all +@@ -729,7 +721,9 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, + */ + zwplug = disk_get_zone_wplug(disk, sector); + if (zwplug) { ++ spin_lock_irqsave(&zwplug->lock, flags); + disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); ++ spin_unlock_irqrestore(&zwplug->lock, flags); + disk_put_zone_wplug(zwplug); + } + +@@ -740,6 +734,7 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) + { + struct gendisk *disk = bio->bi_bdev->bd_disk; + struct blk_zone_wplug *zwplug; ++ unsigned long flags; + sector_t sector; + + /* +@@ -751,7 +746,9 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) + sector += disk->queue->limits.chunk_sectors) { + zwplug = disk_get_zone_wplug(disk, sector); + if (zwplug) { ++ spin_lock_irqsave(&zwplug->lock, flags); + disk_zone_wplug_set_wp_offset(disk, zwplug, 0); ++ spin_unlock_irqrestore(&zwplug->lock, flags); + disk_put_zone_wplug(zwplug); + } + } +@@ -759,9 +756,25 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) + return false; + } + +-static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, +- struct bio *bio, unsigned int nr_segs) ++static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug) + { ++ /* ++ * Take a reference on the zone write plug and schedule the submission ++ * of the next plugged BIO. blk_zone_wplug_bio_work() will release the ++ * reference we take here. ++ */ ++ WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); ++ refcount_inc(&zwplug->ref); ++ queue_work(disk->zone_wplugs_wq, &zwplug->bio_work); ++} ++ ++static inline void disk_zone_wplug_add_bio(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug, ++ struct bio *bio, unsigned int nr_segs) ++{ ++ bool schedule_bio_work = false; ++ + /* + * Grab an extra reference on the BIO request queue usage counter. + * This reference will be reused to submit a request for the BIO for +@@ -777,6 +790,16 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, + */ + bio_clear_polled(bio); + ++ /* ++ * REQ_NOWAIT BIOs are always handled using the zone write plug BIO ++ * work, which can block. So clear the REQ_NOWAIT flag and schedule the ++ * work if this is the first BIO we are plugging. ++ */ ++ if (bio->bi_opf & REQ_NOWAIT) { ++ schedule_bio_work = !(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED); ++ bio->bi_opf &= ~REQ_NOWAIT; ++ } ++ + /* + * Reuse the poll cookie field to store the number of segments when + * split to the hardware limits. +@@ -790,6 +813,11 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, + * at the tail of the list to preserve the sequential write order. + */ + bio_list_add(&zwplug->bio_list, bio); ++ ++ zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; ++ ++ if (schedule_bio_work) ++ disk_zone_wplug_schedule_bio_work(disk, zwplug); + } + + /* +@@ -902,13 +930,23 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug, + { + struct gendisk *disk = bio->bi_bdev->bd_disk; + ++ /* ++ * If we lost track of the zone write pointer due to a write error, ++ * the user must either execute a report zones, reset the zone or finish ++ * the to recover a reliable write pointer position. Fail BIOs if the ++ * user did not do that as we cannot handle emulated zone append ++ * otherwise. ++ */ ++ if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) ++ return false; ++ + /* + * Check that the user is not attempting to write to a full zone. + * We know such BIO will fail, and that would potentially overflow our + * write pointer offset beyond the end of the zone. + */ + if (disk_zone_wplug_is_full(disk, zwplug)) +- goto err; ++ return false; + + if (bio_op(bio) == REQ_OP_ZONE_APPEND) { + /* +@@ -927,24 +965,18 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug, + bio_set_flag(bio, BIO_EMULATES_ZONE_APPEND); + } else { + /* +- * Check for non-sequential writes early because we avoid a +- * whole lot of error handling trouble if we don't send it off +- * to the driver. ++ * Check for non-sequential writes early as we know that BIOs ++ * with a start sector not unaligned to the zone write pointer ++ * will fail. + */ + if (bio_offset_from_zone_start(bio) != zwplug->wp_offset) +- goto err; ++ return false; + } + + /* Advance the zone write pointer offset. */ + zwplug->wp_offset += bio_sectors(bio); + + return true; +- +-err: +- /* We detected an invalid write BIO: schedule error recovery. */ +- disk_zone_wplug_set_error(disk, zwplug); +- kblockd_schedule_work(&disk->zone_wplugs_work); +- return false; + } + + static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) +@@ -983,7 +1015,10 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + + zwplug = disk_get_and_lock_zone_wplug(disk, sector, gfp_mask, &flags); + if (!zwplug) { +- bio_io_error(bio); ++ if (bio->bi_opf & REQ_NOWAIT) ++ bio_wouldblock_error(bio); ++ else ++ bio_io_error(bio); + return true; + } + +@@ -991,18 +1026,20 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + bio_set_flag(bio, BIO_ZONE_WRITE_PLUGGING); + + /* +- * If the zone is already plugged or has a pending error, add the BIO +- * to the plug BIO list. Otherwise, plug and let the BIO execute. ++ * If the zone is already plugged, add the BIO to the plug BIO list. ++ * Do the same for REQ_NOWAIT BIOs to ensure that we will not see a ++ * BLK_STS_AGAIN failure if we let the BIO execute. ++ * Otherwise, plug and let the BIO execute. + */ +- if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) ++ if ((zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) || ++ (bio->bi_opf & REQ_NOWAIT)) + goto plug; + +- /* +- * If an error is detected when preparing the BIO, add it to the BIO +- * list so that error recovery can deal with it. +- */ +- if (!blk_zone_wplug_prepare_bio(zwplug, bio)) +- goto plug; ++ if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { ++ spin_unlock_irqrestore(&zwplug->lock, flags); ++ bio_io_error(bio); ++ return true; ++ } + + zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; + +@@ -1011,8 +1048,7 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + return false; + + plug: +- zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; +- blk_zone_wplug_add_bio(zwplug, bio, nr_segs); ++ disk_zone_wplug_add_bio(disk, zwplug, bio, nr_segs); + + spin_unlock_irqrestore(&zwplug->lock, flags); + +@@ -1096,19 +1132,6 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs) + } + EXPORT_SYMBOL_GPL(blk_zone_plug_bio); + +-static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) +-{ +- /* +- * Take a reference on the zone write plug and schedule the submission +- * of the next plugged BIO. blk_zone_wplug_bio_work() will release the +- * reference we take here. +- */ +- WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); +- atomic_inc(&zwplug->ref); +- queue_work(disk->zone_wplugs_wq, &zwplug->bio_work); +-} +- + static void disk_zone_wplug_unplug_bio(struct gendisk *disk, + struct blk_zone_wplug *zwplug) + { +@@ -1116,16 +1139,6 @@ static void disk_zone_wplug_unplug_bio(struct gendisk *disk, + + spin_lock_irqsave(&zwplug->lock, flags); + +- /* +- * If we had an error, schedule error recovery. The recovery work +- * will restart submission of plugged BIOs. +- */ +- if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) { +- spin_unlock_irqrestore(&zwplug->lock, flags); +- kblockd_schedule_work(&disk->zone_wplugs_work); +- return; +- } +- + /* Schedule submission of the next plugged BIO if we have one. */ + if (!bio_list_empty(&zwplug->bio_list)) { + disk_zone_wplug_schedule_bio_work(disk, zwplug); +@@ -1168,12 +1181,13 @@ void blk_zone_write_plug_bio_endio(struct bio *bio) + } + + /* +- * If the BIO failed, mark the plug as having an error to trigger +- * recovery. ++ * If the BIO failed, abort all plugged BIOs and mark the plug as ++ * needing a write pointer update. + */ + if (bio->bi_status != BLK_STS_OK) { + spin_lock_irqsave(&zwplug->lock, flags); +- disk_zone_wplug_set_error(disk, zwplug); ++ disk_zone_wplug_abort(zwplug); ++ zwplug->flags |= BLK_ZONE_WPLUG_NEED_WP_UPDATE; + spin_unlock_irqrestore(&zwplug->lock, flags); + } + +@@ -1229,6 +1243,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + */ + spin_lock_irqsave(&zwplug->lock, flags); + ++again: + bio = bio_list_pop(&zwplug->bio_list); + if (!bio) { + zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; +@@ -1237,10 +1252,8 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + } + + if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { +- /* Error recovery will decide what to do with the BIO. */ +- bio_list_add_head(&zwplug->bio_list, bio); +- spin_unlock_irqrestore(&zwplug->lock, flags); +- goto put_zwplug; ++ blk_zone_wplug_bio_io_error(zwplug, bio); ++ goto again; + } + + spin_unlock_irqrestore(&zwplug->lock, flags); +@@ -1262,120 +1275,6 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + disk_put_zone_wplug(zwplug); + } + +-static unsigned int blk_zone_wp_offset(struct blk_zone *zone) +-{ +- switch (zone->cond) { +- case BLK_ZONE_COND_IMP_OPEN: +- case BLK_ZONE_COND_EXP_OPEN: +- case BLK_ZONE_COND_CLOSED: +- return zone->wp - zone->start; +- case BLK_ZONE_COND_FULL: +- return zone->len; +- case BLK_ZONE_COND_EMPTY: +- return 0; +- case BLK_ZONE_COND_NOT_WP: +- case BLK_ZONE_COND_OFFLINE: +- case BLK_ZONE_COND_READONLY: +- default: +- /* +- * Conventional, offline and read-only zones do not have a valid +- * write pointer. +- */ +- return UINT_MAX; +- } +-} +- +-static int blk_zone_wplug_report_zone_cb(struct blk_zone *zone, +- unsigned int idx, void *data) +-{ +- struct blk_zone *zonep = data; +- +- *zonep = *zone; +- return 0; +-} +- +-static void disk_zone_wplug_handle_error(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) +-{ +- sector_t zone_start_sector = +- bdev_zone_sectors(disk->part0) * zwplug->zone_no; +- unsigned int noio_flag; +- struct blk_zone zone; +- unsigned long flags; +- int ret; +- +- /* Get the current zone information from the device. */ +- noio_flag = memalloc_noio_save(); +- ret = disk->fops->report_zones(disk, zone_start_sector, 1, +- blk_zone_wplug_report_zone_cb, &zone); +- memalloc_noio_restore(noio_flag); +- +- spin_lock_irqsave(&zwplug->lock, flags); +- +- /* +- * A zone reset or finish may have cleared the error already. In such +- * case, do nothing as the report zones may have seen the "old" write +- * pointer value before the reset/finish operation completed. +- */ +- if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR)) +- goto unlock; +- +- zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR; +- +- if (ret != 1) { +- /* +- * We failed to get the zone information, meaning that something +- * is likely really wrong with the device. Abort all remaining +- * plugged BIOs as otherwise we could endup waiting forever on +- * plugged BIOs to complete if there is a queue freeze on-going. +- */ +- disk_zone_wplug_abort(zwplug); +- goto unplug; +- } +- +- /* Update the zone write pointer offset. */ +- zwplug->wp_offset = blk_zone_wp_offset(&zone); +- disk_zone_wplug_abort_unaligned(disk, zwplug); +- +- /* Restart BIO submission if we still have any BIO left. */ +- if (!bio_list_empty(&zwplug->bio_list)) { +- disk_zone_wplug_schedule_bio_work(disk, zwplug); +- goto unlock; +- } +- +-unplug: +- zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; +- if (disk_should_remove_zone_wplug(disk, zwplug)) +- disk_remove_zone_wplug(disk, zwplug); +- +-unlock: +- spin_unlock_irqrestore(&zwplug->lock, flags); +-} +- +-static void disk_zone_wplugs_work(struct work_struct *work) +-{ +- struct gendisk *disk = +- container_of(work, struct gendisk, zone_wplugs_work); +- struct blk_zone_wplug *zwplug; +- unsigned long flags; +- +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); +- +- while (!list_empty(&disk->zone_wplugs_err_list)) { +- zwplug = list_first_entry(&disk->zone_wplugs_err_list, +- struct blk_zone_wplug, link); +- list_del_init(&zwplug->link); +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); +- +- disk_zone_wplug_handle_error(disk, zwplug); +- disk_put_zone_wplug(zwplug); +- +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); +- } +- +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); +-} +- + static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) + { + return 1U << disk->zone_wplugs_hash_bits; +@@ -1384,8 +1283,6 @@ static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) + void disk_init_zone_resources(struct gendisk *disk) + { + spin_lock_init(&disk->zone_wplugs_lock); +- INIT_LIST_HEAD(&disk->zone_wplugs_err_list); +- INIT_WORK(&disk->zone_wplugs_work, disk_zone_wplugs_work); + } + + /* +@@ -1450,7 +1347,7 @@ static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk) + while (!hlist_empty(&disk->zone_wplugs_hash[i])) { + zwplug = hlist_entry(disk->zone_wplugs_hash[i].first, + struct blk_zone_wplug, node); +- atomic_inc(&zwplug->ref); ++ refcount_inc(&zwplug->ref); + disk_remove_zone_wplug(disk, zwplug); + disk_put_zone_wplug(zwplug); + } +@@ -1484,8 +1381,6 @@ void disk_free_zone_resources(struct gendisk *disk) + if (!disk->zone_wplugs_pool) + return; + +- cancel_work_sync(&disk->zone_wplugs_work); +- + if (disk->zone_wplugs_wq) { + destroy_workqueue(disk->zone_wplugs_wq); + disk->zone_wplugs_wq = NULL; +@@ -1682,6 +1577,8 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx, + if (!disk->zone_wplugs_hash) + return 0; + ++ disk_zone_wplug_sync_wp_offset(disk, zone); ++ + wp_offset = blk_zone_wp_offset(zone); + if (!wp_offset || wp_offset >= zone->capacity) + return 0; +@@ -1818,6 +1715,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk) + memalloc_noio_restore(noio_flag); + return ret; + } ++ + ret = disk->fops->report_zones(disk, 0, UINT_MAX, + blk_revalidate_zone_cb, &args); + if (!ret) { +@@ -1854,6 +1752,48 @@ int blk_revalidate_disk_zones(struct gendisk *disk) + } + EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones); + ++/** ++ * blk_zone_issue_zeroout - zero-fill a block range in a zone ++ * @bdev: blockdev to write ++ * @sector: start sector ++ * @nr_sects: number of sectors to write ++ * @gfp_mask: memory allocation flags (for bio_alloc) ++ * ++ * Description: ++ * Zero-fill a block range in a zone (@sector must be equal to the zone write ++ * pointer), handling potential errors due to the (initially unknown) lack of ++ * hardware offload (See blkdev_issue_zeroout()). ++ */ ++int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector, ++ sector_t nr_sects, gfp_t gfp_mask) ++{ ++ int ret; ++ ++ if (WARN_ON_ONCE(!bdev_is_zoned(bdev))) ++ return -EIO; ++ ++ ret = blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, ++ BLKDEV_ZERO_NOFALLBACK); ++ if (ret != -EOPNOTSUPP) ++ return ret; ++ ++ /* ++ * The failed call to blkdev_issue_zeroout() advanced the zone write ++ * pointer. Undo this using a report zone to update the zone write ++ * pointer to the correct current value. ++ */ ++ ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector); ++ if (ret != 1) ++ return ret < 0 ? ret : -EIO; ++ ++ /* ++ * Retry without BLKDEV_ZERO_NOFALLBACK to force the fallback to a ++ * regular write with zero-pages. ++ */ ++ return blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, 0); ++} ++EXPORT_SYMBOL_GPL(blk_zone_issue_zeroout); ++ + #ifdef CONFIG_BLK_DEBUG_FS + + int queue_zone_wplugs_show(void *data, struct seq_file *m) +@@ -1876,7 +1816,7 @@ int queue_zone_wplugs_show(void *data, struct seq_file *m) + spin_lock_irqsave(&zwplug->lock, flags); + zwp_zone_no = zwplug->zone_no; + zwp_flags = zwplug->flags; +- zwp_ref = atomic_read(&zwplug->ref); ++ zwp_ref = refcount_read(&zwplug->ref); + zwp_wp_offset = zwplug->wp_offset; + zwp_bio_list_size = bio_list_size(&zwplug->bio_list); + spin_unlock_irqrestore(&zwplug->lock, flags); +diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c +index 95f78383bbdba1..bff2d099f4691e 100644 +--- a/drivers/acpi/acpica/evxfregn.c ++++ b/drivers/acpi/acpica/evxfregn.c +@@ -232,8 +232,6 @@ acpi_remove_address_space_handler(acpi_handle device, + + /* Now we can delete the handler object */ + +- acpi_os_release_mutex(handler_obj->address_space. +- context_mutex); + acpi_ut_remove_reference(handler_obj); + goto unlock_and_exit; + } +diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c +index 5429ec9ef06f06..a5d47819b3a4e2 100644 +--- a/drivers/acpi/nfit/core.c ++++ b/drivers/acpi/nfit/core.c +@@ -454,8 +454,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, + if (cmd_rc) + *cmd_rc = -EINVAL; + +- if (cmd == ND_CMD_CALL) ++ if (cmd == ND_CMD_CALL) { ++ if (!buf || buf_len < sizeof(*call_pkg)) ++ return -EINVAL; ++ + call_pkg = buf; ++ } ++ + func = cmd_to_func(nfit_mem, cmd, call_pkg, &family); + if (func < 0) + return func; +diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c +index 7fe842dae1ec05..821867de43bea3 100644 +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -250,6 +250,9 @@ static bool acpi_decode_space(struct resource_win *win, + switch (addr->resource_type) { + case ACPI_MEMORY_RANGE: + acpi_dev_memresource_flags(res, len, wp); ++ ++ if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) ++ res->flags |= IORESOURCE_PREFETCH; + break; + case ACPI_IO_RANGE: + acpi_dev_ioresource_flags(res, len, iodec, +@@ -265,9 +268,6 @@ static bool acpi_decode_space(struct resource_win *win, + if (addr->producer_consumer == ACPI_PRODUCER) + res->flags |= IORESOURCE_WINDOW; + +- if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) +- res->flags |= IORESOURCE_PREFETCH; +- + return !(res->flags & IORESOURCE_DISABLED); + } + +diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c +index 63ef7bb073ce03..596c6d294da906 100644 +--- a/drivers/ata/sata_highbank.c ++++ b/drivers/ata/sata_highbank.c +@@ -348,6 +348,7 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr) + phy_nodes[phy] = phy_data.np; + cphy_base[phy] = of_iomap(phy_nodes[phy], 0); + if (cphy_base[phy] == NULL) { ++ of_node_put(phy_data.np); + return 0; + } + phy_count += 1; +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index 480e4adba9faa6..85e99641eaae02 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -395,6 +395,7 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) + { + struct btmtk_data *data = hci_get_priv(hdev); + int err; ++ bool complete = false; + + if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { + kfree_skb(skb); +@@ -416,19 +417,22 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) + fallthrough; + case HCI_DEVCOREDUMP_ACTIVE: + default: ++ /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ ++ if (data->cd_info.cnt >= MTK_COREDUMP_NUM && ++ skb->len > MTK_COREDUMP_END_LEN) ++ if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], ++ MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) ++ complete = true; ++ + err = hci_devcd_append(hdev, skb); + if (err < 0) + break; + data->cd_info.cnt++; + +- /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ +- if (data->cd_info.cnt > MTK_COREDUMP_NUM && +- skb->len > MTK_COREDUMP_END_LEN) +- if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], +- MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) { +- bt_dev_info(hdev, "Mediatek coredump end"); +- hci_devcd_complete(hdev); +- } ++ if (complete) { ++ bt_dev_info(hdev, "Mediatek coredump end"); ++ hci_devcd_complete(hdev); ++ } + + break; + } +diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c +index bc21b292144926..62a62eaba2aad8 100644 +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -92,6 +92,7 @@ static const u32 slic_base[] = { 100000000, 3125000 }; + static const u32 npu_base[] = { 333000000, 400000000, 500000000 }; + /* EN7581 */ + static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 }; ++static const u32 bus7581_base[] = { 600000000, 540000000 }; + static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 }; + static const u32 crypto_base[] = { 540000000, 480000000 }; + +@@ -227,8 +228,8 @@ static const struct en_clk_desc en7581_base_clks[] = { + .base_reg = REG_BUS_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, +- .base_values = bus_base, +- .n_base_values = ARRAY_SIZE(bus_base), ++ .base_values = bus7581_base, ++ .n_base_values = ARRAY_SIZE(bus7581_base), + + .div_bits = 3, + .div_shift = 0, +diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c +index 1b9b7bccdeff08..45e130b901eb5e 100644 +--- a/drivers/crypto/hisilicon/debugfs.c ++++ b/drivers/crypto/hisilicon/debugfs.c +@@ -192,7 +192,7 @@ static int qm_sqc_dump(struct hisi_qm *qm, char *s, char *name) + + down_read(&qm->qps_lock); + if (qm->sqc) { +- memcpy(&sqc, qm->sqc + qp_id * sizeof(struct qm_sqc), sizeof(struct qm_sqc)); ++ memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc)); + sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); + sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); + dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC"); +@@ -229,7 +229,7 @@ static int qm_cqc_dump(struct hisi_qm *qm, char *s, char *name) + + down_read(&qm->qps_lock); + if (qm->cqc) { +- memcpy(&cqc, qm->cqc + qp_id * sizeof(struct qm_cqc), sizeof(struct qm_cqc)); ++ memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc)); + cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); + cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); + dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC"); +diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c +index f2e911a3d2ca02..ad6a045fd3d2d2 100644 +--- a/drivers/gpio/gpio-graniterapids.c ++++ b/drivers/gpio/gpio-graniterapids.c +@@ -32,12 +32,14 @@ + #define GNR_PINS_PER_REG 32 + #define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG) + +-#define GNR_CFG_BAR 0x00 ++#define GNR_CFG_PADBAR 0x00 + #define GNR_CFG_LOCK_OFFSET 0x04 +-#define GNR_GPI_STATUS_OFFSET 0x20 ++#define GNR_GPI_STATUS_OFFSET 0x14 + #define GNR_GPI_ENABLE_OFFSET 0x24 + +-#define GNR_CFG_DW_RX_MASK GENMASK(25, 22) ++#define GNR_CFG_DW_HOSTSW_MODE BIT(27) ++#define GNR_CFG_DW_RX_MASK GENMASK(23, 22) ++#define GNR_CFG_DW_INTSEL_MASK GENMASK(21, 14) + #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2) + #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1) + #define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0) +@@ -50,6 +52,7 @@ + * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state + * @gc: GPIO controller interface + * @reg_base: base address of the GPIO registers ++ * @pad_base: base address of the vGPIO pad configuration registers + * @ro_bitmap: bitmap of read-only pins + * @lock: guard the registers + * @pad_backup: backup of the register state for suspend +@@ -57,6 +60,7 @@ + struct gnr_gpio { + struct gpio_chip gc; + void __iomem *reg_base; ++ void __iomem *pad_base; + DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS); + raw_spinlock_t lock; + u32 pad_backup[]; +@@ -65,7 +69,7 @@ struct gnr_gpio { + static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv, + unsigned int gpio) + { +- return priv->reg_base + gpio * sizeof(u32); ++ return priv->pad_base + gpio * sizeof(u32); + } + + static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, +@@ -88,6 +92,20 @@ static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, + return 0; + } + ++static int gnr_gpio_request(struct gpio_chip *gc, unsigned int gpio) ++{ ++ struct gnr_gpio *priv = gpiochip_get_data(gc); ++ u32 dw; ++ ++ dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); ++ if (!(dw & GNR_CFG_DW_HOSTSW_MODE)) { ++ dev_warn(gc->parent, "GPIO %u is not owned by host", gpio); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ + static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio) + { + const struct gnr_gpio *priv = gpiochip_get_data(gc); +@@ -139,6 +157,7 @@ static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, in + + static const struct gpio_chip gnr_gpio_chip = { + .owner = THIS_MODULE, ++ .request = gnr_gpio_request, + .get = gnr_gpio_get, + .set = gnr_gpio_set, + .get_direction = gnr_gpio_get_direction, +@@ -166,7 +185,7 @@ static void gnr_gpio_irq_ack(struct irq_data *d) + guard(raw_spinlock_irqsave)(&priv->lock); + + reg = readl(addr); +- reg &= ~BIT(bit_idx); ++ reg |= BIT(bit_idx); + writel(reg, addr); + } + +@@ -209,10 +228,18 @@ static void gnr_gpio_irq_unmask(struct irq_data *d) + static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) + { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +- irq_hw_number_t pin = irqd_to_hwirq(d); +- u32 mask = GNR_CFG_DW_RX_MASK; ++ struct gnr_gpio *priv = gpiochip_get_data(gc); ++ irq_hw_number_t hwirq = irqd_to_hwirq(d); ++ u32 reg; + u32 set; + ++ /* Allow interrupts only if Interrupt Select field is non-zero */ ++ reg = readl(gnr_gpio_get_padcfg_addr(priv, hwirq)); ++ if (!(reg & GNR_CFG_DW_INTSEL_MASK)) { ++ dev_dbg(gc->parent, "GPIO %lu cannot be used as IRQ", hwirq); ++ return -EPERM; ++ } ++ + /* Falling edge and level low triggers not supported by the GPIO controller */ + switch (type) { + case IRQ_TYPE_NONE: +@@ -230,10 +257,11 @@ static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) + return -EINVAL; + } + +- return gnr_gpio_configure_line(gc, pin, mask, set); ++ return gnr_gpio_configure_line(gc, hwirq, GNR_CFG_DW_RX_MASK, set); + } + + static const struct irq_chip gnr_gpio_irq_chip = { ++ .name = "gpio-graniterapids", + .irq_ack = gnr_gpio_irq_ack, + .irq_mask = gnr_gpio_irq_mask, + .irq_unmask = gnr_gpio_irq_unmask, +@@ -291,6 +319,7 @@ static int gnr_gpio_probe(struct platform_device *pdev) + struct gnr_gpio *priv; + void __iomem *regs; + int irq, ret; ++ u32 offset; + + priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL); + if (!priv) +@@ -302,6 +331,10 @@ static int gnr_gpio_probe(struct platform_device *pdev) + if (IS_ERR(regs)) + return PTR_ERR(regs); + ++ priv->reg_base = regs; ++ offset = readl(priv->reg_base + GNR_CFG_PADBAR); ++ priv->pad_base = priv->reg_base + offset; ++ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; +@@ -311,8 +344,6 @@ static int gnr_gpio_probe(struct platform_device *pdev) + if (ret) + return dev_err_probe(dev, ret, "failed to request interrupt\n"); + +- priv->reg_base = regs + readl(regs + GNR_CFG_BAR); +- + gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET, + priv->ro_bitmap); + +@@ -324,7 +355,6 @@ static int gnr_gpio_probe(struct platform_device *pdev) + + girq = &priv->gc.irq; + gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip); +- girq->chip->name = dev_name(dev); + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; +diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c +index dfec9fbfc7a9bd..c2a9b425397441 100644 +--- a/drivers/gpio/gpio-ljca.c ++++ b/drivers/gpio/gpio-ljca.c +@@ -82,9 +82,9 @@ static int ljca_gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, + int ret; + + mutex_lock(&ljca_gpio->trans_lock); ++ packet->num = 1; + packet->item[0].index = gpio_id; + packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id]; +- packet->num = 1; + + ret = ljca_transfer(ljca_gpio->ljca, LJCA_GPIO_CONFIG, (u8 *)packet, + struct_size(packet, item, packet->num), NULL, 0); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index d891ab779ca7f5..5df21529b3b13e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1801,13 +1801,18 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, + if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket) + return -EINVAL; + ++ /* Make sure VRAM is allocated contigiously */ + (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; +- amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); +- for (i = 0; i < (*bo)->placement.num_placement; i++) +- (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; +- r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); +- if (r) +- return r; ++ if ((*bo)->tbo.resource->mem_type == TTM_PL_VRAM && ++ !((*bo)->tbo.resource->placement & TTM_PL_FLAG_CONTIGUOUS)) { ++ ++ amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); ++ for (i = 0; i < (*bo)->placement.num_placement; i++) ++ (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; ++ r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); ++ if (r) ++ return r; ++ } + + return amdgpu_ttm_alloc_gart(&(*bo)->tbo); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index 31fd30dcd593ba..65bb26215e867a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -551,6 +551,8 @@ static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo) + for (i = 0; i < abo->placement.num_placement; ++i) { + abo->placements[i].fpfn = 0 >> PAGE_SHIFT; + abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; ++ if (abo->placements[i].mem_type == TTM_PL_VRAM) ++ abo->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; + } + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +index 6005280f5f38f0..8d2562d0f143c7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +@@ -674,12 +674,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, + pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && + ring->funcs->emit_wreg; + +- if (adev->gfx.enable_cleaner_shader && +- ring->funcs->emit_cleaner_shader && +- job->enforce_isolation) +- ring->funcs->emit_cleaner_shader(ring); +- +- if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync) ++ if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && ++ !(job->enforce_isolation && !job->vmid)) + return 0; + + amdgpu_ring_ib_begin(ring); +@@ -690,6 +686,11 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, + if (need_pipe_sync) + amdgpu_ring_emit_pipeline_sync(ring); + ++ if (adev->gfx.enable_cleaner_shader && ++ ring->funcs->emit_cleaner_shader && ++ job->enforce_isolation) ++ ring->funcs->emit_cleaner_shader(ring); ++ + if (vm_flush_needed) { + trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr); + amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr); +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +index 6068b784dc6938..9a30b8c10838c1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +@@ -1289,7 +1289,7 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + struct amdgpu_job *job, + struct amdgpu_ib *ib) + { +- struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); ++ struct amdgpu_ring *ring = amdgpu_job_ring(job); + unsigned i; + + /* No patching necessary for the first instance */ +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +index 8de61cc524c943..d2993594c848ad 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +@@ -1422,6 +1422,7 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list, + + + static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, ++ bool cache_line_size_missing, + struct kfd_gpu_cache_info *pcache_info) + { + struct amdgpu_device *adev = kdev->adev; +@@ -1436,6 +1437,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_tcp_per_wpg / 2; + pcache_info[i].cache_line_size = adev->gfx.config.gc_tcp_cache_line_size; ++ if (cache_line_size_missing && !pcache_info[i].cache_line_size) ++ pcache_info[i].cache_line_size = 128; + i++; + } + /* Scalar L1 Instruction Cache per SQC */ +@@ -1448,6 +1451,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; + pcache_info[i].cache_line_size = adev->gfx.config.gc_instruction_cache_line_size; ++ if (cache_line_size_missing && !pcache_info[i].cache_line_size) ++ pcache_info[i].cache_line_size = 128; + i++; + } + /* Scalar L1 Data Cache per SQC */ +@@ -1459,6 +1464,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; + pcache_info[i].cache_line_size = adev->gfx.config.gc_scalar_data_cache_line_size; ++ if (cache_line_size_missing && !pcache_info[i].cache_line_size) ++ pcache_info[i].cache_line_size = 64; + i++; + } + /* GL1 Data Cache per SA */ +@@ -1471,7 +1478,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; +- pcache_info[i].cache_line_size = 0; ++ if (cache_line_size_missing) ++ pcache_info[i].cache_line_size = 128; + i++; + } + /* L2 Data Cache per GPU (Total Tex Cache) */ +@@ -1483,6 +1491,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; + pcache_info[i].cache_line_size = adev->gfx.config.gc_tcc_cache_line_size; ++ if (cache_line_size_missing && !pcache_info[i].cache_line_size) ++ pcache_info[i].cache_line_size = 128; + i++; + } + /* L3 Data Cache per GPU */ +@@ -1493,7 +1503,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE); + pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; +- pcache_info[i].cache_line_size = 0; ++ pcache_info[i].cache_line_size = 64; + i++; + } + return i; +@@ -1568,6 +1578,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, + int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pcache_info) + { + int num_of_cache_types = 0; ++ bool cache_line_size_missing = false; + + switch (kdev->adev->asic_type) { + case CHIP_KAVERI: +@@ -1691,10 +1702,17 @@ int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pc + case IP_VERSION(11, 5, 0): + case IP_VERSION(11, 5, 1): + case IP_VERSION(11, 5, 2): ++ /* Cacheline size not available in IP discovery for gc11. ++ * kfd_fill_gpu_cache_info_from_gfx_config to hard code it ++ */ ++ cache_line_size_missing = true; ++ fallthrough; + case IP_VERSION(12, 0, 0): + case IP_VERSION(12, 0, 1): + num_of_cache_types = +- kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd, *pcache_info); ++ kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd, ++ cache_line_size_missing, ++ *pcache_info); + break; + default: + *pcache_info = dummy_cache_info; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 648f40091aa395..f5b3ed20e891b3 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -205,6 +205,21 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, + if (!down_read_trylock(&adev->reset_domain->sem)) + return -EIO; + ++ if (!pdd->proc_ctx_cpu_ptr) { ++ r = amdgpu_amdkfd_alloc_gtt_mem(adev, ++ AMDGPU_MES_PROC_CTX_SIZE, ++ &pdd->proc_ctx_bo, ++ &pdd->proc_ctx_gpu_addr, ++ &pdd->proc_ctx_cpu_ptr, ++ false); ++ if (r) { ++ dev_err(adev->dev, ++ "failed to allocate process context bo\n"); ++ return r; ++ } ++ memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); ++ } ++ + memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input)); + queue_input.process_id = qpd->pqm->process->pasid; + queue_input.page_table_base_addr = qpd->page_table_base; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index ff34bb1ac9db79..3139987b82b100 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1076,7 +1076,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) + + kfd_free_process_doorbells(pdd->dev->kfd, pdd); + +- if (pdd->dev->kfd->shared_resources.enable_mes) ++ if (pdd->dev->kfd->shared_resources.enable_mes && ++ pdd->proc_ctx_cpu_ptr) + amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, + &pdd->proc_ctx_bo); + /* +@@ -1610,7 +1611,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, + struct kfd_process *p) + { + struct kfd_process_device *pdd = NULL; +- int retval = 0; + + if (WARN_ON_ONCE(p->n_pdds >= MAX_GPU_INSTANCE)) + return NULL; +@@ -1634,21 +1634,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, + pdd->user_gpu_id = dev->id; + atomic64_set(&pdd->evict_duration_counter, 0); + +- if (dev->kfd->shared_resources.enable_mes) { +- retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, +- AMDGPU_MES_PROC_CTX_SIZE, +- &pdd->proc_ctx_bo, +- &pdd->proc_ctx_gpu_addr, +- &pdd->proc_ctx_cpu_ptr, +- false); +- if (retval) { +- dev_err(dev->adev->dev, +- "failed to allocate process context bo\n"); +- goto err_free_pdd; +- } +- memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); +- } +- + p->pdds[p->n_pdds++] = pdd; + if (kfd_dbg_is_per_vmid_supported(pdd->dev)) + pdd->spi_dbg_override = pdd->dev->kfd2kgd->disable_debug_trap( +@@ -1660,10 +1645,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, + idr_init(&pdd->alloc_idr); + + return pdd; +- +-err_free_pdd: +- kfree(pdd); +- return NULL; + } + + /** +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index 01b960b152743d..ead4317a21680b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -212,13 +212,17 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm, + void pqm_uninit(struct process_queue_manager *pqm) + { + struct process_queue_node *pqn, *next; +- struct kfd_process_device *pdd; + + list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) { + if (pqn->q) { +- pdd = kfd_get_process_device_data(pqn->q->device, pqm->process); +- kfd_queue_unref_bo_vas(pdd, &pqn->q->properties); +- kfd_queue_release_buffers(pdd, &pqn->q->properties); ++ struct kfd_process_device *pdd = kfd_get_process_device_data(pqn->q->device, ++ pqm->process); ++ if (pdd) { ++ kfd_queue_unref_bo_vas(pdd, &pqn->q->properties); ++ kfd_queue_release_buffers(pdd, &pqn->q->properties); ++ } else { ++ WARN_ON(!pdd); ++ } + pqm_clean_queue_resource(pqm, pqn); + } + +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 d0e6d051e9cf9f..1aedfafa507f7e 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 +@@ -2717,4 +2717,5 @@ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) + smu->workload_map = smu_v13_0_7_workload_map; + smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; + smu_v13_0_set_smu_mailbox_registers(smu); ++ smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + } +diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs +index 1ef56cb07dfbd2..447740d79d3d2e 100644 +--- a/drivers/gpu/drm/drm_panic_qr.rs ++++ b/drivers/gpu/drm/drm_panic_qr.rs +@@ -929,7 +929,6 @@ fn draw_all(&mut self, data: impl Iterator) { + /// * `tmp` must be valid for reading and writing for `tmp_size` bytes. + /// + /// They must remain valid for the duration of the function call. +- + #[no_mangle] + pub unsafe extern "C" fn drm_panic_qr_generate( + url: *const i8, +diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c +index 5d701f48351b96..ec55cb651d4498 100644 +--- a/drivers/gpu/drm/i915/display/intel_color.c ++++ b/drivers/gpu/drm/i915/display/intel_color.c +@@ -1333,19 +1333,29 @@ static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state, + lut = blob->data; + + /* +- * DSB fails to correctly load the legacy LUT +- * unless we either write each entry twice, +- * or use non-posted writes ++ * DSB fails to correctly load the legacy LUT unless ++ * we either write each entry twice when using posted ++ * writes, or we use non-posted writes. ++ * ++ * If palette anti-collision is active during LUT ++ * register writes: ++ * - posted writes simply get dropped and thus the LUT ++ * contents may not be correctly updated ++ * - non-posted writes are blocked and thus the LUT ++ * contents are always correct, but simultaneous CPU ++ * MMIO access will start to fail ++ * ++ * Choose the lesser of two evils and use posted writes. ++ * Using posted writes is also faster, even when having ++ * to write each register twice. + */ +- if (crtc_state->dsb_color_vblank) +- intel_dsb_nonpost_start(crtc_state->dsb_color_vblank); +- +- for (i = 0; i < 256; i++) ++ for (i = 0; i < 256; i++) { + ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i), + i9xx_lut_8(&lut[i])); +- +- if (crtc_state->dsb_color_vblank) +- intel_dsb_nonpost_end(crtc_state->dsb_color_vblank); ++ if (crtc_state->dsb_color_vblank) ++ ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i), ++ i9xx_lut_8(&lut[i])); ++ } + } + + static void ilk_load_lut_10(const struct intel_crtc_state *crtc_state, +diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c +index 6469b9bcf2ec44..082ac72c757a9f 100644 +--- a/drivers/gpu/drm/i915/i915_gpu_error.c ++++ b/drivers/gpu/drm/i915/i915_gpu_error.c +@@ -1652,9 +1652,21 @@ capture_engine(struct intel_engine_cs *engine, + return NULL; + + intel_engine_get_hung_entity(engine, &ce, &rq); +- if (rq && !i915_request_started(rq)) +- drm_info(&engine->gt->i915->drm, "Got hung context on %s with active request %lld:%lld [0x%04X] not yet started\n", +- engine->name, rq->fence.context, rq->fence.seqno, ce->guc_id.id); ++ if (rq && !i915_request_started(rq)) { ++ /* ++ * We want to know also what is the guc_id of the context, ++ * but if we don't have the context reference, then skip ++ * printing it. ++ */ ++ if (ce) ++ drm_info(&engine->gt->i915->drm, ++ "Got hung context on %s with active request %lld:%lld [0x%04X] not yet started\n", ++ engine->name, rq->fence.context, rq->fence.seqno, ce->guc_id.id); ++ else ++ drm_info(&engine->gt->i915->drm, ++ "Got hung context on %s with active request %lld:%lld not yet started\n", ++ engine->name, rq->fence.context, rq->fence.seqno); ++ } + + if (rq) { + capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL); +diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c +index 762127dd56c538..70a854557e6ec5 100644 +--- a/drivers/gpu/drm/i915/i915_scheduler.c ++++ b/drivers/gpu/drm/i915/i915_scheduler.c +@@ -506,6 +506,6 @@ int __init i915_scheduler_module_init(void) + return 0; + + err_priorities: +- kmem_cache_destroy(slab_priorities); ++ kmem_cache_destroy(slab_dependencies); + return -ENOMEM; + } +diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c +index 1a192a2a941b69..3bbdb362d6f0dc 100644 +--- a/drivers/gpu/drm/xe/tests/xe_migrate.c ++++ b/drivers/gpu/drm/xe/tests/xe_migrate.c +@@ -224,8 +224,8 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test) + XE_BO_FLAG_VRAM_IF_DGFX(tile) | + XE_BO_FLAG_PINNED); + if (IS_ERR(tiny)) { +- KUNIT_FAIL(test, "Failed to allocate fake pt: %li\n", +- PTR_ERR(pt)); ++ KUNIT_FAIL(test, "Failed to allocate tiny fake pt: %li\n", ++ PTR_ERR(tiny)); + goto free_pt; + } + +diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c +index 9d82ea30f4df23..7e385940df0863 100644 +--- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c ++++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c +@@ -65,6 +65,14 @@ invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fe + __invalidation_fence_signal(xe, fence); + } + ++void xe_gt_tlb_invalidation_fence_signal(struct xe_gt_tlb_invalidation_fence *fence) ++{ ++ if (WARN_ON_ONCE(!fence->gt)) ++ return; ++ ++ __invalidation_fence_signal(gt_to_xe(fence->gt), fence); ++} ++ + static void xe_gt_tlb_fence_timeout(struct work_struct *work) + { + struct xe_gt *gt = container_of(work, struct xe_gt, +diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h +index f430d5797af701..00b1c6c01e8d95 100644 +--- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h ++++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h +@@ -28,6 +28,7 @@ int xe_guc_tlb_invalidation_done_handler(struct xe_guc *guc, u32 *msg, u32 len); + void xe_gt_tlb_invalidation_fence_init(struct xe_gt *gt, + struct xe_gt_tlb_invalidation_fence *fence, + bool stack); ++void xe_gt_tlb_invalidation_fence_signal(struct xe_gt_tlb_invalidation_fence *fence); + + static inline void + xe_gt_tlb_invalidation_fence_wait(struct xe_gt_tlb_invalidation_fence *fence) +diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c +index f27f579f4d85aa..797576690356f2 100644 +--- a/drivers/gpu/drm/xe/xe_pt.c ++++ b/drivers/gpu/drm/xe/xe_pt.c +@@ -1333,8 +1333,7 @@ static void invalidation_fence_cb(struct dma_fence *fence, + queue_work(system_wq, &ifence->work); + } else { + ifence->base.base.error = ifence->fence->error; +- dma_fence_signal(&ifence->base.base); +- dma_fence_put(&ifence->base.base); ++ xe_gt_tlb_invalidation_fence_signal(&ifence->base); + } + dma_fence_put(ifence->fence); + } +diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c +index 440ac572f6e5ef..52969c0909659d 100644 +--- a/drivers/gpu/drm/xe/xe_reg_sr.c ++++ b/drivers/gpu/drm/xe/xe_reg_sr.c +@@ -26,46 +26,27 @@ + #include "xe_reg_whitelist.h" + #include "xe_rtp_types.h" + +-#define XE_REG_SR_GROW_STEP_DEFAULT 16 +- + static void reg_sr_fini(struct drm_device *drm, void *arg) + { + struct xe_reg_sr *sr = arg; ++ struct xe_reg_sr_entry *entry; ++ unsigned long reg; ++ ++ xa_for_each(&sr->xa, reg, entry) ++ kfree(entry); + + xa_destroy(&sr->xa); +- kfree(sr->pool.arr); +- memset(&sr->pool, 0, sizeof(sr->pool)); + } + + int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe) + { + xa_init(&sr->xa); +- memset(&sr->pool, 0, sizeof(sr->pool)); +- sr->pool.grow_step = XE_REG_SR_GROW_STEP_DEFAULT; + sr->name = name; + + return drmm_add_action_or_reset(&xe->drm, reg_sr_fini, sr); + } + EXPORT_SYMBOL_IF_KUNIT(xe_reg_sr_init); + +-static struct xe_reg_sr_entry *alloc_entry(struct xe_reg_sr *sr) +-{ +- if (sr->pool.used == sr->pool.allocated) { +- struct xe_reg_sr_entry *arr; +- +- arr = krealloc_array(sr->pool.arr, +- ALIGN(sr->pool.allocated + 1, sr->pool.grow_step), +- sizeof(*arr), GFP_KERNEL); +- if (!arr) +- return NULL; +- +- sr->pool.arr = arr; +- sr->pool.allocated += sr->pool.grow_step; +- } +- +- return &sr->pool.arr[sr->pool.used++]; +-} +- + static bool compatible_entries(const struct xe_reg_sr_entry *e1, + const struct xe_reg_sr_entry *e2) + { +@@ -111,7 +92,7 @@ int xe_reg_sr_add(struct xe_reg_sr *sr, + return 0; + } + +- pentry = alloc_entry(sr); ++ pentry = kmalloc(sizeof(*pentry), GFP_KERNEL); + if (!pentry) { + ret = -ENOMEM; + goto fail; +diff --git a/drivers/gpu/drm/xe/xe_reg_sr_types.h b/drivers/gpu/drm/xe/xe_reg_sr_types.h +index ad48a52b824a18..ebe11f237fa26d 100644 +--- a/drivers/gpu/drm/xe/xe_reg_sr_types.h ++++ b/drivers/gpu/drm/xe/xe_reg_sr_types.h +@@ -20,12 +20,6 @@ struct xe_reg_sr_entry { + }; + + struct xe_reg_sr { +- struct { +- struct xe_reg_sr_entry *arr; +- unsigned int used; +- unsigned int allocated; +- unsigned int grow_step; +- } pool; + struct xarray xa; + const char *name; + +diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +index c8ec74f089f3d6..6e41ddaa24d636 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c ++++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +@@ -339,7 +339,7 @@ tegra241_cmdqv_get_cmdq(struct arm_smmu_device *smmu, + * one CPU at a time can enter the process, while the others + * will be spinning at the same lock. + */ +- lidx = smp_processor_id() % cmdqv->num_lvcmdqs_per_vintf; ++ lidx = raw_smp_processor_id() % cmdqv->num_lvcmdqs_per_vintf; + vcmdq = vintf->lvcmdqs[lidx]; + if (!vcmdq || !READ_ONCE(vcmdq->enabled)) + return NULL; +diff --git a/drivers/iommu/intel/cache.c b/drivers/iommu/intel/cache.c +index e5b89f728ad3b2..09694cca8752df 100644 +--- a/drivers/iommu/intel/cache.c ++++ b/drivers/iommu/intel/cache.c +@@ -105,12 +105,35 @@ static void cache_tag_unassign(struct dmar_domain *domain, u16 did, + spin_unlock_irqrestore(&domain->cache_lock, flags); + } + ++/* domain->qi_batch will be freed in iommu_free_domain() path. */ ++static int domain_qi_batch_alloc(struct dmar_domain *domain) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&domain->cache_lock, flags); ++ if (domain->qi_batch) ++ goto out_unlock; ++ ++ domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_ATOMIC); ++ if (!domain->qi_batch) ++ ret = -ENOMEM; ++out_unlock: ++ spin_unlock_irqrestore(&domain->cache_lock, flags); ++ ++ return ret; ++} ++ + static int __cache_tag_assign_domain(struct dmar_domain *domain, u16 did, + struct device *dev, ioasid_t pasid) + { + struct device_domain_info *info = dev_iommu_priv_get(dev); + int ret; + ++ ret = domain_qi_batch_alloc(domain); ++ if (ret) ++ return ret; ++ + ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_IOTLB); + if (ret || !info->ats_enabled) + return ret; +@@ -139,6 +162,10 @@ static int __cache_tag_assign_parent_domain(struct dmar_domain *domain, u16 did, + struct device_domain_info *info = dev_iommu_priv_get(dev); + int ret; + ++ ret = domain_qi_batch_alloc(domain); ++ if (ret) ++ return ret; ++ + ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_NESTING_IOTLB); + if (ret || !info->ats_enabled) + return ret; +@@ -190,13 +217,6 @@ int cache_tag_assign_domain(struct dmar_domain *domain, + u16 did = domain_get_id_for_dev(domain, dev); + int ret; + +- /* domain->qi_bach will be freed in iommu_free_domain() path. */ +- if (!domain->qi_batch) { +- domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_KERNEL); +- if (!domain->qi_batch) +- return -ENOMEM; +- } +- + ret = __cache_tag_assign_domain(domain, did, dev, pasid); + if (ret || domain->domain.type != IOMMU_DOMAIN_NESTED) + return ret; +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index a167d59101ae2e..cc23cfcdeb2d59 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -3372,6 +3372,9 @@ void device_block_translation(struct device *dev) + struct intel_iommu *iommu = info->iommu; + unsigned long flags; + ++ if (info->domain) ++ cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID); ++ + iommu_disable_pci_caps(info); + if (!dev_is_real_dma_subdevice(dev)) { + if (sm_supported(iommu)) +@@ -3388,7 +3391,6 @@ void device_block_translation(struct device *dev) + list_del(&info->link); + spin_unlock_irqrestore(&info->domain->lock, flags); + +- cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID); + domain_detach_iommu(info->domain, iommu); + info->domain = NULL; + } +diff --git a/drivers/md/dm-zoned-reclaim.c b/drivers/md/dm-zoned-reclaim.c +index d58db9a27e6cfd..76e2c686854871 100644 +--- a/drivers/md/dm-zoned-reclaim.c ++++ b/drivers/md/dm-zoned-reclaim.c +@@ -76,9 +76,9 @@ static int dmz_reclaim_align_wp(struct dmz_reclaim *zrc, struct dm_zone *zone, + * pointer and the requested position. + */ + nr_blocks = block - wp_block; +- ret = blkdev_issue_zeroout(dev->bdev, +- dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block), +- dmz_blk2sect(nr_blocks), GFP_NOIO, 0); ++ ret = blk_zone_issue_zeroout(dev->bdev, ++ dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block), ++ dmz_blk2sect(nr_blocks), GFP_NOIO); + if (ret) { + dmz_dev_err(dev, + "Align zone %u wp %llu to %llu (wp+%u) blocks failed %d", +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 15e0f14d0d49de..4d73abae503d1e 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1520,9 +1520,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, + struct slave *slave; + + mask = features; +- +- features &= ~NETIF_F_ONE_FOR_ALL; +- features |= NETIF_F_ALL_FOR_ALL; ++ features = netdev_base_features(features); + + bond_for_each_slave(bond, slave, iter) { + features = netdev_increment_features(features, +@@ -1536,6 +1534,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, + + #define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ + NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \ ++ NETIF_F_GSO_ENCAP_ALL | \ + NETIF_F_HIGHDMA | NETIF_F_LRO) + + #define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ +@@ -1564,8 +1563,9 @@ static void bond_compute_features(struct bonding *bond) + + if (!bond_has_slaves(bond)) + goto done; +- vlan_features &= NETIF_F_ALL_FOR_ALL; +- mpls_features &= NETIF_F_ALL_FOR_ALL; ++ ++ vlan_features = netdev_base_features(vlan_features); ++ mpls_features = netdev_base_features(mpls_features); + + bond_for_each_slave(bond, slave, iter) { + vlan_features = netdev_increment_features(vlan_features, +diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c +index 5290f5ad98f392..bf26cd0abf6dd9 100644 +--- a/drivers/net/dsa/microchip/ksz_common.c ++++ b/drivers/net/dsa/microchip/ksz_common.c +@@ -1098,10 +1098,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x1030, 0x1030), + regmap_reg_range(0x1100, 0x1115), + regmap_reg_range(0x111a, 0x111f), +- regmap_reg_range(0x1122, 0x1127), +- regmap_reg_range(0x112a, 0x112b), +- regmap_reg_range(0x1136, 0x1139), +- regmap_reg_range(0x113e, 0x113f), ++ regmap_reg_range(0x1120, 0x112b), ++ regmap_reg_range(0x1134, 0x113b), ++ regmap_reg_range(0x113c, 0x113f), + regmap_reg_range(0x1400, 0x1401), + regmap_reg_range(0x1403, 0x1403), + regmap_reg_range(0x1410, 0x1417), +@@ -1128,10 +1127,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x2030, 0x2030), + regmap_reg_range(0x2100, 0x2115), + regmap_reg_range(0x211a, 0x211f), +- regmap_reg_range(0x2122, 0x2127), +- regmap_reg_range(0x212a, 0x212b), +- regmap_reg_range(0x2136, 0x2139), +- regmap_reg_range(0x213e, 0x213f), ++ regmap_reg_range(0x2120, 0x212b), ++ regmap_reg_range(0x2134, 0x213b), ++ regmap_reg_range(0x213c, 0x213f), + regmap_reg_range(0x2400, 0x2401), + regmap_reg_range(0x2403, 0x2403), + regmap_reg_range(0x2410, 0x2417), +@@ -1158,10 +1156,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x3030, 0x3030), + regmap_reg_range(0x3100, 0x3115), + regmap_reg_range(0x311a, 0x311f), +- regmap_reg_range(0x3122, 0x3127), +- regmap_reg_range(0x312a, 0x312b), +- regmap_reg_range(0x3136, 0x3139), +- regmap_reg_range(0x313e, 0x313f), ++ regmap_reg_range(0x3120, 0x312b), ++ regmap_reg_range(0x3134, 0x313b), ++ regmap_reg_range(0x313c, 0x313f), + regmap_reg_range(0x3400, 0x3401), + regmap_reg_range(0x3403, 0x3403), + regmap_reg_range(0x3410, 0x3417), +@@ -1188,10 +1185,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x4030, 0x4030), + regmap_reg_range(0x4100, 0x4115), + regmap_reg_range(0x411a, 0x411f), +- regmap_reg_range(0x4122, 0x4127), +- regmap_reg_range(0x412a, 0x412b), +- regmap_reg_range(0x4136, 0x4139), +- regmap_reg_range(0x413e, 0x413f), ++ regmap_reg_range(0x4120, 0x412b), ++ regmap_reg_range(0x4134, 0x413b), ++ regmap_reg_range(0x413c, 0x413f), + regmap_reg_range(0x4400, 0x4401), + regmap_reg_range(0x4403, 0x4403), + regmap_reg_range(0x4410, 0x4417), +@@ -1218,10 +1214,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x5030, 0x5030), + regmap_reg_range(0x5100, 0x5115), + regmap_reg_range(0x511a, 0x511f), +- regmap_reg_range(0x5122, 0x5127), +- regmap_reg_range(0x512a, 0x512b), +- regmap_reg_range(0x5136, 0x5139), +- regmap_reg_range(0x513e, 0x513f), ++ regmap_reg_range(0x5120, 0x512b), ++ regmap_reg_range(0x5134, 0x513b), ++ regmap_reg_range(0x513c, 0x513f), + regmap_reg_range(0x5400, 0x5401), + regmap_reg_range(0x5403, 0x5403), + regmap_reg_range(0x5410, 0x5417), +@@ -1248,10 +1243,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x6030, 0x6030), + regmap_reg_range(0x6100, 0x6115), + regmap_reg_range(0x611a, 0x611f), +- regmap_reg_range(0x6122, 0x6127), +- regmap_reg_range(0x612a, 0x612b), +- regmap_reg_range(0x6136, 0x6139), +- regmap_reg_range(0x613e, 0x613f), ++ regmap_reg_range(0x6120, 0x612b), ++ regmap_reg_range(0x6134, 0x613b), ++ regmap_reg_range(0x613c, 0x613f), + regmap_reg_range(0x6300, 0x6301), + regmap_reg_range(0x6400, 0x6401), + regmap_reg_range(0x6403, 0x6403), +diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c +index 0102a82e88cc61..940f1b71226d64 100644 +--- a/drivers/net/dsa/ocelot/felix_vsc9959.c ++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c +@@ -24,7 +24,7 @@ + #define VSC9959_NUM_PORTS 6 + + #define VSC9959_TAS_GCL_ENTRY_MAX 63 +-#define VSC9959_TAS_MIN_GATE_LEN_NS 33 ++#define VSC9959_TAS_MIN_GATE_LEN_NS 35 + #define VSC9959_VCAP_POLICER_BASE 63 + #define VSC9959_VCAP_POLICER_MAX 383 + #define VSC9959_SWITCH_PCI_BAR 4 +@@ -1056,11 +1056,15 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot) + mdiobus_free(felix->imdio); + } + +-/* The switch considers any frame (regardless of size) as eligible for +- * transmission if the traffic class gate is open for at least 33 ns. ++/* The switch considers any frame (regardless of size) as eligible ++ * for transmission if the traffic class gate is open for at least ++ * VSC9959_TAS_MIN_GATE_LEN_NS. ++ * + * Overruns are prevented by cropping an interval at the end of the gate time +- * slot for which egress scheduling is blocked, but we need to still keep 33 ns +- * available for one packet to be transmitted, otherwise the port tc will hang. ++ * slot for which egress scheduling is blocked, but we need to still keep ++ * VSC9959_TAS_MIN_GATE_LEN_NS available for one packet to be transmitted, ++ * otherwise the port tc will hang. ++ * + * This function returns the size of a gate interval that remains available for + * setting the guard band, after reserving the space for one egress frame. + */ +@@ -1303,7 +1307,8 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) + * per-tc static guard band lengths, so it reduces the + * useful gate interval length. Therefore, be careful + * to calculate a guard band (and therefore max_sdu) +- * that still leaves 33 ns available in the time slot. ++ * that still leaves VSC9959_TAS_MIN_GATE_LEN_NS ++ * available in the time slot. + */ + max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte); + /* A TC gate may be completely closed, which is a +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 3d9ee91e1f8be0..dafc5a4039cd2c 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -1518,7 +1518,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, + if (TPA_START_IS_IPV6(tpa_start1)) + tpa_info->gso_type = SKB_GSO_TCPV6; + /* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */ +- else if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP && ++ else if (!BNXT_CHIP_P4_PLUS(bp) && + TPA_START_HASH_TYPE(tpa_start) == 3) + tpa_info->gso_type = SKB_GSO_TCPV6; + tpa_info->rss_hash = +@@ -2212,15 +2212,13 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) { + type = bnxt_rss_ext_op(bp, rxcmp); + } else { +- u32 hash_type = RX_CMP_HASH_TYPE(rxcmp); ++ u32 itypes = RX_CMP_ITYPES(rxcmp); + +- /* RSS profiles 1 and 3 with extract code 0 for inner +- * 4-tuple +- */ +- if (hash_type != 1 && hash_type != 3) +- type = PKT_HASH_TYPE_L3; +- else ++ if (itypes == RX_CMP_FLAGS_ITYPE_TCP || ++ itypes == RX_CMP_FLAGS_ITYPE_UDP) + type = PKT_HASH_TYPE_L4; ++ else ++ type = PKT_HASH_TYPE_L3; + } + skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type); + } +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +index 69231e85140b2e..9e05704d94450e 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h +@@ -267,6 +267,9 @@ struct rx_cmp { + (((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\ + RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) + ++#define RX_CMP_ITYPES(rxcmp) \ ++ (le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_FLAGS_ITYPES_MASK) ++ + #define RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp) \ + ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_LEGACY) >>\ + RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT) +@@ -378,7 +381,7 @@ struct rx_agg_cmp { + u32 rx_agg_cmp_opaque; + __le32 rx_agg_cmp_v; + #define RX_AGG_CMP_V (1 << 0) +- #define RX_AGG_CMP_AGG_ID (0xffff << 16) ++ #define RX_AGG_CMP_AGG_ID (0x0fff << 16) + #define RX_AGG_CMP_AGG_ID_SHIFT 16 + __le32 rx_agg_cmp_unused; + }; +@@ -416,7 +419,7 @@ struct rx_tpa_start_cmp { + #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT 7 + #define RX_TPA_START_CMP_AGG_ID (0x7f << 25) + #define RX_TPA_START_CMP_AGG_ID_SHIFT 25 +- #define RX_TPA_START_CMP_AGG_ID_P5 (0xffff << 16) ++ #define RX_TPA_START_CMP_AGG_ID_P5 (0x0fff << 16) + #define RX_TPA_START_CMP_AGG_ID_SHIFT_P5 16 + #define RX_TPA_START_CMP_METADATA1 (0xf << 28) + #define RX_TPA_START_CMP_METADATA1_SHIFT 28 +@@ -540,7 +543,7 @@ struct rx_tpa_end_cmp { + #define RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT 16 + #define RX_TPA_END_CMP_AGG_ID (0x7f << 25) + #define RX_TPA_END_CMP_AGG_ID_SHIFT 25 +- #define RX_TPA_END_CMP_AGG_ID_P5 (0xffff << 16) ++ #define RX_TPA_END_CMP_AGG_ID_P5 (0x0fff << 16) + #define RX_TPA_END_CMP_AGG_ID_SHIFT_P5 16 + + __le32 rx_tpa_end_cmp_tsdelta; +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +index bbf7641a0fc799..7e13cd69f68a1f 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +@@ -2077,7 +2077,7 @@ void t4_idma_monitor(struct adapter *adapter, + struct sge_idma_monitor_state *idma, + int hz, int ticks); + int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, +- unsigned int naddr, u8 *addr); ++ u8 start, unsigned int naddr, u8 *addr); + void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs, + u32 start_index, bool sleep_ok); + void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs, +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +index 2418645c882373..fb3933fbb8425e 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +@@ -3246,7 +3246,7 @@ static int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac) + + dev_info(pi->adapter->pdev_dev, + "Setting MAC %pM on VF %d\n", mac, vf); +- ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac); ++ ret = t4_set_vf_mac_acl(adap, vf + 1, pi->lport, 1, mac); + if (!ret) + ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac); + return ret; +diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +index 76de55306c4d01..175bf9b1305888 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +@@ -10215,11 +10215,12 @@ int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) + * t4_set_vf_mac_acl - Set MAC address for the specified VF + * @adapter: The adapter + * @vf: one of the VFs instantiated by the specified PF ++ * @start: The start port id associated with specified VF + * @naddr: the number of MAC addresses + * @addr: the MAC address(es) to be set to the specified VF + */ + int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, +- unsigned int naddr, u8 *addr) ++ u8 start, unsigned int naddr, u8 *addr) + { + struct fw_acl_mac_cmd cmd; + +@@ -10234,7 +10235,7 @@ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, + cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); + cmd.nmac = naddr; + +- switch (adapter->pf) { ++ switch (start) { + case 3: + memcpy(cmd.macaddr3, addr, sizeof(cmd.macaddr3)); + break; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +index 3d74109f82300e..49f22cad92bfd0 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +@@ -297,7 +297,9 @@ dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport) + if (ret) { + mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret); + kvfree(vport_caps); +- return ERR_PTR(ret); ++ if (ret == -EBUSY) ++ return ERR_PTR(-EBUSY); ++ return NULL; + } + + return vport_caps; +diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +index b64c814eac11e8..0c4c75b3682faa 100644 +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +@@ -693,12 +693,11 @@ static int sparx5_start(struct sparx5 *sparx5) + err = -ENXIO; + if (sparx5->fdma_irq >= 0) { + if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0) +- err = devm_request_threaded_irq(sparx5->dev, +- sparx5->fdma_irq, +- NULL, +- sparx5_fdma_handler, +- IRQF_ONESHOT, +- "sparx5-fdma", sparx5); ++ err = devm_request_irq(sparx5->dev, ++ sparx5->fdma_irq, ++ sparx5_fdma_handler, ++ 0, ++ "sparx5-fdma", sparx5); + if (!err) + err = sparx5_fdma_start(sparx5); + if (err) +diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c +index 062e486c002cf6..672508efce5c29 100644 +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c +@@ -1119,7 +1119,7 @@ int sparx5_port_init(struct sparx5 *sparx5, + spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN), + DEV10G_MAC_MAXLEN_CFG_MAX_LEN, + devinst, +- DEV10G_MAC_ENA_CFG(0)); ++ DEV10G_MAC_MAXLEN_CFG(0)); + + /* Handle Signal Detect in 10G PCS */ + spx5_inst_wr(PCS10G_BR_PCS_SD_CFG_SD_POL_SET(sd_pol) | +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index ca4ed58f1206dd..0c2ba2fa88c466 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -1315,7 +1315,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) + GFP_KERNEL); + if (!gc->irq_contexts) { + err = -ENOMEM; +- goto free_irq_vector; ++ goto free_irq_array; + } + + for (i = 0; i < nvec; i++) { +@@ -1372,6 +1372,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) + gc->max_num_msix = nvec; + gc->num_msix_usable = nvec; + cpus_read_unlock(); ++ kfree(irqs); + return 0; + + free_irq: +@@ -1384,8 +1385,9 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) + } + + kfree(gc->irq_contexts); +- kfree(irqs); + gc->irq_contexts = NULL; ++free_irq_array: ++ kfree(irqs); + free_irq_vector: + cpus_read_unlock(); + pci_free_irq_vectors(pdev); +diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c +index e172638b060102..808ce8e68d3937 100644 +--- a/drivers/net/ethernet/mscc/ocelot_ptp.c ++++ b/drivers/net/ethernet/mscc/ocelot_ptp.c +@@ -14,6 +14,8 @@ + #include + #include "ocelot.h" + ++#define OCELOT_PTP_TX_TSTAMP_TIMEOUT (5 * HZ) ++ + int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) + { + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); +@@ -495,6 +497,28 @@ static int ocelot_traps_to_ptp_rx_filter(unsigned int proto) + return HWTSTAMP_FILTER_NONE; + } + ++static int ocelot_ptp_tx_type_to_cmd(int tx_type, int *ptp_cmd) ++{ ++ switch (tx_type) { ++ case HWTSTAMP_TX_ON: ++ *ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; ++ break; ++ case HWTSTAMP_TX_ONESTEP_SYNC: ++ /* IFH_REW_OP_ONE_STEP_PTP updates the correctionField, ++ * what we need to update is the originTimestamp. ++ */ ++ *ptp_cmd = IFH_REW_OP_ORIGIN_PTP; ++ break; ++ case HWTSTAMP_TX_OFF: ++ *ptp_cmd = 0; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ return 0; ++} ++ + int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; +@@ -521,30 +545,19 @@ EXPORT_SYMBOL(ocelot_hwstamp_get); + int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ int ptp_cmd, old_ptp_cmd = ocelot_port->ptp_cmd; + bool l2 = false, l4 = false; + struct hwtstamp_config cfg; ++ bool old_l2, old_l4; + int err; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + /* Tx type sanity check */ +- switch (cfg.tx_type) { +- case HWTSTAMP_TX_ON: +- ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; +- break; +- case HWTSTAMP_TX_ONESTEP_SYNC: +- /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we +- * need to update the origin time. +- */ +- ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP; +- break; +- case HWTSTAMP_TX_OFF: +- ocelot_port->ptp_cmd = 0; +- break; +- default: +- return -ERANGE; +- } ++ err = ocelot_ptp_tx_type_to_cmd(cfg.tx_type, &ptp_cmd); ++ if (err) ++ return err; + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: +@@ -569,13 +582,27 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) + return -ERANGE; + } + ++ old_l2 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L2; ++ old_l4 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L4; ++ + err = ocelot_setup_ptp_traps(ocelot, port, l2, l4); + if (err) + return err; + ++ ocelot_port->ptp_cmd = ptp_cmd; ++ + cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto); + +- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; ++ if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) { ++ err = -EFAULT; ++ goto out_restore_ptp_traps; ++ } ++ ++ return 0; ++out_restore_ptp_traps: ++ ocelot_setup_ptp_traps(ocelot, port, old_l2, old_l4); ++ ocelot_port->ptp_cmd = old_ptp_cmd; ++ return err; + } + EXPORT_SYMBOL(ocelot_hwstamp_set); + +@@ -603,34 +630,87 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port, + } + EXPORT_SYMBOL(ocelot_get_ts_info); + +-static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port, +- struct sk_buff *clone) ++static struct sk_buff *ocelot_port_dequeue_ptp_tx_skb(struct ocelot *ocelot, ++ int port, u8 ts_id, ++ u32 seqid) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; +- unsigned long flags; ++ struct sk_buff *skb, *skb_tmp, *skb_match = NULL; ++ struct ptp_header *hdr; + +- spin_lock_irqsave(&ocelot->ts_id_lock, flags); ++ spin_lock(&ocelot->ts_id_lock); + +- if (ocelot_port->ptp_skbs_in_flight == OCELOT_MAX_PTP_ID || +- ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) { +- spin_unlock_irqrestore(&ocelot->ts_id_lock, flags); +- return -EBUSY; ++ skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { ++ if (OCELOT_SKB_CB(skb)->ts_id != ts_id) ++ continue; ++ ++ /* Check that the timestamp ID is for the expected PTP ++ * sequenceId. We don't have to test ptp_parse_header() against ++ * NULL, because we've pre-validated the packet's ptp_class. ++ */ ++ hdr = ptp_parse_header(skb, OCELOT_SKB_CB(skb)->ptp_class); ++ if (seqid != ntohs(hdr->sequence_id)) ++ continue; ++ ++ __skb_unlink(skb, &ocelot_port->tx_skbs); ++ ocelot->ptp_skbs_in_flight--; ++ skb_match = skb; ++ break; + } + +- skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; +- /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */ +- OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id; ++ spin_unlock(&ocelot->ts_id_lock); + +- ocelot_port->ts_id++; +- if (ocelot_port->ts_id == OCELOT_MAX_PTP_ID) +- ocelot_port->ts_id = 0; ++ return skb_match; ++} ++ ++static int ocelot_port_queue_ptp_tx_skb(struct ocelot *ocelot, int port, ++ struct sk_buff *clone) ++{ ++ struct ocelot_port *ocelot_port = ocelot->ports[port]; ++ DECLARE_BITMAP(ts_id_in_flight, OCELOT_MAX_PTP_ID); ++ struct sk_buff *skb, *skb_tmp; ++ unsigned long n; ++ ++ spin_lock(&ocelot->ts_id_lock); ++ ++ /* To get a better chance of acquiring a timestamp ID, first flush the ++ * stale packets still waiting in the TX timestamping queue. They are ++ * probably lost. ++ */ ++ skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { ++ if (time_before(OCELOT_SKB_CB(skb)->ptp_tx_time + ++ OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) { ++ dev_warn_ratelimited(ocelot->dev, ++ "port %d invalidating stale timestamp ID %u which seems lost\n", ++ port, OCELOT_SKB_CB(skb)->ts_id); ++ __skb_unlink(skb, &ocelot_port->tx_skbs); ++ kfree_skb(skb); ++ ocelot->ptp_skbs_in_flight--; ++ } else { ++ __set_bit(OCELOT_SKB_CB(skb)->ts_id, ts_id_in_flight); ++ } ++ } ++ ++ if (ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) { ++ spin_unlock(&ocelot->ts_id_lock); ++ return -EBUSY; ++ } ++ ++ n = find_first_zero_bit(ts_id_in_flight, OCELOT_MAX_PTP_ID); ++ if (n == OCELOT_MAX_PTP_ID) { ++ spin_unlock(&ocelot->ts_id_lock); ++ return -EBUSY; ++ } + +- ocelot_port->ptp_skbs_in_flight++; ++ /* Found an available timestamp ID, use it */ ++ OCELOT_SKB_CB(clone)->ts_id = n; ++ OCELOT_SKB_CB(clone)->ptp_tx_time = jiffies; + ocelot->ptp_skbs_in_flight++; ++ __skb_queue_tail(&ocelot_port->tx_skbs, clone); + +- skb_queue_tail(&ocelot_port->tx_skbs, clone); ++ spin_unlock(&ocelot->ts_id_lock); + +- spin_unlock_irqrestore(&ocelot->ts_id_lock, flags); ++ dev_dbg_ratelimited(ocelot->dev, "port %d timestamp id %lu\n", port, n); + + return 0; + } +@@ -687,10 +767,14 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port, + if (!(*clone)) + return -ENOMEM; + +- err = ocelot_port_add_txtstamp_skb(ocelot, port, *clone); +- if (err) ++ /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */ ++ err = ocelot_port_queue_ptp_tx_skb(ocelot, port, *clone); ++ if (err) { ++ kfree_skb(*clone); + return err; ++ } + ++ skb_shinfo(*clone)->tx_flags |= SKBTX_IN_PROGRESS; + OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd; + OCELOT_SKB_CB(*clone)->ptp_class = ptp_class; + } +@@ -726,28 +810,15 @@ static void ocelot_get_hwtimestamp(struct ocelot *ocelot, + spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + } + +-static bool ocelot_validate_ptp_skb(struct sk_buff *clone, u16 seqid) +-{ +- struct ptp_header *hdr; +- +- hdr = ptp_parse_header(clone, OCELOT_SKB_CB(clone)->ptp_class); +- if (WARN_ON(!hdr)) +- return false; +- +- return seqid == ntohs(hdr->sequence_id); +-} +- + void ocelot_get_txtstamp(struct ocelot *ocelot) + { + int budget = OCELOT_PTP_QUEUE_SZ; + + while (budget--) { +- struct sk_buff *skb, *skb_tmp, *skb_match = NULL; + struct skb_shared_hwtstamps shhwtstamps; + u32 val, id, seqid, txport; +- struct ocelot_port *port; ++ struct sk_buff *skb_match; + struct timespec64 ts; +- unsigned long flags; + + val = ocelot_read(ocelot, SYS_PTP_STATUS); + +@@ -762,36 +833,14 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) + txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val); + seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val); + +- port = ocelot->ports[txport]; +- +- spin_lock(&ocelot->ts_id_lock); +- port->ptp_skbs_in_flight--; +- ocelot->ptp_skbs_in_flight--; +- spin_unlock(&ocelot->ts_id_lock); +- + /* Retrieve its associated skb */ +-try_again: +- spin_lock_irqsave(&port->tx_skbs.lock, flags); +- +- skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { +- if (OCELOT_SKB_CB(skb)->ts_id != id) +- continue; +- __skb_unlink(skb, &port->tx_skbs); +- skb_match = skb; +- break; +- } +- +- spin_unlock_irqrestore(&port->tx_skbs.lock, flags); +- +- if (WARN_ON(!skb_match)) +- continue; +- +- if (!ocelot_validate_ptp_skb(skb_match, seqid)) { +- dev_err_ratelimited(ocelot->dev, +- "port %d received stale TX timestamp for seqid %d, discarding\n", +- txport, seqid); +- dev_kfree_skb_any(skb); +- goto try_again; ++ skb_match = ocelot_port_dequeue_ptp_tx_skb(ocelot, txport, id, ++ seqid); ++ if (!skb_match) { ++ dev_warn_ratelimited(ocelot->dev, ++ "port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n", ++ txport, seqid, id); ++ goto next_ts; + } + + /* Get the h/w timestamp */ +@@ -802,7 +851,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + skb_complete_tx_timestamp(skb_match, &shhwtstamps); + +- /* Next ts */ ++next_ts: + ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); + } + } +diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c +index 8f7ce6b51a1c9b..6b4b40c6e1fe00 100644 +--- a/drivers/net/ethernet/qualcomm/qca_spi.c ++++ b/drivers/net/ethernet/qualcomm/qca_spi.c +@@ -53,7 +53,7 @@ MODULE_PARM_DESC(qcaspi_burst_len, "Number of data bytes per burst. Use 1-5000." + + #define QCASPI_PLUGGABLE_MIN 0 + #define QCASPI_PLUGGABLE_MAX 1 +-static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; ++static int qcaspi_pluggable = QCASPI_PLUGGABLE_MAX; + module_param(qcaspi_pluggable, int, 0); + MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); + +@@ -812,7 +812,6 @@ qcaspi_netdev_init(struct net_device *dev) + + dev->mtu = QCAFRM_MAX_MTU; + dev->type = ARPHRD_ETHER; +- qca->clkspeed = qcaspi_clkspeed; + qca->burst_len = qcaspi_burst_len; + qca->spi_thread = NULL; + qca->buffer_size = (QCAFRM_MAX_MTU + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + +@@ -903,17 +902,15 @@ qca_spi_probe(struct spi_device *spi) + legacy_mode = of_property_read_bool(spi->dev.of_node, + "qca,legacy-mode"); + +- if (qcaspi_clkspeed == 0) { +- if (spi->max_speed_hz) +- qcaspi_clkspeed = spi->max_speed_hz; +- else +- qcaspi_clkspeed = QCASPI_CLK_SPEED; +- } ++ if (qcaspi_clkspeed) ++ spi->max_speed_hz = qcaspi_clkspeed; ++ else if (!spi->max_speed_hz) ++ spi->max_speed_hz = QCASPI_CLK_SPEED; + +- if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) || +- (qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) { +- dev_err(&spi->dev, "Invalid clkspeed: %d\n", +- qcaspi_clkspeed); ++ if (spi->max_speed_hz < QCASPI_CLK_SPEED_MIN || ++ spi->max_speed_hz > QCASPI_CLK_SPEED_MAX) { ++ dev_err(&spi->dev, "Invalid clkspeed: %u\n", ++ spi->max_speed_hz); + return -EINVAL; + } + +@@ -938,14 +935,13 @@ qca_spi_probe(struct spi_device *spi) + return -EINVAL; + } + +- dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n", ++ dev_info(&spi->dev, "ver=%s, clkspeed=%u, burst_len=%d, pluggable=%d\n", + QCASPI_DRV_VERSION, +- qcaspi_clkspeed, ++ spi->max_speed_hz, + qcaspi_burst_len, + qcaspi_pluggable); + + spi->mode = SPI_MODE_3; +- spi->max_speed_hz = qcaspi_clkspeed; + if (spi_setup(spi) < 0) { + dev_err(&spi->dev, "Unable to setup SPI device\n"); + return -EFAULT; +diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h +index 8f4808695e8206..0831cefc58b898 100644 +--- a/drivers/net/ethernet/qualcomm/qca_spi.h ++++ b/drivers/net/ethernet/qualcomm/qca_spi.h +@@ -89,7 +89,6 @@ struct qcaspi { + #endif + + /* user configurable options */ +- u32 clkspeed; + u8 legacy_mode; + u16 burst_len; + }; +diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c +index b80aa27a7214d4..09117110e3dd2a 100644 +--- a/drivers/net/ethernet/renesas/rswitch.c ++++ b/drivers/net/ethernet/renesas/rswitch.c +@@ -862,13 +862,10 @@ static void rswitch_tx_free(struct net_device *ndev) + struct rswitch_ext_desc *desc; + struct sk_buff *skb; + +- for (; rswitch_get_num_cur_queues(gq) > 0; +- gq->dirty = rswitch_next_queue_index(gq, false, 1)) { +- desc = &gq->tx_ring[gq->dirty]; +- if ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) +- break; +- ++ desc = &gq->tx_ring[gq->dirty]; ++ while ((desc->desc.die_dt & DT_MASK) == DT_FEMPTY) { + dma_rmb(); ++ + skb = gq->skbs[gq->dirty]; + if (skb) { + rdev->ndev->stats.tx_packets++; +@@ -879,7 +876,10 @@ static void rswitch_tx_free(struct net_device *ndev) + dev_kfree_skb_any(gq->skbs[gq->dirty]); + gq->skbs[gq->dirty] = NULL; + } ++ + desc->desc.die_dt = DT_EEMPTY; ++ gq->dirty = rswitch_next_queue_index(gq, false, 1); ++ desc = &gq->tx_ring[gq->dirty]; + } + } + +@@ -908,8 +908,10 @@ static int rswitch_poll(struct napi_struct *napi, int budget) + + if (napi_complete_done(napi, budget - quota)) { + spin_lock_irqsave(&priv->lock, flags); +- rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); +- rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); ++ if (test_bit(rdev->port, priv->opened_ports)) { ++ rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); ++ rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); ++ } + spin_unlock_irqrestore(&priv->lock, flags); + } + +@@ -1114,25 +1116,40 @@ static int rswitch_etha_wait_link_verification(struct rswitch_etha *etha) + + static void rswitch_rmac_setting(struct rswitch_etha *etha, const u8 *mac) + { +- u32 val; ++ u32 pis, lsc; + + rswitch_etha_write_mac_address(etha, mac); + ++ switch (etha->phy_interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ pis = MPIC_PIS_GMII; ++ break; ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_5GBASER: ++ pis = MPIC_PIS_XGMII; ++ break; ++ default: ++ pis = FIELD_GET(MPIC_PIS, ioread32(etha->addr + MPIC)); ++ break; ++ } ++ + switch (etha->speed) { + case 100: +- val = MPIC_LSC_100M; ++ lsc = MPIC_LSC_100M; + break; + case 1000: +- val = MPIC_LSC_1G; ++ lsc = MPIC_LSC_1G; + break; + case 2500: +- val = MPIC_LSC_2_5G; ++ lsc = MPIC_LSC_2_5G; + break; + default: +- return; ++ lsc = FIELD_GET(MPIC_LSC, ioread32(etha->addr + MPIC)); ++ break; + } + +- iowrite32(MPIC_PIS_GMII | val, etha->addr + MPIC); ++ rswitch_modify(etha->addr, MPIC, MPIC_PIS | MPIC_LSC, ++ FIELD_PREP(MPIC_PIS, pis) | FIELD_PREP(MPIC_LSC, lsc)); + } + + static void rswitch_etha_enable_mii(struct rswitch_etha *etha) +@@ -1538,20 +1555,20 @@ static int rswitch_open(struct net_device *ndev) + struct rswitch_device *rdev = netdev_priv(ndev); + unsigned long flags; + +- phy_start(ndev->phydev); ++ if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) ++ iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE); + + napi_enable(&rdev->napi); +- netif_start_queue(ndev); + + spin_lock_irqsave(&rdev->priv->lock, flags); ++ bitmap_set(rdev->priv->opened_ports, rdev->port, 1); + rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true); + rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true); + spin_unlock_irqrestore(&rdev->priv->lock, flags); + +- if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) +- iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE); ++ phy_start(ndev->phydev); + +- bitmap_set(rdev->priv->opened_ports, rdev->port, 1); ++ netif_start_queue(ndev); + + return 0; + }; +@@ -1563,7 +1580,16 @@ static int rswitch_stop(struct net_device *ndev) + unsigned long flags; + + netif_tx_stop_all_queues(ndev); ++ ++ phy_stop(ndev->phydev); ++ ++ spin_lock_irqsave(&rdev->priv->lock, flags); ++ rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false); ++ rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false); + bitmap_clear(rdev->priv->opened_ports, rdev->port, 1); ++ spin_unlock_irqrestore(&rdev->priv->lock, flags); ++ ++ napi_disable(&rdev->napi); + + if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) + iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID); +@@ -1576,14 +1602,6 @@ static int rswitch_stop(struct net_device *ndev) + kfree(ts_info); + } + +- spin_lock_irqsave(&rdev->priv->lock, flags); +- rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false); +- rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false); +- spin_unlock_irqrestore(&rdev->priv->lock, flags); +- +- phy_stop(ndev->phydev); +- napi_disable(&rdev->napi); +- + return 0; + }; + +@@ -1681,8 +1699,11 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd + if (dma_mapping_error(ndev->dev.parent, dma_addr_orig)) + goto err_kfree; + +- gq->skbs[gq->cur] = skb; +- gq->unmap_addrs[gq->cur] = dma_addr_orig; ++ /* Stored the skb at the last descriptor to avoid skb free before hardware completes send */ ++ gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = skb; ++ gq->unmap_addrs[(gq->cur + nr_desc - 1) % gq->ring_size] = dma_addr_orig; ++ ++ dma_wmb(); + + /* DT_FSTART should be set at last. So, this is reverse order. */ + for (i = nr_desc; i-- > 0; ) { +@@ -1694,14 +1715,13 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd + goto err_unmap; + } + +- wmb(); /* gq->cur must be incremented after die_dt was set */ +- + gq->cur = rswitch_next_queue_index(gq, true, nr_desc); + rswitch_modify(rdev->addr, GWTRC(gq->index), 0, BIT(gq->index % 32)); + + return ret; + + err_unmap: ++ gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = NULL; + dma_unmap_single(ndev->dev.parent, dma_addr_orig, skb->len, DMA_TO_DEVICE); + + err_kfree: +@@ -1889,7 +1909,6 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index + rdev->np_port = rswitch_get_port_node(rdev); + rdev->disabled = !rdev->np_port; + err = of_get_ethdev_address(rdev->np_port, ndev); +- of_node_put(rdev->np_port); + if (err) { + if (is_valid_ether_addr(rdev->etha->mac_addr)) + eth_hw_addr_set(ndev, rdev->etha->mac_addr); +@@ -1919,6 +1938,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index + + out_rxdmac: + out_get_params: ++ of_node_put(rdev->np_port); + netif_napi_del(&rdev->napi); + free_netdev(ndev); + +@@ -1932,6 +1952,7 @@ static void rswitch_device_free(struct rswitch_private *priv, unsigned int index + + rswitch_txdmac_free(ndev); + rswitch_rxdmac_free(ndev); ++ of_node_put(rdev->np_port); + netif_napi_del(&rdev->napi); + free_netdev(ndev); + } +diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h +index 72e3ff596d3183..e020800dcc570e 100644 +--- a/drivers/net/ethernet/renesas/rswitch.h ++++ b/drivers/net/ethernet/renesas/rswitch.h +@@ -724,13 +724,13 @@ enum rswitch_etha_mode { + + #define EAVCC_VEM_SC_TAG (0x3 << 16) + +-#define MPIC_PIS_MII 0x00 +-#define MPIC_PIS_GMII 0x02 +-#define MPIC_PIS_XGMII 0x04 +-#define MPIC_LSC_SHIFT 3 +-#define MPIC_LSC_100M (1 << MPIC_LSC_SHIFT) +-#define MPIC_LSC_1G (2 << MPIC_LSC_SHIFT) +-#define MPIC_LSC_2_5G (3 << MPIC_LSC_SHIFT) ++#define MPIC_PIS GENMASK(2, 0) ++#define MPIC_PIS_GMII 2 ++#define MPIC_PIS_XGMII 4 ++#define MPIC_LSC GENMASK(5, 3) ++#define MPIC_LSC_100M 1 ++#define MPIC_LSC_1G 2 ++#define MPIC_LSC_2_5G 3 + + #define MDIO_READ_C45 0x03 + #define MDIO_WRITE_C45 0x01 +diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c +index 18191d5a8bd4d3..6ace5a74cddb57 100644 +--- a/drivers/net/team/team_core.c ++++ b/drivers/net/team/team_core.c +@@ -983,7 +983,8 @@ static void team_port_disable(struct team *team, + + #define TEAM_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ + NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \ +- NETIF_F_HIGHDMA | NETIF_F_LRO) ++ NETIF_F_HIGHDMA | NETIF_F_LRO | \ ++ NETIF_F_GSO_ENCAP_ALL) + + #define TEAM_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ + NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE) +@@ -991,13 +992,14 @@ static void team_port_disable(struct team *team, + static void __team_compute_features(struct team *team) + { + struct team_port *port; +- netdev_features_t vlan_features = TEAM_VLAN_FEATURES & +- NETIF_F_ALL_FOR_ALL; ++ netdev_features_t vlan_features = TEAM_VLAN_FEATURES; + netdev_features_t enc_features = TEAM_ENC_FEATURES; + unsigned short max_hard_header_len = ETH_HLEN; + unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | + IFF_XMIT_DST_RELEASE_PERM; + ++ vlan_features = netdev_base_features(vlan_features); ++ + rcu_read_lock(); + list_for_each_entry_rcu(port, &team->port_list, list) { + vlan_features = netdev_increment_features(vlan_features, +@@ -2012,8 +2014,7 @@ static netdev_features_t team_fix_features(struct net_device *dev, + netdev_features_t mask; + + mask = features; +- features &= ~NETIF_F_ONE_FOR_ALL; +- features |= NETIF_F_ALL_FOR_ALL; ++ features = netdev_base_features(features); + + rcu_read_lock(); + list_for_each_entry_rcu(port, &team->port_list, list) { +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index c897afef0b414c..60027b439021b8 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -502,6 +502,7 @@ struct virtio_net_common_hdr { + }; + + static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf); ++static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq); + static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp, + struct net_device *dev, + unsigned int *xdp_xmit, +@@ -2898,7 +2899,6 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index) + if (err < 0) + goto err_xdp_reg_mem_model; + +- netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, qp_index)); + virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi); + virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi); + +@@ -3166,7 +3166,7 @@ static int virtnet_rx_resize(struct virtnet_info *vi, + + virtnet_rx_pause(vi, rq); + +- err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf); ++ err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL); + if (err) + netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err); + +@@ -3229,7 +3229,8 @@ static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq, + + virtnet_tx_pause(vi, sq); + +- err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf); ++ err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf, ++ virtnet_sq_free_unused_buf_done); + if (err) + netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err); + +@@ -5997,6 +5998,14 @@ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf) + xdp_return_frame(ptr_to_xdp(buf)); + } + ++static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq) ++{ ++ struct virtnet_info *vi = vq->vdev->priv; ++ int i = vq2txq(vq); ++ ++ netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i)); ++} ++ + static void free_unused_bufs(struct virtnet_info *vi) + { + void *buf; +@@ -6728,11 +6737,20 @@ static int virtnet_probe(struct virtio_device *vdev) + + static void remove_vq_common(struct virtnet_info *vi) + { ++ int i; ++ + virtio_reset_device(vi->vdev); + + /* Free unused buffers in both send and recv, if any. */ + free_unused_bufs(vi); + ++ /* ++ * Rule of thumb is netdev_tx_reset_queue() should follow any ++ * skb freeing not followed by netdev_tx_completed_queue() ++ */ ++ for (i = 0; i < vi->max_queue_pairs; i++) ++ netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i)); ++ + free_receive_bufs(vi); + + free_receive_page_frags(vi); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +index a7a10e716e6517..e96ddaeeeeff52 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +@@ -1967,7 +1967,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, + if (csa_err_mask & (CS_ERR_COUNT_ERROR | + CS_ERR_LONG_DELAY_AFTER_CS | + CS_ERR_TX_BLOCK_TIMER_EXPIRED)) +- ieee80211_channel_switch_disconnect(vif, true); ++ ieee80211_channel_switch_disconnect(vif); + rcu_read_unlock(); + } + +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index 4265c1cd0ff716..63fe51d0e64db3 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -867,7 +867,7 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev + static int xennet_close(struct net_device *dev) + { + struct netfront_info *np = netdev_priv(dev); +- unsigned int num_queues = dev->real_num_tx_queues; ++ unsigned int num_queues = np->queues ? dev->real_num_tx_queues : 0; + unsigned int i; + struct netfront_queue *queue; + netif_tx_stop_all_queues(np->netdev); +@@ -882,6 +882,9 @@ static void xennet_destroy_queues(struct netfront_info *info) + { + unsigned int i; + ++ if (!info->queues) ++ return; ++ + for (i = 0; i < info->netdev->real_num_tx_queues; i++) { + struct netfront_queue *queue = &info->queues[i]; + +diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c +index 617c8d6706d3d0..6cea4fe39bcfe4 100644 +--- a/drivers/ptp/ptp_kvm_x86.c ++++ b/drivers/ptp/ptp_kvm_x86.c +@@ -26,7 +26,7 @@ int kvm_arch_ptp_init(void) + long ret; + + if (!kvm_para_available()) +- return -ENODEV; ++ return -EOPNOTSUPP; + + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { + p = alloc_page(GFP_KERNEL | __GFP_ZERO); +@@ -46,14 +46,14 @@ int kvm_arch_ptp_init(void) + + clock_pair_gpa = slow_virt_to_phys(clock_pair); + if (!pvclock_get_pvti_cpu0_va()) { +- ret = -ENODEV; ++ ret = -EOPNOTSUPP; + goto err; + } + + ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa, + KVM_CLOCK_PAIRING_WALLCLOCK); + if (ret == -KVM_ENOSYS) { +- ret = -ENODEV; ++ ret = -EOPNOTSUPP; + goto err; + } + +diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c +index a8e91d9d028b89..945d2917b91bac 100644 +--- a/drivers/regulator/axp20x-regulator.c ++++ b/drivers/regulator/axp20x-regulator.c +@@ -371,8 +371,8 @@ + .ops = &axp20x_ops, \ + } + +-#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ +- _vmask, _ereg, _emask) \ ++#define AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ ++ _vmask, _ereg, _emask, _ramp_delay) \ + [_family##_##_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ +@@ -388,9 +388,15 @@ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ ++ .ramp_delay = (_ramp_delay), \ + .ops = &axp20x_ops, \ + } + ++#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ ++ _vmask, _ereg, _emask) \ ++ AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ ++ _vmask, _ereg, _emask, 0) ++ + #define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \ + [_family##_##_id] = { \ + .name = (_match), \ +@@ -419,8 +425,8 @@ + .ops = &axp20x_ops_fixed \ + } + +-#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ +- _vreg, _vmask, _ereg, _emask) \ ++#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ ++ _vreg, _vmask, _ereg, _emask, _ramp_delay) \ + [_family##_##_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ +@@ -436,9 +442,15 @@ + .enable_mask = (_emask), \ + .linear_ranges = (_ranges), \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ ++ .ramp_delay = (_ramp_delay), \ + .ops = &axp20x_ops_range, \ + } + ++#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ ++ _vreg, _vmask, _ereg, _emask) \ ++ AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \ ++ _n_voltages, _vreg, _vmask, _ereg, _emask, 0) ++ + static const int axp209_dcdc2_ldo3_slew_rates[] = { + 1600, + 800, +@@ -781,21 +793,21 @@ static const struct linear_range axp717_dcdc3_ranges[] = { + }; + + static const struct regulator_desc axp717_regulators[] = { +- AXP_DESC_RANGES(AXP717, DCDC1, "dcdc1", "vin1", ++ AXP_DESC_RANGES_DELAY(AXP717, DCDC1, "dcdc1", "vin1", + axp717_dcdc1_ranges, AXP717_DCDC1_NUM_VOLTAGES, + AXP717_DCDC1_CONTROL, AXP717_DCDC_V_OUT_MASK, +- AXP717_DCDC_OUTPUT_CONTROL, BIT(0)), +- AXP_DESC_RANGES(AXP717, DCDC2, "dcdc2", "vin2", ++ AXP717_DCDC_OUTPUT_CONTROL, BIT(0), 640), ++ AXP_DESC_RANGES_DELAY(AXP717, DCDC2, "dcdc2", "vin2", + axp717_dcdc2_ranges, AXP717_DCDC2_NUM_VOLTAGES, + AXP717_DCDC2_CONTROL, AXP717_DCDC_V_OUT_MASK, +- AXP717_DCDC_OUTPUT_CONTROL, BIT(1)), +- AXP_DESC_RANGES(AXP717, DCDC3, "dcdc3", "vin3", ++ AXP717_DCDC_OUTPUT_CONTROL, BIT(1), 640), ++ AXP_DESC_RANGES_DELAY(AXP717, DCDC3, "dcdc3", "vin3", + axp717_dcdc3_ranges, AXP717_DCDC3_NUM_VOLTAGES, + AXP717_DCDC3_CONTROL, AXP717_DCDC_V_OUT_MASK, +- AXP717_DCDC_OUTPUT_CONTROL, BIT(2)), +- AXP_DESC(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100, ++ AXP717_DCDC_OUTPUT_CONTROL, BIT(2), 640), ++ AXP_DESC_DELAY(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100, + AXP717_DCDC4_CONTROL, AXP717_DCDC_V_OUT_MASK, +- AXP717_DCDC_OUTPUT_CONTROL, BIT(3)), ++ AXP717_DCDC_OUTPUT_CONTROL, BIT(3), 6400), + AXP_DESC(AXP717, ALDO1, "aldo1", "aldoin", 500, 3500, 100, + AXP717_ALDO1_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(0)), +diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c +index bbd417c55e7f56..b0e3f307b28353 100644 +--- a/drivers/spi/spi-aspeed-smc.c ++++ b/drivers/spi/spi-aspeed-smc.c +@@ -239,7 +239,7 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip, + + ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, offset, op->cmd.opcode); + if (ret < 0) +- return ret; ++ goto stop_user; + + if (op->dummy.buswidth && op->dummy.nbytes) { + for (i = 0; i < op->dummy.nbytes / op->dummy.buswidth; i++) +@@ -249,8 +249,9 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip, + aspeed_spi_set_io_mode(chip, io_mode); + + aspeed_spi_read_from_ahb(buf, chip->ahb_base, len); ++stop_user: + aspeed_spi_stop_user(chip); +- return 0; ++ return ret; + } + + static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, +@@ -261,10 +262,11 @@ static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, + aspeed_spi_start_user(chip); + ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode); + if (ret < 0) +- return ret; ++ goto stop_user; + aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes); ++stop_user: + aspeed_spi_stop_user(chip); +- return 0; ++ return ret; + } + + /* support for 1-1-1, 1-1-2 or 1-1-4 */ +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 0bb33c43b1b46e..40a64a598a7495 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -241,6 +241,20 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) + struct spi_controller *ctlr = spi->controller; + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable; ++ bool cs_actual; ++ ++ /* ++ * SPI subsystem tries to avoid no-op calls that would break the PM ++ * refcount below. It can't however for the first time it is used. ++ * To detect this case we read it here and bail out early for no-ops. ++ */ ++ if (spi_get_csgpiod(spi, 0)) ++ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & 1); ++ else ++ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & ++ BIT(spi_get_chipselect(spi, 0))); ++ if (unlikely(cs_actual == cs_asserted)) ++ return; + + if (cs_asserted) { + /* Keep things powered as long as CS is asserted */ +diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c +index b80e9a528e17ff..bdf17eafd3598d 100644 +--- a/drivers/tty/serial/sh-sci.c ++++ b/drivers/tty/serial/sh-sci.c +@@ -157,6 +157,7 @@ struct sci_port { + + bool has_rtscts; + bool autorts; ++ bool tx_occurred; + }; + + #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS +@@ -850,6 +851,7 @@ static void sci_transmit_chars(struct uart_port *port) + { + struct tty_port *tport = &port->state->port; + unsigned int stopped = uart_tx_stopped(port); ++ struct sci_port *s = to_sci_port(port); + unsigned short status; + unsigned short ctrl; + int count; +@@ -885,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port) + } + + sci_serial_out(port, SCxTDR, c); ++ s->tx_occurred = true; + + port->icount.tx++; + } while (--count > 0); +@@ -1241,6 +1244,8 @@ static void sci_dma_tx_complete(void *arg) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + ++ s->tx_occurred = true; ++ + if (!kfifo_is_empty(&tport->xmit_fifo)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); +@@ -1731,6 +1736,19 @@ static void sci_flush_buffer(struct uart_port *port) + s->cookie_tx = -EINVAL; + } + } ++ ++static void sci_dma_check_tx_occurred(struct sci_port *s) ++{ ++ struct dma_tx_state state; ++ enum dma_status status; ++ ++ if (!s->chan_tx) ++ return; ++ ++ status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); ++ if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS) ++ s->tx_occurred = true; ++} + #else /* !CONFIG_SERIAL_SH_SCI_DMA */ + static inline void sci_request_dma(struct uart_port *port) + { +@@ -1740,6 +1758,10 @@ static inline void sci_free_dma(struct uart_port *port) + { + } + ++static void sci_dma_check_tx_occurred(struct sci_port *s) ++{ ++} ++ + #define sci_flush_buffer NULL + #endif /* !CONFIG_SERIAL_SH_SCI_DMA */ + +@@ -2076,6 +2098,12 @@ static unsigned int sci_tx_empty(struct uart_port *port) + { + unsigned short status = sci_serial_in(port, SCxSR); + unsigned short in_tx_fifo = sci_txfill(port); ++ struct sci_port *s = to_sci_port(port); ++ ++ sci_dma_check_tx_occurred(s); ++ ++ if (!s->tx_occurred) ++ return TIOCSER_TEMT; + + return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; + } +@@ -2247,6 +2275,7 @@ static int sci_startup(struct uart_port *port) + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + ++ s->tx_occurred = false; + sci_request_dma(port); + + ret = sci_request_irq(s); +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index cfebe4a1af9e84..bc13133efaa508 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -5566,6 +5566,7 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag, + + lrbp = &hba->lrb[task_tag]; + lrbp->compl_time_stamp = ktime_get(); ++ lrbp->compl_time_stamp_local_clock = local_clock(); + cmd = lrbp->cmd; + if (cmd) { + if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) +diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c +index 500dc35e64774d..0b2490347b9fe7 100644 +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -2794,8 +2794,14 @@ int usb_add_hcd(struct usb_hcd *hcd, + int retval; + struct usb_device *rhdev; + struct usb_hcd *shared_hcd; ++ int skip_phy_initialization; + +- if (!hcd->skip_phy_initialization) { ++ if (usb_hcd_is_primary_hcd(hcd)) ++ skip_phy_initialization = hcd->skip_phy_initialization; ++ else ++ skip_phy_initialization = hcd->primary_hcd->skip_phy_initialization; ++ ++ if (!skip_phy_initialization) { + if (usb_hcd_is_primary_hcd(hcd)) { + hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev); + if (IS_ERR(hcd->phy_roothub)) +diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c +index cb54390e7de488..8c3941ecaaf5d4 100644 +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -3546,11 +3546,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + port_status |= USB_PORT_STAT_C_OVERCURRENT << 16; + } + +- if (!hsotg->flags.b.port_connect_status) { ++ if (dwc2_is_device_mode(hsotg)) { + /* +- * The port is disconnected, which means the core is +- * either in device mode or it soon will be. Just +- * return 0's for the remainder of the port status ++ * Just return 0's for the remainder of the port status + * since the port register can't be read if the core + * is in device mode. + */ +@@ -3620,13 +3618,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) + goto error; + +- if (!hsotg->flags.b.port_connect_status) { ++ if (dwc2_is_device_mode(hsotg)) { + /* +- * The port is disconnected, which means the core is +- * either in device mode or it soon will be. Just +- * return without doing anything since the port +- * register can't be written if the core is in device +- * mode. ++ * Just return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. + */ + break; + } +@@ -4349,7 +4345,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) + if (hsotg->bus_suspended) + goto skip_power_saving; + +- if (hsotg->flags.b.port_connect_status == 0) ++ if (!(dwc2_read_hprt0(hsotg) & HPRT0_CONNSTS)) + goto skip_power_saving; + + switch (hsotg->params.power_down) { +@@ -4431,6 +4427,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) + * Power Down mode. + */ + if (hprt0 & HPRT0_CONNSTS) { ++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + hsotg->lx_state = DWC2_L0; + goto unlock; + } +diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c +index 64c0cd1995aa06..e99faf014c78a6 100644 +--- a/drivers/usb/dwc3/dwc3-imx8mp.c ++++ b/drivers/usb/dwc3/dwc3-imx8mp.c +@@ -129,6 +129,16 @@ static void dwc3_imx8mp_wakeup_disable(struct dwc3_imx8mp *dwc3_imx) + writel(val, dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); + } + ++static const struct property_entry dwc3_imx8mp_properties[] = { ++ PROPERTY_ENTRY_BOOL("xhci-missing-cas-quirk"), ++ PROPERTY_ENTRY_BOOL("xhci-skip-phy-init-quirk"), ++ {}, ++}; ++ ++static const struct software_node dwc3_imx8mp_swnode = { ++ .properties = dwc3_imx8mp_properties, ++}; ++ + static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) + { + struct dwc3_imx8mp *dwc3_imx = _dwc3_imx; +@@ -148,17 +158,6 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) + return IRQ_HANDLED; + } + +-static int dwc3_imx8mp_set_software_node(struct device *dev) +-{ +- struct property_entry props[3] = { 0 }; +- int prop_idx = 0; +- +- props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-missing-cas-quirk"); +- props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-skip-phy-init-quirk"); +- +- return device_create_managed_software_node(dev, props, NULL); +-} +- + static int dwc3_imx8mp_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -221,17 +220,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) + if (err < 0) + goto disable_rpm; + +- err = dwc3_imx8mp_set_software_node(dev); ++ err = device_add_software_node(dev, &dwc3_imx8mp_swnode); + if (err) { + err = -ENODEV; +- dev_err(dev, "failed to create software node\n"); ++ dev_err(dev, "failed to add software node\n"); + goto disable_rpm; + } + + err = of_platform_populate(node, NULL, NULL, dev); + if (err) { + dev_err(&pdev->dev, "failed to create dwc3 core\n"); +- goto disable_rpm; ++ goto remove_swnode; + } + + dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np); +@@ -255,6 +254,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) + + depopulate: + of_platform_depopulate(dev); ++remove_swnode: ++ device_remove_software_node(dev); + disable_rpm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +@@ -268,6 +269,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + of_platform_depopulate(dev); ++ device_remove_software_node(dev); + + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c +index b5e5be424ce997..96c87dc4757f22 100644 +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -121,8 +121,11 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) + * in use but the usb3-phy entry is missing from the device tree. + * Therefore, skip these operations in this case. + */ +- if (!priv_data->usb3_phy) ++ if (!priv_data->usb3_phy) { ++ /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */ ++ writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); + goto skip_usb3_phy; ++ } + + crst = devm_reset_control_get_exclusive(dev, "usb_crst"); + if (IS_ERR(crst)) { +diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c +index 8285df9ed6fd78..8c9d0074db588b 100644 +--- a/drivers/usb/gadget/function/f_midi2.c ++++ b/drivers/usb/gadget/function/f_midi2.c +@@ -1593,7 +1593,11 @@ static int f_midi2_create_card(struct f_midi2 *midi2) + fb->info.midi_ci_version = b->midi_ci_version; + fb->info.ui_hint = reverse_dir(b->ui_hint); + fb->info.sysex8_streams = b->sysex8_streams; +- fb->info.flags |= b->is_midi1; ++ if (b->is_midi1 < 2) ++ fb->info.flags |= b->is_midi1; ++ else ++ fb->info.flags |= SNDRV_UMP_BLOCK_IS_MIDI1 | ++ SNDRV_UMP_BLOCK_IS_LOWSPEED; + strscpy(fb->info.name, ump_fb_name(b), + sizeof(fb->info.name)); + } +diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c +index 0a8c05b2746b4e..53d9fc41acc522 100644 +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -579,9 +579,12 @@ static int gs_start_io(struct gs_port *port) + * we didn't in gs_start_tx() */ + tty_wakeup(port->port.tty); + } else { +- gs_free_requests(ep, head, &port->read_allocated); +- gs_free_requests(port->port_usb->in, &port->write_pool, +- &port->write_allocated); ++ /* Free reqs only if we are still connected */ ++ if (port->port_usb) { ++ gs_free_requests(ep, head, &port->read_allocated); ++ gs_free_requests(port->port_usb->in, &port->write_pool, ++ &port->write_allocated); ++ } + status = -EIO; + } + +diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c +index d31d9506e41ab0..7c2b2339e674dd 100644 +--- a/drivers/usb/host/ehci-sh.c ++++ b/drivers/usb/host/ehci-sh.c +@@ -119,8 +119,12 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) + if (IS_ERR(priv->iclk)) + priv->iclk = NULL; + +- clk_enable(priv->fclk); +- clk_enable(priv->iclk); ++ ret = clk_enable(priv->fclk); ++ if (ret) ++ goto fail_request_resource; ++ ret = clk_enable(priv->iclk); ++ if (ret) ++ goto fail_iclk; + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret != 0) { +@@ -136,6 +140,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) + + fail_add_hcd: + clk_disable(priv->iclk); ++fail_iclk: + clk_disable(priv->fclk); + + fail_request_resource: +diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c +index 9fe4f48b18980c..0881fdd1823e0b 100644 +--- a/drivers/usb/host/max3421-hcd.c ++++ b/drivers/usb/host/max3421-hcd.c +@@ -779,11 +779,17 @@ max3421_check_unlink(struct usb_hcd *hcd) + retval = 1; + dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", + __func__, urb, urb->unlinked); +- usb_hcd_unlink_urb_from_ep(hcd, urb); +- spin_unlock_irqrestore(&max3421_hcd->lock, +- flags); +- usb_hcd_giveback_urb(hcd, urb, 0); +- spin_lock_irqsave(&max3421_hcd->lock, flags); ++ if (urb == max3421_hcd->curr_urb) { ++ max3421_hcd->urb_done = 1; ++ max3421_hcd->hien &= ~(BIT(MAX3421_HI_HXFRDN_BIT) | ++ BIT(MAX3421_HI_RCVDAV_BIT)); ++ } else { ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++ spin_unlock_irqrestore(&max3421_hcd->lock, ++ flags); ++ usb_hcd_giveback_urb(hcd, urb, 0); ++ spin_lock_irqsave(&max3421_hcd->lock, flags); ++ } + } + } + } +diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c +index 75dfdca04ff1c2..27b0a6e182678b 100644 +--- a/drivers/usb/misc/onboard_usb_dev.c ++++ b/drivers/usb/misc/onboard_usb_dev.c +@@ -407,8 +407,10 @@ static int onboard_dev_probe(struct platform_device *pdev) + } + + if (of_device_is_compatible(pdev->dev.of_node, "usb424,2744") || +- of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) ++ of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) { + err = onboard_dev_5744_i2c_init(client); ++ onboard_dev->always_powered_in_suspend = true; ++ } + + put_device(&client->dev); + if (err < 0) +diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c +index d1e7c487ddfbb5..0ae0a5ee3fae07 100644 +--- a/drivers/usb/typec/anx7411.c ++++ b/drivers/usb/typec/anx7411.c +@@ -290,6 +290,8 @@ struct anx7411_data { + struct power_supply *psy; + struct power_supply_desc psy_desc; + struct device *dev; ++ struct fwnode_handle *switch_node; ++ struct fwnode_handle *mux_node; + }; + + static u8 snk_identity[] = { +@@ -1021,6 +1023,16 @@ static void anx7411_port_unregister_altmodes(struct typec_altmode **adev) + } + } + ++static void anx7411_port_unregister(struct typec_params *typecp) ++{ ++ fwnode_handle_put(typecp->caps.fwnode); ++ anx7411_port_unregister_altmodes(typecp->port_amode); ++ if (typecp->port) ++ typec_unregister_port(typecp->port); ++ if (typecp->role_sw) ++ usb_role_switch_put(typecp->role_sw); ++} ++ + static int anx7411_usb_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) + { +@@ -1089,6 +1101,7 @@ static void anx7411_unregister_mux(struct anx7411_data *ctx) + if (ctx->typec.typec_mux) { + typec_mux_unregister(ctx->typec.typec_mux); + ctx->typec.typec_mux = NULL; ++ fwnode_handle_put(ctx->mux_node); + } + } + +@@ -1097,6 +1110,7 @@ static void anx7411_unregister_switch(struct anx7411_data *ctx) + if (ctx->typec.typec_switch) { + typec_switch_unregister(ctx->typec.typec_switch); + ctx->typec.typec_switch = NULL; ++ fwnode_handle_put(ctx->switch_node); + } + } + +@@ -1104,28 +1118,29 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, + struct device *dev) + { + int ret; +- struct device_node *node; + +- node = of_get_child_by_name(dev->of_node, "orientation_switch"); +- if (!node) ++ ctx->switch_node = device_get_named_child_node(dev, "orientation_switch"); ++ if (!ctx->switch_node) + return 0; + +- ret = anx7411_register_switch(ctx, dev, &node->fwnode); ++ ret = anx7411_register_switch(ctx, dev, ctx->switch_node); + if (ret) { + dev_err(dev, "failed register switch"); ++ fwnode_handle_put(ctx->switch_node); + return ret; + } + +- node = of_get_child_by_name(dev->of_node, "mode_switch"); +- if (!node) { ++ ctx->mux_node = device_get_named_child_node(dev, "mode_switch"); ++ if (!ctx->mux_node) { + dev_err(dev, "no typec mux exist"); + ret = -ENODEV; + goto unregister_switch; + } + +- ret = anx7411_register_mux(ctx, dev, &node->fwnode); ++ ret = anx7411_register_mux(ctx, dev, ctx->mux_node); + if (ret) { + dev_err(dev, "failed register mode switch"); ++ fwnode_handle_put(ctx->mux_node); + ret = -ENODEV; + goto unregister_switch; + } +@@ -1154,34 +1169,34 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, + ret = fwnode_property_read_string(fwnode, "power-role", &buf); + if (ret) { + dev_err(dev, "power-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_port_power_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->type = ret; + + ret = fwnode_property_read_string(fwnode, "data-role", &buf); + if (ret) { + dev_err(dev, "data-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_port_data_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->data = ret; + + ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); + if (ret) { + dev_err(dev, "try-power-role not found: %d\n", ret); +- return ret; ++ goto put_fwnode; + } + + ret = typec_find_power_role(buf); + if (ret < 0) +- return ret; ++ goto put_fwnode; + cap->prefer_role = ret; + + /* Get source pdos */ +@@ -1193,7 +1208,7 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, + typecp->src_pdo_nr); + if (ret < 0) { + dev_err(dev, "source cap validate failed: %d\n", ret); +- return -EINVAL; ++ goto put_fwnode; + } + + typecp->caps_flags |= HAS_SOURCE_CAP; +@@ -1207,7 +1222,7 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, + typecp->sink_pdo_nr); + if (ret < 0) { + dev_err(dev, "sink cap validate failed: %d\n", ret); +- return -EINVAL; ++ goto put_fwnode; + } + + for (i = 0; i < typecp->sink_pdo_nr; i++) { +@@ -1251,13 +1266,21 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, + ret = PTR_ERR(ctx->typec.port); + ctx->typec.port = NULL; + dev_err(dev, "Failed to register type c port %d\n", ret); +- return ret; ++ goto put_usb_role_switch; + } + + typec_port_register_altmodes(ctx->typec.port, NULL, ctx, + ctx->typec.port_amode, + MAX_ALTMODE); + return 0; ++ ++put_usb_role_switch: ++ if (ctx->typec.role_sw) ++ usb_role_switch_put(ctx->typec.role_sw); ++put_fwnode: ++ fwnode_handle_put(fwnode); ++ ++ return ret; + } + + static int anx7411_typec_check_connection(struct anx7411_data *ctx) +@@ -1523,8 +1546,7 @@ static int anx7411_i2c_probe(struct i2c_client *client) + destroy_workqueue(plat->workqueue); + + free_typec_port: +- typec_unregister_port(plat->typec.port); +- anx7411_port_unregister_altmodes(plat->typec.port_amode); ++ anx7411_port_unregister(&plat->typec); + + free_typec_switch: + anx7411_unregister_switch(plat); +@@ -1548,17 +1570,11 @@ static void anx7411_i2c_remove(struct i2c_client *client) + + i2c_unregister_device(plat->spi_client); + +- if (plat->typec.role_sw) +- usb_role_switch_put(plat->typec.role_sw); +- + anx7411_unregister_mux(plat); + + anx7411_unregister_switch(plat); + +- if (plat->typec.port) +- typec_unregister_port(plat->typec.port); +- +- anx7411_port_unregister_altmodes(plat->typec.port_amode); ++ anx7411_port_unregister(&plat->typec); + } + + static const struct i2c_device_id anx7411_id[] = { +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index e0f3925e401b3d..7a3f0f5af38fdb 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -46,11 +46,11 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) + ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); + + if (cci & UCSI_CCI_ACK_COMPLETE && +- test_bit(ACK_PENDING, &ucsi->flags)) ++ test_and_clear_bit(ACK_PENDING, &ucsi->flags)) + complete(&ucsi->complete); + + if (cci & UCSI_CCI_COMMAND_COMPLETE && +- test_bit(COMMAND_PENDING, &ucsi->flags)) ++ test_and_clear_bit(COMMAND_PENDING, &ucsi->flags)) + complete(&ucsi->complete); + } + EXPORT_SYMBOL_GPL(ucsi_notify_common); +@@ -65,6 +65,8 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command) + else + set_bit(COMMAND_PENDING, &ucsi->flags); + ++ reinit_completion(&ucsi->complete); ++ + ret = ucsi->ops->async_control(ucsi, command); + if (ret) + goto out_clear_bit; +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index 98374ed7c57723..0112742e4504b9 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -2716,6 +2716,7 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma); + * @_vq: the struct virtqueue we're talking about. + * @num: new ring num + * @recycle: callback to recycle unused buffers ++ * @recycle_done: callback to be invoked when recycle for all unused buffers done + * + * When it is really necessary to create a new vring, it will set the current vq + * into the reset state. Then call the passed callback to recycle the buffer +@@ -2736,7 +2737,8 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma); + * + */ + int virtqueue_resize(struct virtqueue *_vq, u32 num, +- void (*recycle)(struct virtqueue *vq, void *buf)) ++ void (*recycle)(struct virtqueue *vq, void *buf), ++ void (*recycle_done)(struct virtqueue *vq)) + { + struct vring_virtqueue *vq = to_vvq(_vq); + int err; +@@ -2753,6 +2755,8 @@ int virtqueue_resize(struct virtqueue *_vq, u32 num, + err = virtqueue_disable_and_recycle(_vq, recycle); + if (err) + return err; ++ if (recycle_done) ++ recycle_done(_vq); + + if (vq->packed_ring) + err = virtqueue_resize_packed(_vq, num); +diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c +index b35fe1075503e1..fafc07e38663ca 100644 +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -1925,6 +1925,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) + goto unlink_out; + } + ++ netfs_wait_for_outstanding_io(inode); + cifs_close_deferred_file_under_dentry(tcon, full_path); + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY + if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & +@@ -2442,8 +2443,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + } + + cifs_close_deferred_file_under_dentry(tcon, from_name); +- if (d_inode(target_dentry) != NULL) ++ if (d_inode(target_dentry) != NULL) { ++ netfs_wait_for_outstanding_io(d_inode(target_dentry)); + cifs_close_deferred_file_under_dentry(tcon, to_name); ++ } + + rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, + to_name); +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index 611716bc8f27c1..8892177e500f19 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -1016,6 +1016,8 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id, + + ses_enc_key = enc ? sess->smb3encryptionkey : + sess->smb3decryptionkey; ++ if (enc) ++ ksmbd_user_session_get(sess); + memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); + + return 0; +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index ad02fe555fda7e..d960ddcbba1657 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -263,8 +263,10 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, + + down_read(&conn->session_lock); + sess = xa_load(&conn->sessions, id); +- if (sess) ++ if (sess) { + sess->last_active = jiffies; ++ ksmbd_user_session_get(sess); ++ } + up_read(&conn->session_lock); + return sess; + } +@@ -275,6 +277,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) + + down_read(&sessions_table_lock); + sess = __session_lookup(id); ++ if (sess) ++ ksmbd_user_session_get(sess); + up_read(&sessions_table_lock); + + return sess; +diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c +index c8cc6fa6fc3ebb..698af37e988d7b 100644 +--- a/fs/smb/server/server.c ++++ b/fs/smb/server/server.c +@@ -241,14 +241,14 @@ static void __handle_ksmbd_work(struct ksmbd_work *work, + if (work->tcon) + ksmbd_tree_connect_put(work->tcon); + smb3_preauth_hash_rsp(work); +- if (work->sess) +- ksmbd_user_session_put(work->sess); + if (work->sess && work->sess->enc && work->encrypted && + conn->ops->encrypt_resp) { + rc = conn->ops->encrypt_resp(work); + if (rc < 0) + conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); + } ++ if (work->sess) ++ ksmbd_user_session_put(work->sess); + + ksmbd_conn_write(work); + } +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index d0836d710f1814..7d01dd313351f7 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -67,8 +67,10 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id) + return false; + + sess = ksmbd_session_lookup_all(conn, id); +- if (sess) ++ if (sess) { ++ ksmbd_user_session_put(sess); + return true; ++ } + pr_err("Invalid user session id: %llu\n", id); + return false; + } +@@ -605,10 +607,8 @@ int smb2_check_user_session(struct ksmbd_work *work) + + /* Check for validity of user session */ + work->sess = ksmbd_session_lookup_all(conn, sess_id); +- if (work->sess) { +- ksmbd_user_session_get(work->sess); ++ if (work->sess) + return 1; +- } + ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); + return -ENOENT; + } +@@ -1701,29 +1701,35 @@ int smb2_sess_setup(struct ksmbd_work *work) + + if (conn->dialect != sess->dialect) { + rc = -EINVAL; ++ ksmbd_user_session_put(sess); + goto out_err; + } + + if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) { + rc = -EINVAL; ++ ksmbd_user_session_put(sess); + goto out_err; + } + + if (strncmp(conn->ClientGUID, sess->ClientGUID, + SMB2_CLIENT_GUID_SIZE)) { + rc = -ENOENT; ++ ksmbd_user_session_put(sess); + goto out_err; + } + + if (sess->state == SMB2_SESSION_IN_PROGRESS) { + rc = -EACCES; ++ ksmbd_user_session_put(sess); + goto out_err; + } + + if (sess->state == SMB2_SESSION_EXPIRED) { + rc = -EFAULT; ++ ksmbd_user_session_put(sess); + goto out_err; + } ++ ksmbd_user_session_put(sess); + + if (ksmbd_conn_need_reconnect(conn)) { + rc = -EFAULT; +@@ -1731,7 +1737,8 @@ int smb2_sess_setup(struct ksmbd_work *work) + goto out_err; + } + +- if (ksmbd_session_lookup(conn, sess_id)) { ++ sess = ksmbd_session_lookup(conn, sess_id); ++ if (!sess) { + rc = -EACCES; + goto out_err; + } +@@ -1742,7 +1749,6 @@ int smb2_sess_setup(struct ksmbd_work *work) + } + + conn->binding = true; +- ksmbd_user_session_get(sess); + } else if ((conn->dialect < SMB30_PROT_ID || + server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && + (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { +@@ -1769,7 +1775,6 @@ int smb2_sess_setup(struct ksmbd_work *work) + } + + conn->binding = false; +- ksmbd_user_session_get(sess); + } + work->sess = sess; + +@@ -2195,9 +2200,9 @@ int smb2_tree_disconnect(struct ksmbd_work *work) + int smb2_session_logoff(struct ksmbd_work *work) + { + struct ksmbd_conn *conn = work->conn; ++ struct ksmbd_session *sess = work->sess; + struct smb2_logoff_req *req; + struct smb2_logoff_rsp *rsp; +- struct ksmbd_session *sess; + u64 sess_id; + int err; + +@@ -2219,11 +2224,6 @@ int smb2_session_logoff(struct ksmbd_work *work) + ksmbd_close_session_fds(work); + ksmbd_conn_wait_idle(conn); + +- /* +- * Re-lookup session to validate if session is deleted +- * while waiting request complete +- */ +- sess = ksmbd_session_lookup_all(conn, sess_id); + if (ksmbd_tree_conn_session_logoff(sess)) { + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; +@@ -8962,6 +8962,7 @@ int smb3_decrypt_req(struct ksmbd_work *work) + le64_to_cpu(tr_hdr->SessionId)); + return -ECONNABORTED; + } ++ ksmbd_user_session_put(sess); + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; +diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c +index a5c4af148853f8..134d87b3489aa4 100644 +--- a/fs/xfs/libxfs/xfs_btree.c ++++ b/fs/xfs/libxfs/xfs_btree.c +@@ -3569,14 +3569,31 @@ xfs_btree_insrec( + xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); + + /* +- * If we just inserted into a new tree block, we have to +- * recalculate nkey here because nkey is out of date. ++ * Update btree keys to reflect the newly added record or keyptr. ++ * There are three cases here to be aware of. Normally, all we have to ++ * do is walk towards the root, updating keys as necessary. + * +- * Otherwise we're just updating an existing block (having shoved +- * some records into the new tree block), so use the regular key +- * update mechanism. ++ * If the caller had us target a full block for the insertion, we dealt ++ * with that by calling the _make_block_unfull function. If the ++ * "make unfull" function splits the block, it'll hand us back the key ++ * and pointer of the new block. We haven't yet added the new block to ++ * the next level up, so if we decide to add the new record to the new ++ * block (bp->b_bn != old_bn), we have to update the caller's pointer ++ * so that the caller adds the new block with the correct key. ++ * ++ * However, there is a third possibility-- if the selected block is the ++ * root block of an inode-rooted btree and cannot be expanded further, ++ * the "make unfull" function moves the root block contents to a new ++ * block and updates the root block to point to the new block. In this ++ * case, no block pointer is passed back because the block has already ++ * been added to the btree. In this case, we need to use the regular ++ * key update function, just like the first case. This is critical for ++ * overlapping btrees, because the high key must be updated to reflect ++ * the entire tree, not just the subtree accessible through the first ++ * child of the root (which is now two levels down from the root). + */ +- if (bp && xfs_buf_daddr(bp) != old_bn) { ++ if (!xfs_btree_ptr_is_null(cur, &nptr) && ++ bp && xfs_buf_daddr(bp) != old_bn) { + xfs_btree_get_keys(cur, block, lkey); + } else if (xfs_btree_needs_key_update(cur, optr)) { + error = xfs_btree_update_keys(cur, level); +@@ -5156,7 +5173,7 @@ xfs_btree_count_blocks_helper( + int level, + void *data) + { +- xfs_extlen_t *blocks = data; ++ xfs_filblks_t *blocks = data; + (*blocks)++; + + return 0; +@@ -5166,7 +5183,7 @@ xfs_btree_count_blocks_helper( + int + xfs_btree_count_blocks( + struct xfs_btree_cur *cur, +- xfs_extlen_t *blocks) ++ xfs_filblks_t *blocks) + { + *blocks = 0; + return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper, +diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h +index 10b7ddc3b2b34e..91e0b6dac31ec6 100644 +--- a/fs/xfs/libxfs/xfs_btree.h ++++ b/fs/xfs/libxfs/xfs_btree.h +@@ -485,7 +485,7 @@ typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level, + int xfs_btree_visit_blocks(struct xfs_btree_cur *cur, + xfs_btree_visit_blocks_fn fn, unsigned int flags, void *data); + +-int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks); ++int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_filblks_t *blocks); + + union xfs_btree_rec *xfs_btree_rec_addr(struct xfs_btree_cur *cur, int n, + struct xfs_btree_block *block); +diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c +index 401b42d52af686..6aa43f3fc68e03 100644 +--- a/fs/xfs/libxfs/xfs_ialloc_btree.c ++++ b/fs/xfs/libxfs/xfs_ialloc_btree.c +@@ -743,6 +743,7 @@ xfs_finobt_count_blocks( + { + struct xfs_buf *agbp = NULL; + struct xfs_btree_cur *cur; ++ xfs_filblks_t blocks; + int error; + + error = xfs_ialloc_read_agi(pag, tp, 0, &agbp); +@@ -750,9 +751,10 @@ xfs_finobt_count_blocks( + return error; + + cur = xfs_finobt_init_cursor(pag, tp, agbp); +- error = xfs_btree_count_blocks(cur, tree_blocks); ++ error = xfs_btree_count_blocks(cur, &blocks); + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, agbp); ++ *tree_blocks = blocks; + + return error; + } +diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c +index f228127a88ff26..fb47a76ead18c2 100644 +--- a/fs/xfs/libxfs/xfs_symlink_remote.c ++++ b/fs/xfs/libxfs/xfs_symlink_remote.c +@@ -92,8 +92,10 @@ xfs_symlink_verify( + struct xfs_mount *mp = bp->b_mount; + struct xfs_dsymlink_hdr *dsl = bp->b_addr; + ++ /* no verification of non-crc buffers */ + if (!xfs_has_crc(mp)) +- return __this_address; ++ return NULL; ++ + if (!xfs_verify_magic(bp, dsl->sl_magic)) + return __this_address; + if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid)) +diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c +index f8e5b67128d25a..da30f926cbe66d 100644 +--- a/fs/xfs/scrub/agheader.c ++++ b/fs/xfs/scrub/agheader.c +@@ -434,7 +434,7 @@ xchk_agf_xref_btreeblks( + { + struct xfs_agf *agf = sc->sa.agf_bp->b_addr; + struct xfs_mount *mp = sc->mp; +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + xfs_agblock_t btreeblks; + int error; + +@@ -483,7 +483,7 @@ xchk_agf_xref_refcblks( + struct xfs_scrub *sc) + { + struct xfs_agf *agf = sc->sa.agf_bp->b_addr; +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + int error; + + if (!sc->sa.refc_cur) +@@ -816,7 +816,7 @@ xchk_agi_xref_fiblocks( + struct xfs_scrub *sc) + { + struct xfs_agi *agi = sc->sa.agi_bp->b_addr; +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + int error = 0; + + if (!xfs_has_inobtcounts(sc->mp)) +diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c +index 2f98d90d7fd66d..69b003259784fe 100644 +--- a/fs/xfs/scrub/agheader_repair.c ++++ b/fs/xfs/scrub/agheader_repair.c +@@ -256,7 +256,7 @@ xrep_agf_calc_from_btrees( + struct xfs_agf *agf = agf_bp->b_addr; + struct xfs_mount *mp = sc->mp; + xfs_agblock_t btreeblks; +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + int error; + + /* Update the AGF counters from the bnobt. */ +@@ -946,7 +946,7 @@ xrep_agi_calc_from_btrees( + if (error) + goto err; + if (xfs_has_inobtcounts(mp)) { +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + + error = xfs_btree_count_blocks(cur, &blocks); + if (error) +@@ -959,7 +959,7 @@ xrep_agi_calc_from_btrees( + agi->agi_freecount = cpu_to_be32(freecount); + + if (xfs_has_finobt(mp) && xfs_has_inobtcounts(mp)) { +- xfs_agblock_t blocks; ++ xfs_filblks_t blocks; + + cur = xfs_finobt_init_cursor(sc->sa.pag, sc->tp, agi_bp); + error = xfs_btree_count_blocks(cur, &blocks); +diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c +index 1d3e98346933e1..454f17595c9c9e 100644 +--- a/fs/xfs/scrub/fscounters.c ++++ b/fs/xfs/scrub/fscounters.c +@@ -261,7 +261,7 @@ xchk_fscount_btreeblks( + struct xchk_fscounters *fsc, + xfs_agnumber_t agno) + { +- xfs_extlen_t blocks; ++ xfs_filblks_t blocks; + int error; + + error = xchk_ag_init_existing(sc, agno, &sc->sa); +diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c +index 750d7b0cd25a78..a59c44e5903a45 100644 +--- a/fs/xfs/scrub/ialloc.c ++++ b/fs/xfs/scrub/ialloc.c +@@ -652,8 +652,8 @@ xchk_iallocbt_xref_rmap_btreeblks( + struct xfs_scrub *sc) + { + xfs_filblks_t blocks; +- xfs_extlen_t inobt_blocks = 0; +- xfs_extlen_t finobt_blocks = 0; ++ xfs_filblks_t inobt_blocks = 0; ++ xfs_filblks_t finobt_blocks = 0; + int error; + + if (!sc->sa.ino_cur || !sc->sa.rmap_cur || +diff --git a/fs/xfs/scrub/refcount.c b/fs/xfs/scrub/refcount.c +index d0c7d4a29c0feb..cccf39d917a09c 100644 +--- a/fs/xfs/scrub/refcount.c ++++ b/fs/xfs/scrub/refcount.c +@@ -490,7 +490,7 @@ xchk_refcount_xref_rmap( + struct xfs_scrub *sc, + xfs_filblks_t cow_blocks) + { +- xfs_extlen_t refcbt_blocks = 0; ++ xfs_filblks_t refcbt_blocks = 0; + xfs_filblks_t blocks; + int error; + +diff --git a/fs/xfs/scrub/symlink_repair.c b/fs/xfs/scrub/symlink_repair.c +index d015a86ef460fb..953ce7be78dc2f 100644 +--- a/fs/xfs/scrub/symlink_repair.c ++++ b/fs/xfs/scrub/symlink_repair.c +@@ -36,6 +36,7 @@ + #include "scrub/tempfile.h" + #include "scrub/tempexch.h" + #include "scrub/reap.h" ++#include "scrub/health.h" + + /* + * Symbolic Link Repair +@@ -233,7 +234,7 @@ xrep_symlink_salvage( + * target zapped flag. + */ + if (buflen == 0) { +- sc->sick_mask |= XFS_SICK_INO_SYMLINK_ZAPPED; ++ xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_SYMLINK_ZAPPED); + sprintf(target_buf, DUMMY_TARGET); + } + +diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h +index c886d5d0eb021a..da773fee8638af 100644 +--- a/fs/xfs/scrub/trace.h ++++ b/fs/xfs/scrub/trace.h +@@ -601,7 +601,7 @@ TRACE_EVENT(xchk_ifork_btree_op_error, + TP_fast_assign( + xfs_fsblock_t fsbno = xchk_btree_cur_fsbno(cur, level); + __entry->dev = sc->mp->m_super->s_dev; +- __entry->ino = sc->ip->i_ino; ++ __entry->ino = cur->bc_ino.ip->i_ino; + __entry->whichfork = cur->bc_ino.whichfork; + __entry->type = sc->sm->sm_type; + __assign_str(name); +diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c +index edaf193dbd5ccc..95f8a09f96ae20 100644 +--- a/fs/xfs/xfs_bmap_util.c ++++ b/fs/xfs/xfs_bmap_util.c +@@ -111,7 +111,7 @@ xfs_bmap_count_blocks( + struct xfs_mount *mp = ip->i_mount; + struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); + struct xfs_btree_cur *cur; +- xfs_extlen_t btblocks = 0; ++ xfs_filblks_t btblocks = 0; + int error; + + *nextents = 0; +diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c +index b19916b11fd563..aba54e3c583661 100644 +--- a/fs/xfs/xfs_file.c ++++ b/fs/xfs/xfs_file.c +@@ -1228,6 +1228,14 @@ xfs_file_remap_range( + xfs_iunlock2_remapping(src, dest); + if (ret) + trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); ++ /* ++ * If the caller did not set CAN_SHORTEN, then it is not prepared to ++ * handle partial results -- either the whole remap succeeds, or we ++ * must say why it did not. In this case, any error should be returned ++ * to the caller. ++ */ ++ if (ret && remapped < len && !(remap_flags & REMAP_FILE_CAN_SHORTEN)) ++ return ret; + return remapped > 0 ? remapped : ret; + } + +diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c +index 3a2005a1e673dc..8caa55b8167467 100644 +--- a/fs/xfs/xfs_rtalloc.c ++++ b/fs/xfs/xfs_rtalloc.c +@@ -1295,7 +1295,7 @@ xfs_rtallocate( + * For an allocation to an empty file at offset 0, pick an extent that + * will space things out in the rt area. + */ +- if (bno_hint) ++ if (bno_hint != NULLFSBLOCK) + start = xfs_rtb_to_rtx(args.mp, bno_hint); + else if (initial_user_data) + start = xfs_rtpick_extent(args.mp, tp, maxlen); +diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c +index bdf3704dc30118..30e03342287a94 100644 +--- a/fs/xfs/xfs_trans.c ++++ b/fs/xfs/xfs_trans.c +@@ -834,13 +834,6 @@ __xfs_trans_commit( + + trace_xfs_trans_commit(tp, _RET_IP_); + +- error = xfs_trans_run_precommits(tp); +- if (error) { +- if (tp->t_flags & XFS_TRANS_PERM_LOG_RES) +- xfs_defer_cancel(tp); +- goto out_unreserve; +- } +- + /* + * Finish deferred items on final commit. Only permanent transactions + * should ever have deferred ops. +@@ -851,13 +844,12 @@ __xfs_trans_commit( + error = xfs_defer_finish_noroll(&tp); + if (error) + goto out_unreserve; +- +- /* Run precommits from final tx in defer chain. */ +- error = xfs_trans_run_precommits(tp); +- if (error) +- goto out_unreserve; + } + ++ error = xfs_trans_run_precommits(tp); ++ if (error) ++ goto out_unreserve; ++ + /* + * If there is nothing to be logged by the transaction, + * then unlock all of the items associated with the +@@ -1382,5 +1374,8 @@ xfs_trans_alloc_dir( + + out_cancel: + xfs_trans_cancel(tp); ++ xfs_iunlock(dp, XFS_ILOCK_EXCL); ++ if (dp != ip) ++ xfs_iunlock(ip, XFS_ILOCK_EXCL); + return error; + } +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 6b4bc85f4999ba..b7f327ce797e5b 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -200,8 +200,6 @@ struct gendisk { + spinlock_t zone_wplugs_lock; + struct mempool_s *zone_wplugs_pool; + struct hlist_head *zone_wplugs_hash; +- struct list_head zone_wplugs_err_list; +- struct work_struct zone_wplugs_work; + struct workqueue_struct *zone_wplugs_wq; + #endif /* CONFIG_BLK_DEV_ZONED */ + +@@ -1386,6 +1384,9 @@ static inline bool bdev_is_zone_start(struct block_device *bdev, + return bdev_offset_from_zone_start(bdev, sector) == 0; + } + ++int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector, ++ sector_t nr_sects, gfp_t gfp_mask); ++ + static inline int queue_dma_alignment(const struct request_queue *q) + { + return q->limits.dma_alignment; +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index cbe2350912460b..a7af13f550e0d4 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -2157,26 +2157,25 @@ bpf_prog_run_array(const struct bpf_prog_array *array, + * rcu-protected dynamically sized maps. + */ + static __always_inline u32 +-bpf_prog_run_array_uprobe(const struct bpf_prog_array __rcu *array_rcu, ++bpf_prog_run_array_uprobe(const struct bpf_prog_array *array, + const void *ctx, bpf_prog_run_fn run_prog) + { + const struct bpf_prog_array_item *item; + const struct bpf_prog *prog; +- const struct bpf_prog_array *array; + struct bpf_run_ctx *old_run_ctx; + struct bpf_trace_run_ctx run_ctx; + u32 ret = 1; + + might_fault(); ++ RCU_LOCKDEP_WARN(!rcu_read_lock_trace_held(), "no rcu lock held"); ++ ++ if (unlikely(!array)) ++ return ret; + +- rcu_read_lock_trace(); + migrate_disable(); + + run_ctx.is_uprobe = true; + +- array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held()); +- if (unlikely(!array)) +- goto out; + old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx); + item = &array->items[0]; + while ((prog = READ_ONCE(item->prog))) { +@@ -2191,9 +2190,7 @@ bpf_prog_run_array_uprobe(const struct bpf_prog_array __rcu *array_rcu, + rcu_read_unlock(); + } + bpf_reset_run_ctx(old_run_ctx); +-out: + migrate_enable(); +- rcu_read_unlock_trace(); + return ret; + } + +@@ -3471,10 +3468,4 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog) + return prog->aux->func_idx != 0; + } + +-static inline bool bpf_prog_is_raw_tp(const struct bpf_prog *prog) +-{ +- return prog->type == BPF_PROG_TYPE_TRACING && +- prog->expected_attach_type == BPF_TRACE_RAW_TP; +-} +- + #endif /* _LINUX_BPF_H */ +diff --git a/include/linux/compiler.h b/include/linux/compiler.h +index 4d4e23b6e3e761..2d962dade9faee 100644 +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -216,28 +216,43 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, + + #endif /* __KERNEL__ */ + ++/** ++ * offset_to_ptr - convert a relative memory offset to an absolute pointer ++ * @off: the address of the 32-bit offset value ++ */ ++static inline void *offset_to_ptr(const int *off) ++{ ++ return (void *)((unsigned long)off + *off); ++} ++ ++#endif /* __ASSEMBLY__ */ ++ ++#ifdef CONFIG_64BIT ++#define ARCH_SEL(a,b) a ++#else ++#define ARCH_SEL(a,b) b ++#endif ++ + /* + * Force the compiler to emit 'sym' as a symbol, so that we can reference + * it from inline assembler. Necessary in case 'sym' could be inlined + * otherwise, or eliminated entirely due to lack of references that are + * visible to the compiler. + */ +-#define ___ADDRESSABLE(sym, __attrs) \ +- static void * __used __attrs \ ++#define ___ADDRESSABLE(sym, __attrs) \ ++ static void * __used __attrs \ + __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)(uintptr_t)&sym; ++ + #define __ADDRESSABLE(sym) \ + ___ADDRESSABLE(sym, __section(".discard.addressable")) + +-/** +- * offset_to_ptr - convert a relative memory offset to an absolute pointer +- * @off: the address of the 32-bit offset value +- */ +-static inline void *offset_to_ptr(const int *off) +-{ +- return (void *)((unsigned long)off + *off); +-} ++#define __ADDRESSABLE_ASM(sym) \ ++ .pushsection .discard.addressable,"aw"; \ ++ .align ARCH_SEL(8,4); \ ++ ARCH_SEL(.quad, .long) __stringify(sym); \ ++ .popsection; + +-#endif /* __ASSEMBLY__ */ ++#define __ADDRESSABLE_ASM_STR(sym) __stringify(__ADDRESSABLE_ASM(sym)) + + /* &a[0] degrades to a pointer: a different type from an array */ + #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) +diff --git a/include/linux/dsa/ocelot.h b/include/linux/dsa/ocelot.h +index 6fbfbde68a37c3..620a3260fc0802 100644 +--- a/include/linux/dsa/ocelot.h ++++ b/include/linux/dsa/ocelot.h +@@ -15,6 +15,7 @@ + struct ocelot_skb_cb { + struct sk_buff *clone; + unsigned int ptp_class; /* valid only for clones */ ++ unsigned long ptp_tx_time; /* valid only for clones */ + u32 tstamp_lo; + u8 ptp_cmd; + u8 ts_id; +diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h +index 66e7d26b70a4fe..11be70a7929f28 100644 +--- a/include/linux/netdev_features.h ++++ b/include/linux/netdev_features.h +@@ -253,4 +253,11 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start) + NETIF_F_GSO_UDP_TUNNEL | \ + NETIF_F_GSO_UDP_TUNNEL_CSUM) + ++static inline netdev_features_t netdev_base_features(netdev_features_t features) ++{ ++ features &= ~NETIF_F_ONE_FOR_ALL; ++ features |= NETIF_F_ALL_FOR_ALL; ++ return features; ++} ++ + #endif /* _LINUX_NETDEV_FEATURES_H */ +diff --git a/include/linux/static_call.h b/include/linux/static_call.h +index 141e6b176a1b30..78a77a4ae0ea87 100644 +--- a/include/linux/static_call.h ++++ b/include/linux/static_call.h +@@ -160,6 +160,8 @@ extern void arch_static_call_transform(void *site, void *tramp, void *func, bool + + #ifdef CONFIG_HAVE_STATIC_CALL_INLINE + ++extern int static_call_initialized; ++ + extern int __init static_call_init(void); + + extern void static_call_force_reinit(void); +@@ -225,6 +227,8 @@ extern long __static_call_return0(void); + + #elif defined(CONFIG_HAVE_STATIC_CALL) + ++#define static_call_initialized 0 ++ + static inline int static_call_init(void) { return 0; } + + #define DEFINE_STATIC_CALL(name, _func) \ +@@ -281,6 +285,8 @@ extern long __static_call_return0(void); + + #else /* Generic implementation */ + ++#define static_call_initialized 0 ++ + static inline int static_call_init(void) { return 0; } + + static inline long __static_call_return0(void) +diff --git a/include/linux/virtio.h b/include/linux/virtio.h +index 306137a15d0753..73c8922e69e095 100644 +--- a/include/linux/virtio.h ++++ b/include/linux/virtio.h +@@ -100,7 +100,8 @@ dma_addr_t virtqueue_get_avail_addr(const struct virtqueue *vq); + dma_addr_t virtqueue_get_used_addr(const struct virtqueue *vq); + + int virtqueue_resize(struct virtqueue *vq, u32 num, +- void (*recycle)(struct virtqueue *vq, void *buf)); ++ void (*recycle)(struct virtqueue *vq, void *buf), ++ void (*recycle_done)(struct virtqueue *vq)); + int virtqueue_reset(struct virtqueue *vq, + void (*recycle)(struct virtqueue *vq, void *buf)); + +diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h +index f66bc85c6411dd..435250c72d5684 100644 +--- a/include/net/bluetooth/bluetooth.h ++++ b/include/net/bluetooth/bluetooth.h +@@ -123,6 +123,7 @@ struct bt_voice { + + #define BT_VOICE_TRANSPARENT 0x0003 + #define BT_VOICE_CVSD_16BIT 0x0060 ++#define BT_VOICE_TRANSPARENT_16BIT 0x0063 + + #define BT_SNDMTU 12 + #define BT_RCVMTU 13 +@@ -590,15 +591,6 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk, + return skb; + } + +-static inline int bt_copy_from_sockptr(void *dst, size_t dst_size, +- sockptr_t src, size_t src_size) +-{ +- if (dst_size > src_size) +- return -EINVAL; +- +- return copy_from_sockptr(dst, src, dst_size); +-} +- + int bt_to_errno(u16 code); + __u8 bt_status(int err); + +diff --git a/include/net/lapb.h b/include/net/lapb.h +index 124ee122f2c8f8..6c07420644e45a 100644 +--- a/include/net/lapb.h ++++ b/include/net/lapb.h +@@ -4,7 +4,7 @@ + #include + #include + +-#define LAPB_HEADER_LEN 20 /* LAPB over Ethernet + a bit more */ ++#define LAPB_HEADER_LEN MAX_HEADER /* LAPB over Ethernet + a bit more */ + + #define LAPB_ACK_PENDING_CONDITION 0x01 + #define LAPB_REJECT_CONDITION 0x02 +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 333e0fae6796c8..5b712582f9a9ce 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6770,14 +6770,12 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success, + /** + * ieee80211_channel_switch_disconnect - disconnect due to channel switch error + * @vif: &struct ieee80211_vif pointer from the add_interface callback. +- * @block_tx: if %true, do not send deauth frame. + * + * Instruct mac80211 to disconnect due to a channel switch error. The channel + * switch can request to block the tx and so, we need to make sure we do not send + * a deauth frame in this case. + */ +-void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, +- bool block_tx); ++void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif); + + /** + * ieee80211_request_smps - request SM PS transition +diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h +index e67b483cc8bbb8..9398c8f4995368 100644 +--- a/include/net/net_namespace.h ++++ b/include/net/net_namespace.h +@@ -80,6 +80,7 @@ struct net { + * or to unregister pernet ops + * (pernet_ops_rwsem write locked). + */ ++ struct llist_node defer_free_list; + struct llist_node cleanup_list; /* namespaces on death row */ + + #ifdef CONFIG_KEYS +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 066a3ea33b12e9..91ae20cb76485b 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -1103,7 +1103,6 @@ struct nft_rule_blob { + * @name: name of the chain + * @udlen: user data length + * @udata: user data in the chain +- * @rcu_head: rcu head for deferred release + * @blob_next: rule blob pointer to the next in the chain + */ + struct nft_chain { +@@ -1121,7 +1120,6 @@ struct nft_chain { + char *name; + u16 udlen; + u8 *udata; +- struct rcu_head rcu_head; + + /* Only used during control plane commit phase: */ + struct nft_rule_blob *blob_next; +@@ -1265,7 +1263,6 @@ static inline void nft_use_inc_restore(u32 *use) + * @sets: sets in the table + * @objects: stateful objects in the table + * @flowtables: flow tables in the table +- * @net: netnamespace this table belongs to + * @hgenerator: handle generator state + * @handle: table handle + * @use: number of chain references to this table +@@ -1285,7 +1282,6 @@ struct nft_table { + struct list_head sets; + struct list_head objects; + struct list_head flowtables; +- possible_net_t net; + u64 hgenerator; + u64 handle; + u32 use; +diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h +index 462c653e101746..2db9ae0575b609 100644 +--- a/include/soc/mscc/ocelot.h ++++ b/include/soc/mscc/ocelot.h +@@ -778,7 +778,6 @@ struct ocelot_port { + + phy_interface_t phy_mode; + +- unsigned int ptp_skbs_in_flight; + struct sk_buff_head tx_skbs; + + unsigned int trap_proto; +@@ -786,7 +785,6 @@ struct ocelot_port { + u16 mrp_ring_id; + + u8 ptp_cmd; +- u8 ts_id; + + u8 index; + +diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c +index 346826e3c933da..41d20b7199c4af 100644 +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -6415,6 +6415,101 @@ int btf_ctx_arg_offset(const struct btf *btf, const struct btf_type *func_proto, + return off; + } + ++struct bpf_raw_tp_null_args { ++ const char *func; ++ u64 mask; ++}; ++ ++static const struct bpf_raw_tp_null_args raw_tp_null_args[] = { ++ /* sched */ ++ { "sched_pi_setprio", 0x10 }, ++ /* ... from sched_numa_pair_template event class */ ++ { "sched_stick_numa", 0x100 }, ++ { "sched_swap_numa", 0x100 }, ++ /* afs */ ++ { "afs_make_fs_call", 0x10 }, ++ { "afs_make_fs_calli", 0x10 }, ++ { "afs_make_fs_call1", 0x10 }, ++ { "afs_make_fs_call2", 0x10 }, ++ { "afs_protocol_error", 0x1 }, ++ { "afs_flock_ev", 0x10 }, ++ /* cachefiles */ ++ { "cachefiles_lookup", 0x1 | 0x200 }, ++ { "cachefiles_unlink", 0x1 }, ++ { "cachefiles_rename", 0x1 }, ++ { "cachefiles_prep_read", 0x1 }, ++ { "cachefiles_mark_active", 0x1 }, ++ { "cachefiles_mark_failed", 0x1 }, ++ { "cachefiles_mark_inactive", 0x1 }, ++ { "cachefiles_vfs_error", 0x1 }, ++ { "cachefiles_io_error", 0x1 }, ++ { "cachefiles_ondemand_open", 0x1 }, ++ { "cachefiles_ondemand_copen", 0x1 }, ++ { "cachefiles_ondemand_close", 0x1 }, ++ { "cachefiles_ondemand_read", 0x1 }, ++ { "cachefiles_ondemand_cread", 0x1 }, ++ { "cachefiles_ondemand_fd_write", 0x1 }, ++ { "cachefiles_ondemand_fd_release", 0x1 }, ++ /* ext4, from ext4__mballoc event class */ ++ { "ext4_mballoc_discard", 0x10 }, ++ { "ext4_mballoc_free", 0x10 }, ++ /* fib */ ++ { "fib_table_lookup", 0x100 }, ++ /* filelock */ ++ /* ... from filelock_lock event class */ ++ { "posix_lock_inode", 0x10 }, ++ { "fcntl_setlk", 0x10 }, ++ { "locks_remove_posix", 0x10 }, ++ { "flock_lock_inode", 0x10 }, ++ /* ... from filelock_lease event class */ ++ { "break_lease_noblock", 0x10 }, ++ { "break_lease_block", 0x10 }, ++ { "break_lease_unblock", 0x10 }, ++ { "generic_delete_lease", 0x10 }, ++ { "time_out_leases", 0x10 }, ++ /* host1x */ ++ { "host1x_cdma_push_gather", 0x10000 }, ++ /* huge_memory */ ++ { "mm_khugepaged_scan_pmd", 0x10 }, ++ { "mm_collapse_huge_page_isolate", 0x1 }, ++ { "mm_khugepaged_scan_file", 0x10 }, ++ { "mm_khugepaged_collapse_file", 0x10 }, ++ /* kmem */ ++ { "mm_page_alloc", 0x1 }, ++ { "mm_page_pcpu_drain", 0x1 }, ++ /* .. from mm_page event class */ ++ { "mm_page_alloc_zone_locked", 0x1 }, ++ /* netfs */ ++ { "netfs_failure", 0x10 }, ++ /* power */ ++ { "device_pm_callback_start", 0x10 }, ++ /* qdisc */ ++ { "qdisc_dequeue", 0x1000 }, ++ /* rxrpc */ ++ { "rxrpc_recvdata", 0x1 }, ++ { "rxrpc_resend", 0x10 }, ++ /* sunrpc */ ++ { "xs_stream_read_data", 0x1 }, ++ /* ... from xprt_cong_event event class */ ++ { "xprt_reserve_cong", 0x10 }, ++ { "xprt_release_cong", 0x10 }, ++ { "xprt_get_cong", 0x10 }, ++ { "xprt_put_cong", 0x10 }, ++ /* tcp */ ++ { "tcp_send_reset", 0x11 }, ++ /* tegra_apb_dma */ ++ { "tegra_dma_tx_status", 0x100 }, ++ /* timer_migration */ ++ { "tmigr_update_events", 0x1 }, ++ /* writeback, from writeback_folio_template event class */ ++ { "writeback_dirty_folio", 0x10 }, ++ { "folio_wait_writeback", 0x10 }, ++ /* rdma */ ++ { "mr_integ_alloc", 0x2000 }, ++ /* bpf_testmod */ ++ { "bpf_testmod_test_read", 0x0 }, ++}; ++ + bool btf_ctx_access(int off, int size, enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +@@ -6425,6 +6520,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, + const char *tname = prog->aux->attach_func_name; + struct bpf_verifier_log *log = info->log; + const struct btf_param *args; ++ bool ptr_err_raw_tp = false; + const char *tag_value; + u32 nr_args, arg; + int i, ret; +@@ -6519,6 +6615,12 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, + return false; + } + ++ if (size != sizeof(u64)) { ++ bpf_log(log, "func '%s' size %d must be 8\n", ++ tname, size); ++ return false; ++ } ++ + /* check for PTR_TO_RDONLY_BUF_OR_NULL or PTR_TO_RDWR_BUF_OR_NULL */ + for (i = 0; i < prog->aux->ctx_arg_info_size; i++) { + const struct bpf_ctx_arg_aux *ctx_arg_info = &prog->aux->ctx_arg_info[i]; +@@ -6564,12 +6666,42 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, + if (prog_args_trusted(prog)) + info->reg_type |= PTR_TRUSTED; + +- /* Raw tracepoint arguments always get marked as maybe NULL */ +- if (bpf_prog_is_raw_tp(prog)) +- info->reg_type |= PTR_MAYBE_NULL; +- else if (btf_param_match_suffix(btf, &args[arg], "__nullable")) ++ if (btf_param_match_suffix(btf, &args[arg], "__nullable")) + info->reg_type |= PTR_MAYBE_NULL; + ++ if (prog->expected_attach_type == BPF_TRACE_RAW_TP) { ++ struct btf *btf = prog->aux->attach_btf; ++ const struct btf_type *t; ++ const char *tname; ++ ++ /* BTF lookups cannot fail, return false on error */ ++ t = btf_type_by_id(btf, prog->aux->attach_btf_id); ++ if (!t) ++ return false; ++ tname = btf_name_by_offset(btf, t->name_off); ++ if (!tname) ++ return false; ++ /* Checked by bpf_check_attach_target */ ++ tname += sizeof("btf_trace_") - 1; ++ for (i = 0; i < ARRAY_SIZE(raw_tp_null_args); i++) { ++ /* Is this a func with potential NULL args? */ ++ if (strcmp(tname, raw_tp_null_args[i].func)) ++ continue; ++ if (raw_tp_null_args[i].mask & (0x1 << (arg * 4))) ++ info->reg_type |= PTR_MAYBE_NULL; ++ /* Is the current arg IS_ERR? */ ++ if (raw_tp_null_args[i].mask & (0x2 << (arg * 4))) ++ ptr_err_raw_tp = true; ++ break; ++ } ++ /* If we don't know NULL-ness specification and the tracepoint ++ * is coming from a loadable module, be conservative and mark ++ * argument as PTR_MAYBE_NULL. ++ */ ++ if (i == ARRAY_SIZE(raw_tp_null_args) && btf_is_module(btf)) ++ info->reg_type |= PTR_MAYBE_NULL; ++ } ++ + if (tgt_prog) { + enum bpf_prog_type tgt_type; + +@@ -6614,6 +6746,15 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, + bpf_log(log, "func '%s' arg%d has btf_id %d type %s '%s'\n", + tname, arg, info->btf_id, btf_type_str(t), + __btf_name_by_offset(btf, t->name_off)); ++ ++ /* Perform all checks on the validity of type for this argument, but if ++ * we know it can be IS_ERR at runtime, scrub pointer type and mark as ++ * scalar. ++ */ ++ if (ptr_err_raw_tp) { ++ bpf_log(log, "marking pointer arg%d as scalar as it may encode error", arg); ++ info->reg_type = SCALAR_VALUE; ++ } + return true; + } + EXPORT_SYMBOL_GPL(btf_ctx_access); +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index b2008076df9c26..4c486a0bfcc4d8 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -418,25 +418,6 @@ static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) + return rec; + } + +-static bool mask_raw_tp_reg_cond(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) { +- return reg->type == (PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL) && +- bpf_prog_is_raw_tp(env->prog) && !reg->ref_obj_id; +-} +- +-static bool mask_raw_tp_reg(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) +-{ +- if (!mask_raw_tp_reg_cond(env, reg)) +- return false; +- reg->type &= ~PTR_MAYBE_NULL; +- return true; +-} +- +-static void unmask_raw_tp_reg(struct bpf_reg_state *reg, bool result) +-{ +- if (result) +- reg->type |= PTR_MAYBE_NULL; +-} +- + static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog) + { + struct bpf_func_info_aux *aux = env->prog->aux->func_info_aux; +@@ -6618,7 +6599,6 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + const char *field_name = NULL; + enum bpf_type_flag flag = 0; + u32 btf_id = 0; +- bool mask; + int ret; + + if (!env->allow_ptr_leaks) { +@@ -6690,21 +6670,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + + if (ret < 0) + return ret; +- /* For raw_tp progs, we allow dereference of PTR_MAYBE_NULL +- * trusted PTR_TO_BTF_ID, these are the ones that are possibly +- * arguments to the raw_tp. Since internal checks in for trusted +- * reg in check_ptr_to_btf_access would consider PTR_MAYBE_NULL +- * modifier as problematic, mask it out temporarily for the +- * check. Don't apply this to pointers with ref_obj_id > 0, as +- * those won't be raw_tp args. +- * +- * We may end up applying this relaxation to other trusted +- * PTR_TO_BTF_ID with maybe null flag, since we cannot +- * distinguish PTR_MAYBE_NULL tagged for arguments vs normal +- * tagging, but that should expand allowed behavior, and not +- * cause regression for existing behavior. +- */ +- mask = mask_raw_tp_reg(env, reg); ++ + if (ret != PTR_TO_BTF_ID) { + /* just mark; */ + +@@ -6765,13 +6731,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, + clear_trusted_flags(&flag); + } + +- if (atype == BPF_READ && value_regno >= 0) { ++ if (atype == BPF_READ && value_regno >= 0) + mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag); +- /* We've assigned a new type to regno, so don't undo masking. */ +- if (regno == value_regno) +- mask = false; +- } +- unmask_raw_tp_reg(reg, mask); + + return 0; + } +@@ -7146,7 +7107,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn + if (!err && t == BPF_READ && value_regno >= 0) + mark_reg_unknown(env, regs, value_regno); + } else if (base_type(reg->type) == PTR_TO_BTF_ID && +- (mask_raw_tp_reg_cond(env, reg) || !type_may_be_null(reg->type))) { ++ !type_may_be_null(reg->type)) { + err = check_ptr_to_btf_access(env, regs, regno, off, size, t, + value_regno); + } else if (reg->type == CONST_PTR_TO_MAP) { +@@ -8844,7 +8805,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, + enum bpf_reg_type type = reg->type; + u32 *arg_btf_id = NULL; + int err = 0; +- bool mask; + + if (arg_type == ARG_DONTCARE) + return 0; +@@ -8885,11 +8845,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, + base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK) + arg_btf_id = fn->arg_btf_id[arg]; + +- mask = mask_raw_tp_reg(env, reg); + err = check_reg_type(env, regno, arg_type, arg_btf_id, meta); ++ if (err) ++ return err; + +- err = err ?: check_func_arg_reg_off(env, reg, regno, arg_type); +- unmask_raw_tp_reg(reg, mask); ++ err = check_func_arg_reg_off(env, reg, regno, arg_type); + if (err) + return err; + +@@ -9684,17 +9644,14 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog, + return ret; + } else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) { + struct bpf_call_arg_meta meta; +- bool mask; + int err; + + if (register_is_null(reg) && type_may_be_null(arg->arg_type)) + continue; + + memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */ +- mask = mask_raw_tp_reg(env, reg); + err = check_reg_type(env, regno, arg->arg_type, &arg->btf_id, &meta); + err = err ?: check_func_arg_reg_off(env, reg, regno, arg->arg_type); +- unmask_raw_tp_reg(reg, mask); + if (err) + return err; + } else { +@@ -12009,7 +11966,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + enum bpf_arg_type arg_type = ARG_DONTCARE; + u32 regno = i + 1, ref_id, type_size; + bool is_ret_buf_sz = false; +- bool mask = false; + int kf_arg_type; + + t = btf_type_skip_modifiers(btf, args[i].type, NULL); +@@ -12068,15 +12024,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + return -EINVAL; + } + +- mask = mask_raw_tp_reg(env, reg); + if ((is_kfunc_trusted_args(meta) || is_kfunc_rcu(meta)) && + (register_is_null(reg) || type_may_be_null(reg->type)) && + !is_kfunc_arg_nullable(meta->btf, &args[i])) { + verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i); +- unmask_raw_tp_reg(reg, mask); + return -EACCES; + } +- unmask_raw_tp_reg(reg, mask); + + if (reg->ref_obj_id) { + if (is_kfunc_release(meta) && meta->ref_obj_id) { +@@ -12134,24 +12087,16 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta)) + break; + +- /* Allow passing maybe NULL raw_tp arguments to +- * kfuncs for compatibility. Don't apply this to +- * arguments with ref_obj_id > 0. +- */ +- mask = mask_raw_tp_reg(env, reg); + if (!is_trusted_reg(reg)) { + if (!is_kfunc_rcu(meta)) { + verbose(env, "R%d must be referenced or trusted\n", regno); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + if (!is_rcu_reg(reg)) { + verbose(env, "R%d must be a rcu pointer\n", regno); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + } +- unmask_raw_tp_reg(reg, mask); + fallthrough; + case KF_ARG_PTR_TO_CTX: + case KF_ARG_PTR_TO_DYNPTR: +@@ -12174,9 +12119,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + + if (is_kfunc_release(meta) && reg->ref_obj_id) + arg_type |= OBJ_RELEASE; +- mask = mask_raw_tp_reg(env, reg); + ret = check_func_arg_reg_off(env, reg, regno, arg_type); +- unmask_raw_tp_reg(reg, mask); + if (ret < 0) + return ret; + +@@ -12353,7 +12296,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + ref_tname = btf_name_by_offset(btf, ref_t->name_off); + fallthrough; + case KF_ARG_PTR_TO_BTF_ID: +- mask = mask_raw_tp_reg(env, reg); + /* Only base_type is checked, further checks are done here */ + if ((base_type(reg->type) != PTR_TO_BTF_ID || + (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) && +@@ -12362,11 +12304,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ + verbose(env, "expected %s or socket\n", + reg_type_str(env, base_type(reg->type) | + (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS))); +- unmask_raw_tp_reg(reg, mask); + return -EINVAL; + } + ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i); +- unmask_raw_tp_reg(reg, mask); + if (ret < 0) + return ret; + break; +@@ -13336,7 +13276,7 @@ static int sanitize_check_bounds(struct bpf_verifier_env *env, + */ + static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, + struct bpf_insn *insn, +- struct bpf_reg_state *ptr_reg, ++ const struct bpf_reg_state *ptr_reg, + const struct bpf_reg_state *off_reg) + { + struct bpf_verifier_state *vstate = env->cur_state; +@@ -13350,7 +13290,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, + struct bpf_sanitize_info info = {}; + u8 opcode = BPF_OP(insn->code); + u32 dst = insn->dst_reg; +- bool mask; + int ret; + + dst_reg = ®s[dst]; +@@ -13377,14 +13316,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, + return -EACCES; + } + +- mask = mask_raw_tp_reg(env, ptr_reg); + if (ptr_reg->type & PTR_MAYBE_NULL) { + verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", + dst, reg_type_str(env, ptr_reg->type)); +- unmask_raw_tp_reg(ptr_reg, mask); + return -EACCES; + } +- unmask_raw_tp_reg(ptr_reg, mask); + + switch (base_type(ptr_reg->type)) { + case PTR_TO_CTX: +@@ -19934,7 +19870,6 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) + * for this case. + */ + case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED: +- case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL: + if (type == BPF_READ) { + if (BPF_MODE(insn->code) == BPF_MEM) + insn->code = BPF_LDX | BPF_PROBE_MEM | +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 40a1ad4493b4d9..fc6f41ac33eb13 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -781,7 +781,7 @@ static inline void replenish_dl_new_period(struct sched_dl_entity *dl_se, + * If it is a deferred reservation, and the server + * is not handling an starvation case, defer it. + */ +- if (dl_se->dl_defer & !dl_se->dl_defer_running) { ++ if (dl_se->dl_defer && !dl_se->dl_defer_running) { + dl_se->dl_throttled = 1; + dl_se->dl_defer_armed = 1; + } +diff --git a/kernel/static_call_inline.c b/kernel/static_call_inline.c +index 5259cda486d058..bb7d066a7c3979 100644 +--- a/kernel/static_call_inline.c ++++ b/kernel/static_call_inline.c +@@ -15,7 +15,7 @@ extern struct static_call_site __start_static_call_sites[], + extern struct static_call_tramp_key __start_static_call_tramp_key[], + __stop_static_call_tramp_key[]; + +-static int static_call_initialized; ++int static_call_initialized; + + /* + * Must be called before early_initcall() to be effective. +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 792dc35414a3c3..50881898e758d8 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2215,6 +2215,9 @@ void perf_event_detach_bpf_prog(struct perf_event *event) + goto unlock; + + old_array = bpf_event_rcu_dereference(event->tp_event->prog_array); ++ if (!old_array) ++ goto put; ++ + ret = bpf_prog_array_copy(old_array, event->prog, NULL, 0, &new_array); + if (ret < 0) { + bpf_prog_array_delete_safe(old_array, event->prog); +@@ -2223,6 +2226,14 @@ void perf_event_detach_bpf_prog(struct perf_event *event) + bpf_prog_array_free_sleepable(old_array); + } + ++put: ++ /* ++ * It could be that the bpf_prog is not sleepable (and will be freed ++ * via normal RCU), but is called from a point that supports sleepable ++ * programs and uses tasks-trace-RCU. ++ */ ++ synchronize_rcu_tasks_trace(); ++ + bpf_prog_put(event->prog); + event->prog = NULL; + +diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c +index b30fc8fcd0956a..b085a8a164ea03 100644 +--- a/kernel/trace/trace_uprobe.c ++++ b/kernel/trace/trace_uprobe.c +@@ -1400,9 +1400,13 @@ static void __uprobe_perf_func(struct trace_uprobe *tu, + + #ifdef CONFIG_BPF_EVENTS + if (bpf_prog_array_valid(call)) { ++ const struct bpf_prog_array *array; + u32 ret; + +- ret = bpf_prog_run_array_uprobe(call->prog_array, regs, bpf_prog_run); ++ rcu_read_lock_trace(); ++ array = rcu_dereference_check(call->prog_array, rcu_read_lock_trace_held()); ++ ret = bpf_prog_run_array_uprobe(array, regs, bpf_prog_run); ++ rcu_read_unlock_trace(); + if (!ret) + return; + } +diff --git a/mm/slub.c b/mm/slub.c +index 15ba89fef89a1f..b9447a955f6112 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2199,9 +2199,24 @@ bool memcg_slab_post_charge(void *p, gfp_t flags) + + folio = virt_to_folio(p); + if (!folio_test_slab(folio)) { +- return folio_memcg_kmem(folio) || +- (__memcg_kmem_charge_page(folio_page(folio, 0), flags, +- folio_order(folio)) == 0); ++ int size; ++ ++ if (folio_memcg_kmem(folio)) ++ return true; ++ ++ if (__memcg_kmem_charge_page(folio_page(folio, 0), flags, ++ folio_order(folio))) ++ return false; ++ ++ /* ++ * This folio has already been accounted in the global stats but ++ * not in the memcg stats. So, subtract from the global and use ++ * the interface which adds to both global and memcg stats. ++ */ ++ size = folio_size(folio); ++ node_stat_mod_folio(folio, NR_SLAB_UNRECLAIMABLE_B, -size); ++ lruvec_stat_mod_folio(folio, NR_SLAB_UNRECLAIMABLE_B, size); ++ return true; + } + + slab = folio_slab(folio); +diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c +index 2243cec18ecc86..53dea8ae96e477 100644 +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -990,16 +990,25 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) + int tt_diff_len, tt_change_len = 0; + int tt_diff_entries_num = 0; + int tt_diff_entries_count = 0; ++ bool drop_changes = false; ++ size_t tt_extra_len = 0; + u16 tvlv_len; + + tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); + tt_diff_len = batadv_tt_len(tt_diff_entries_num); + + /* if we have too many changes for one packet don't send any +- * and wait for the tt table request which will be fragmented ++ * and wait for the tt table request so we can reply with the full ++ * (fragmented) table. ++ * ++ * The local change history should still be cleaned up so the next ++ * TT round can start again with a clean state. + */ +- if (tt_diff_len > bat_priv->soft_iface->mtu) ++ if (tt_diff_len > bat_priv->soft_iface->mtu) { + tt_diff_len = 0; ++ tt_diff_entries_num = 0; ++ drop_changes = true; ++ } + + tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, + &tt_change, &tt_diff_len); +@@ -1008,7 +1017,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) + + tt_data->flags = BATADV_TT_OGM_DIFF; + +- if (tt_diff_len == 0) ++ if (!drop_changes && tt_diff_len == 0) + goto container_register; + + spin_lock_bh(&bat_priv->tt.changes_list_lock); +@@ -1027,6 +1036,9 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) + } + spin_unlock_bh(&bat_priv->tt.changes_list_lock); + ++ tt_extra_len = batadv_tt_len(tt_diff_entries_num - ++ tt_diff_entries_count); ++ + /* Keep the buffer for possible tt_request */ + spin_lock_bh(&bat_priv->tt.last_changeset_lock); + kfree(bat_priv->tt.last_changeset); +@@ -1035,6 +1047,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) + tt_change_len = batadv_tt_len(tt_diff_entries_count); + /* check whether this new OGM has no changes due to size problems */ + if (tt_diff_entries_count > 0) { ++ tt_diff_len -= tt_extra_len; + /* if kmalloc() fails we will reply with the full table + * instead of providing the diff + */ +@@ -1047,6 +1060,8 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) + } + spin_unlock_bh(&bat_priv->tt.last_changeset_lock); + ++ /* Remove extra packet space for OGM */ ++ tvlv_len -= tt_extra_len; + container_register: + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, + tvlv_len); +@@ -2747,14 +2762,16 @@ static bool batadv_tt_global_valid(const void *entry_ptr, + * + * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb + * is not provided then this becomes a no-op. ++ * ++ * Return: Remaining unused length in tvlv_buff. + */ +-static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, +- struct batadv_hashtable *hash, +- void *tvlv_buff, u16 tt_len, +- bool (*valid_cb)(const void *, +- const void *, +- u8 *flags), +- void *cb_data) ++static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, ++ struct batadv_hashtable *hash, ++ void *tvlv_buff, u16 tt_len, ++ bool (*valid_cb)(const void *, ++ const void *, ++ u8 *flags), ++ void *cb_data) + { + struct batadv_tt_common_entry *tt_common_entry; + struct batadv_tvlv_tt_change *tt_change; +@@ -2768,7 +2785,7 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, + tt_change = tvlv_buff; + + if (!valid_cb) +- return; ++ return tt_len; + + rcu_read_lock(); + for (i = 0; i < hash->size; i++) { +@@ -2794,6 +2811,8 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, + } + } + rcu_read_unlock(); ++ ++ return batadv_tt_len(tt_tot - tt_num_entries); + } + + /** +@@ -3069,10 +3088,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, + goto out; + + /* fill the rest of the tvlv with the real TT entries */ +- batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, +- tt_change, tt_len, +- batadv_tt_global_valid, +- req_dst_orig_node); ++ tvlv_len -= batadv_tt_tvlv_generate(bat_priv, ++ bat_priv->tt.global_hash, ++ tt_change, tt_len, ++ batadv_tt_global_valid, ++ req_dst_orig_node); + } + + /* Don't send the response, if larger than fragmented packet. */ +@@ -3196,9 +3216,11 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, + goto out; + + /* fill the rest of the tvlv with the real TT entries */ +- batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, +- tt_change, tt_len, +- batadv_tt_local_valid, NULL); ++ tvlv_len -= batadv_tt_tvlv_generate(bat_priv, ++ bat_priv->tt.local_hash, ++ tt_change, tt_len, ++ batadv_tt_local_valid, ++ NULL); + } + + tvlv_tt_data->flags = BATADV_TT_RESPONSE; +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 2b5ba8acd1d84a..388d46c6a043d4 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -6872,38 +6872,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, + return; + + hci_dev_lock(hdev); +- rcu_read_lock(); + + /* Connect all BISes that are bound to the BIG */ +- list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { +- if (bacmp(&conn->dst, BDADDR_ANY) || +- conn->type != ISO_LINK || +- conn->iso_qos.bcast.big != ev->handle) ++ while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle, ++ BT_BOUND))) { ++ if (ev->status) { ++ hci_connect_cfm(conn, ev->status); ++ hci_conn_del(conn); + continue; ++ } + + if (hci_conn_set_handle(conn, + __le16_to_cpu(ev->bis_handle[i++]))) + continue; + +- if (!ev->status) { +- conn->state = BT_CONNECTED; +- set_bit(HCI_CONN_BIG_CREATED, &conn->flags); +- rcu_read_unlock(); +- hci_debugfs_create_conn(conn); +- hci_conn_add_sysfs(conn); +- hci_iso_setup_path(conn); +- rcu_read_lock(); +- continue; +- } +- +- hci_connect_cfm(conn, ev->status); +- rcu_read_unlock(); +- hci_conn_del(conn); +- rcu_read_lock(); ++ conn->state = BT_CONNECTED; ++ set_bit(HCI_CONN_BIG_CREATED, &conn->flags); ++ hci_debugfs_create_conn(conn); ++ hci_conn_add_sysfs(conn); ++ hci_iso_setup_path(conn); + } + +- rcu_read_unlock(); +- + if (!ev->status && !i) + /* If no BISes have been connected for the BIG, + * terminate. This is in case all bound connections +diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c +index 2272e1849ebd89..022b86797acdc5 100644 +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -1926,7 +1926,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, + } + + static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname, +- sockptr_t optval, unsigned int len) ++ sockptr_t optval, unsigned int optlen) + { + struct hci_ufilter uf = { .opcode = 0 }; + struct sock *sk = sock->sk; +@@ -1943,7 +1943,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname, + + switch (optname) { + case HCI_DATA_DIR: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1954,7 +1954,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname, + break; + + case HCI_TIME_STAMP: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1974,7 +1974,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname, + uf.event_mask[1] = *((u32 *) f->event_mask + 1); + } + +- err = bt_copy_from_sockptr(&uf, sizeof(uf), optval, len); ++ err = copy_safe_from_sockptr(&uf, sizeof(uf), optval, optlen); + if (err) + break; + +@@ -2005,7 +2005,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname, + } + + static int hci_sock_setsockopt(struct socket *sock, int level, int optname, +- sockptr_t optval, unsigned int len) ++ sockptr_t optval, unsigned int optlen) + { + struct sock *sk = sock->sk; + int err = 0; +@@ -2015,7 +2015,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, + + if (level == SOL_HCI) + return hci_sock_setsockopt_old(sock, level, optname, optval, +- len); ++ optlen); + + if (level != SOL_BLUETOOTH) + return -ENOPROTOOPT; +@@ -2035,7 +2035,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, + goto done; + } + +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c +index 5e2d9758bd3c1c..644b606743e212 100644 +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -1129,6 +1129,7 @@ static int iso_listen_bis(struct sock *sk) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); ++ lock_sock(sk); + + /* Fail if user set invalid QoS */ + if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) { +@@ -1158,10 +1159,10 @@ static int iso_listen_bis(struct sock *sk) + goto unlock; + } + +- hci_dev_put(hdev); +- + unlock: ++ release_sock(sk); + hci_dev_unlock(hdev); ++ hci_dev_put(hdev); + return err; + } + +@@ -1188,6 +1189,7 @@ static int iso_sock_listen(struct socket *sock, int backlog) + + BT_DBG("sk %p backlog %d", sk, backlog); + ++ sock_hold(sk); + lock_sock(sk); + + if (sk->sk_state != BT_BOUND) { +@@ -1200,10 +1202,16 @@ static int iso_sock_listen(struct socket *sock, int backlog) + goto done; + } + +- if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) ++ if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) { + err = iso_listen_cis(sk); +- else ++ } else { ++ /* Drop sock lock to avoid potential ++ * deadlock with the hdev lock. ++ */ ++ release_sock(sk); + err = iso_listen_bis(sk); ++ lock_sock(sk); ++ } + + if (err) + goto done; +@@ -1215,6 +1223,7 @@ static int iso_sock_listen(struct socket *sock, int backlog) + + done: + release_sock(sk); ++ sock_put(sk); + return err; + } + +@@ -1226,7 +1235,11 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock, + long timeo; + int err = 0; + +- lock_sock(sk); ++ /* Use explicit nested locking to avoid lockdep warnings generated ++ * because the parent socket and the child socket are locked on the ++ * same thread. ++ */ ++ lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + + timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK); + +@@ -1257,7 +1270,7 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock, + release_sock(sk); + + timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); +- lock_sock(sk); ++ lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + } + remove_wait_queue(sk_sleep(sk), &wait); + +@@ -1398,6 +1411,7 @@ static void iso_conn_big_sync(struct sock *sk) + * change. + */ + hci_dev_lock(hdev); ++ lock_sock(sk); + + if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) { + err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon, +@@ -1410,6 +1424,7 @@ static void iso_conn_big_sync(struct sock *sk) + err); + } + ++ release_sock(sk); + hci_dev_unlock(hdev); + } + +@@ -1418,39 +1433,57 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, + { + struct sock *sk = sock->sk; + struct iso_pinfo *pi = iso_pi(sk); ++ bool early_ret = false; ++ int err = 0; + + BT_DBG("sk %p", sk); + + if (test_and_clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { ++ sock_hold(sk); + lock_sock(sk); ++ + switch (sk->sk_state) { + case BT_CONNECT2: + if (test_bit(BT_SK_PA_SYNC, &pi->flags)) { ++ release_sock(sk); + iso_conn_big_sync(sk); ++ lock_sock(sk); ++ + sk->sk_state = BT_LISTEN; + } else { + iso_conn_defer_accept(pi->conn->hcon); + sk->sk_state = BT_CONFIG; + } +- release_sock(sk); +- return 0; ++ ++ early_ret = true; ++ break; + case BT_CONNECTED: + if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { ++ release_sock(sk); + iso_conn_big_sync(sk); ++ lock_sock(sk); ++ + sk->sk_state = BT_LISTEN; +- release_sock(sk); +- return 0; ++ early_ret = true; + } + +- release_sock(sk); + break; + case BT_CONNECT: + release_sock(sk); +- return iso_connect_cis(sk); ++ err = iso_connect_cis(sk); ++ lock_sock(sk); ++ ++ early_ret = true; ++ break; + default: +- release_sock(sk); + break; + } ++ ++ release_sock(sk); ++ sock_put(sk); ++ ++ if (early_ret) ++ return err; + } + + return bt_sock_recvmsg(sock, msg, len, flags); +@@ -1566,7 +1599,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1577,7 +1610,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, + break; + + case BT_PKT_STATUS: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1596,7 +1629,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&qos, sizeof(qos), optval, optlen); ++ err = copy_safe_from_sockptr(&qos, sizeof(qos), optval, optlen); + if (err) + break; + +@@ -1617,8 +1650,8 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(iso_pi(sk)->base, optlen, optval, +- optlen); ++ err = copy_safe_from_sockptr(iso_pi(sk)->base, optlen, optval, ++ optlen); + if (err) + break; + +diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c +index 18e89e764f3b42..3d2553dcdb1b3c 100644 +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -755,7 +755,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, + opts.max_tx = chan->max_tx; + opts.txwin_size = chan->tx_win; + +- err = bt_copy_from_sockptr(&opts, sizeof(opts), optval, optlen); ++ err = copy_safe_from_sockptr(&opts, sizeof(opts), optval, ++ optlen); + if (err) + break; + +@@ -800,7 +801,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, + break; + + case L2CAP_LM: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -909,7 +910,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + + sec.level = BT_SECURITY_LOW; + +- err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen); ++ err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen); + if (err) + break; + +@@ -956,7 +957,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -970,7 +971,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + + case BT_FLUSHABLE: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1004,7 +1005,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + + pwr.force_active = BT_POWER_FORCE_ACTIVE_ON; + +- err = bt_copy_from_sockptr(&pwr, sizeof(pwr), optval, optlen); ++ err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen); + if (err) + break; + +@@ -1015,7 +1016,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + + case BT_CHANNEL_POLICY: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -1046,7 +1047,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&mtu, sizeof(mtu), optval, optlen); ++ err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen); + if (err) + break; + +@@ -1076,7 +1077,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&mode, sizeof(mode), optval, optlen); ++ err = copy_safe_from_sockptr(&mode, sizeof(mode), optval, ++ optlen); + if (err) + break; + +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index 40766f8119ed9c..913402806fa0d4 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -629,10 +629,9 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, + + switch (optname) { + case RFCOMM_LM: +- if (bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen)) { +- err = -EFAULT; ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ if (err) + break; +- } + + if (opt & RFCOMM_LM_FIPS) { + err = -EINVAL; +@@ -685,7 +684,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, + + sec.level = BT_SECURITY_LOW; + +- err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen); ++ err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen); + if (err) + break; + +@@ -703,7 +702,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 1c7252a3686694..b872a2ca3ff38b 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -267,10 +267,13 @@ static int sco_connect(struct sock *sk) + else + type = SCO_LINK; + +- if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT && +- (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) { +- err = -EOPNOTSUPP; +- goto unlock; ++ switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) { ++ case SCO_AIRMODE_TRANSP: ++ if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) { ++ err = -EOPNOTSUPP; ++ goto unlock; ++ } ++ break; + } + + hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, +@@ -853,7 +856,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -872,18 +875,11 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + + voice.setting = sco_pi(sk)->setting; + +- err = bt_copy_from_sockptr(&voice, sizeof(voice), optval, +- optlen); ++ err = copy_safe_from_sockptr(&voice, sizeof(voice), optval, ++ optlen); + if (err) + break; + +- /* Explicitly check for these values */ +- if (voice.setting != BT_VOICE_TRANSPARENT && +- voice.setting != BT_VOICE_CVSD_16BIT) { +- err = -EINVAL; +- break; +- } +- + sco_pi(sk)->setting = voice.setting; + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, + BDADDR_BREDR); +@@ -891,14 +887,19 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + err = -EBADFD; + break; + } +- if (enhanced_sync_conn_capable(hdev) && +- voice.setting == BT_VOICE_TRANSPARENT) +- sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT; ++ ++ switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) { ++ case SCO_AIRMODE_TRANSP: ++ if (enhanced_sync_conn_capable(hdev)) ++ sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT; ++ break; ++ } ++ + hci_dev_put(hdev); + break; + + case BT_PKT_STATUS: +- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen); ++ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); + if (err) + break; + +@@ -941,7 +942,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- err = bt_copy_from_sockptr(buffer, optlen, optval, optlen); ++ err = copy_struct_from_sockptr(buffer, sizeof(buffer), optval, ++ optlen); + if (err) { + hci_dev_put(hdev); + break; +diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c +index e39479f1c9a486..70fea7c1a4b0a4 100644 +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -443,6 +443,21 @@ static struct net *net_alloc(void) + goto out; + } + ++static LLIST_HEAD(defer_free_list); ++ ++static void net_complete_free(void) ++{ ++ struct llist_node *kill_list; ++ struct net *net, *next; ++ ++ /* Get the list of namespaces to free from last round. */ ++ kill_list = llist_del_all(&defer_free_list); ++ ++ llist_for_each_entry_safe(net, next, kill_list, defer_free_list) ++ kmem_cache_free(net_cachep, net); ++ ++} ++ + static void net_free(struct net *net) + { + if (refcount_dec_and_test(&net->passive)) { +@@ -451,7 +466,8 @@ static void net_free(struct net *net) + /* There should not be any trackers left there. */ + ref_tracker_dir_exit(&net->notrefcnt_tracker); + +- kmem_cache_free(net_cachep, net); ++ /* Wait for an extra rcu_barrier() before final free. */ ++ llist_add(&net->defer_free_list, &defer_free_list); + } + } + +@@ -636,6 +652,8 @@ static void cleanup_net(struct work_struct *work) + */ + rcu_barrier(); + ++ net_complete_free(); ++ + /* Finally it is safe to free my network namespace structure */ + list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { + list_del_init(&net->exit_list); +diff --git a/net/core/sock_map.c b/net/core/sock_map.c +index 78347d7d25ef31..f1b9b3958792cd 100644 +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -159,6 +159,7 @@ static void sock_map_del_link(struct sock *sk, + verdict_stop = true; + list_del(&link->list); + sk_psock_free_link(link); ++ break; + } + } + spin_unlock_bh(&psock->link_lock); +@@ -411,12 +412,11 @@ static void *sock_map_lookup_sys(struct bpf_map *map, void *key) + static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test, + struct sock **psk) + { +- struct sock *sk; ++ struct sock *sk = NULL; + int err = 0; + + spin_lock_bh(&stab->lock); +- sk = *psk; +- if (!sk_test || sk_test == sk) ++ if (!sk_test || sk_test == *psk) + sk = xchg(psk, NULL); + + if (likely(sk)) +diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c +index 8e8b1bef6af69d..11ea8cfd62661c 100644 +--- a/net/dsa/tag_ocelot_8021q.c ++++ b/net/dsa/tag_ocelot_8021q.c +@@ -79,7 +79,7 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, + static struct sk_buff *ocelot_rcv(struct sk_buff *skb, + struct net_device *netdev) + { +- int src_port, switch_id; ++ int src_port = -1, switch_id = -1; + + dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL); + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 68804fd01dafc4..8efc58716ce969 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -883,8 +883,10 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, + unsigned int size; + + if (mptcp_syn_options(sk, skb, &size, &opts->mptcp)) { +- opts->options |= OPTION_MPTCP; +- remaining -= size; ++ if (remaining >= size) { ++ opts->options |= OPTION_MPTCP; ++ remaining -= size; ++ } + } + } + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 6dfc61a9acd4a5..1b1bf044378d48 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1061,13 +1061,13 @@ ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst, + { + int i, offset = 0; + ++ dst->cnt = src->cnt; + for (i = 0; i < src->cnt; i++) { + memcpy(pos + offset, src->elem[i].data, src->elem[i].len); + dst->elem[i].len = src->elem[i].len; + dst->elem[i].data = pos + offset; + offset += dst->elem[i].len; + } +- dst->cnt = src->cnt; + + return offset; + } +@@ -1911,6 +1911,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, + params->eht_capa_len, + link_sta); + ++ ieee80211_sta_init_nss(link_sta); ++ + if (params->opmode_notif_used) { + /* returned value is only needed for rc update, but the + * rc isn't initialized here yet, so ignore it +@@ -1920,8 +1922,6 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, + sband->band); + } + +- ieee80211_sta_init_nss(link_sta); +- + return 0; + } + +@@ -3674,13 +3674,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id) + } + EXPORT_SYMBOL(ieee80211_csa_finish); + +-void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx) ++void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif) + { + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + +- sdata->csa_blocked_queues = block_tx; + sdata_info(sdata, "channel switch failed, disconnecting\n"); + wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work); + } +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 3d3c9139ff5e45..7a0242e937d364 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1106,8 +1106,6 @@ struct ieee80211_sub_if_data { + + unsigned long state; + +- bool csa_blocked_queues; +- + char name[IFNAMSIZ]; + + struct ieee80211_fragment_cache frags; +@@ -2411,17 +2409,13 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata); + void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr, bool ack, u16 tx_time); +- ++unsigned int ++ieee80211_get_vif_queues(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata); + void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, + unsigned long queues, + enum queue_stop_reason reason, + bool refcounted); +-void ieee80211_stop_vif_queues(struct ieee80211_local *local, +- struct ieee80211_sub_if_data *sdata, +- enum queue_stop_reason reason); +-void ieee80211_wake_vif_queues(struct ieee80211_local *local, +- struct ieee80211_sub_if_data *sdata, +- enum queue_stop_reason reason); + void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, + unsigned long queues, + enum queue_stop_reason reason, +@@ -2432,6 +2426,43 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, + void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, + enum queue_stop_reason reason, + bool refcounted); ++static inline void ++ieee80211_stop_vif_queues(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ enum queue_stop_reason reason) ++{ ++ ieee80211_stop_queues_by_reason(&local->hw, ++ ieee80211_get_vif_queues(local, sdata), ++ reason, true); ++} ++ ++static inline void ++ieee80211_wake_vif_queues(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ enum queue_stop_reason reason) ++{ ++ ieee80211_wake_queues_by_reason(&local->hw, ++ ieee80211_get_vif_queues(local, sdata), ++ reason, true); ++} ++static inline void ++ieee80211_stop_vif_queues_norefcount(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ enum queue_stop_reason reason) ++{ ++ ieee80211_stop_queues_by_reason(&local->hw, ++ ieee80211_get_vif_queues(local, sdata), ++ reason, false); ++} ++static inline void ++ieee80211_wake_vif_queues_norefcount(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ enum queue_stop_reason reason) ++{ ++ ieee80211_wake_queues_by_reason(&local->hw, ++ ieee80211_get_vif_queues(local, sdata), ++ reason, false); ++} + void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb); + void ieee80211_add_pending_skbs(struct ieee80211_local *local, +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 6ef0990d3d296a..af9055252e6dfa 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -2364,18 +2364,14 @@ void ieee80211_vif_block_queues_csa(struct ieee80211_sub_if_data *sdata) + if (ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA)) + return; + +- ieee80211_stop_vif_queues(local, sdata, +- IEEE80211_QUEUE_STOP_REASON_CSA); +- sdata->csa_blocked_queues = true; ++ ieee80211_stop_vif_queues_norefcount(local, sdata, ++ IEEE80211_QUEUE_STOP_REASON_CSA); + } + + void ieee80211_vif_unblock_queues_csa(struct ieee80211_sub_if_data *sdata) + { + struct ieee80211_local *local = sdata->local; + +- if (sdata->csa_blocked_queues) { +- ieee80211_wake_vif_queues(local, sdata, +- IEEE80211_QUEUE_STOP_REASON_CSA); +- sdata->csa_blocked_queues = false; +- } ++ ieee80211_wake_vif_queues_norefcount(local, sdata, ++ IEEE80211_QUEUE_STOP_REASON_CSA); + } +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 0303972c23e4cb..111066928b963c 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2636,8 +2636,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, + */ + link->conf->csa_active = true; + link->u.mgd.csa.blocked_tx = csa_ie.mode; +- sdata->csa_blocked_queues = +- csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA); + + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); +diff --git a/net/mac80211/util.c b/net/mac80211/util.c +index f94faa86ba8a35..b4814e97cf7422 100644 +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -657,7 +657,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) + } + EXPORT_SYMBOL(ieee80211_wake_queues); + +-static unsigned int ++unsigned int + ieee80211_get_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) + { +@@ -669,7 +669,8 @@ ieee80211_get_vif_queues(struct ieee80211_local *local, + queues = 0; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) +- queues |= BIT(sdata->vif.hw_queue[ac]); ++ if (sdata->vif.hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) ++ queues |= BIT(sdata->vif.hw_queue[ac]); + if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE) + queues |= BIT(sdata->vif.cab_queue); + } else { +@@ -724,24 +725,6 @@ void ieee80211_flush_queues(struct ieee80211_local *local, + __ieee80211_flush_queues(local, sdata, 0, drop); + } + +-void ieee80211_stop_vif_queues(struct ieee80211_local *local, +- struct ieee80211_sub_if_data *sdata, +- enum queue_stop_reason reason) +-{ +- ieee80211_stop_queues_by_reason(&local->hw, +- ieee80211_get_vif_queues(local, sdata), +- reason, true); +-} +- +-void ieee80211_wake_vif_queues(struct ieee80211_local *local, +- struct ieee80211_sub_if_data *sdata, +- enum queue_stop_reason reason) +-{ +- ieee80211_wake_queues_by_reason(&local->hw, +- ieee80211_get_vif_queues(local, sdata), +- reason, true); +-} +- + static void __iterate_interfaces(struct ieee80211_local *local, + u32 iter_flags, + void (*iterator)(void *data, u8 *mac, +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 4a137afaf0b87e..0c5ff4afc37022 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -1495,7 +1495,6 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info, + INIT_LIST_HEAD(&table->sets); + INIT_LIST_HEAD(&table->objects); + INIT_LIST_HEAD(&table->flowtables); +- write_pnet(&table->net, net); + table->family = family; + table->flags = flags; + table->handle = ++nft_net->table_handle; +@@ -3884,8 +3883,11 @@ void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule) + kfree(rule); + } + ++/* can only be used if rule is no longer visible to dumps */ + static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule) + { ++ lockdep_commit_lock_is_held(ctx->net); ++ + nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE); + nf_tables_rule_destroy(ctx, rule); + } +@@ -5650,6 +5652,8 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_set_binding *binding, + enum nft_trans_phase phase) + { ++ lockdep_commit_lock_is_held(ctx->net); ++ + switch (phase) { + case NFT_TRANS_PREPARE_ERROR: + nft_set_trans_unbind(ctx, set); +@@ -11456,19 +11460,6 @@ static void __nft_release_basechain_now(struct nft_ctx *ctx) + nf_tables_chain_destroy(ctx->chain); + } + +-static void nft_release_basechain_rcu(struct rcu_head *head) +-{ +- struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head); +- struct nft_ctx ctx = { +- .family = chain->table->family, +- .chain = chain, +- .net = read_pnet(&chain->table->net), +- }; +- +- __nft_release_basechain_now(&ctx); +- put_net(ctx.net); +-} +- + int __nft_release_basechain(struct nft_ctx *ctx) + { + struct nft_rule *rule; +@@ -11483,11 +11474,18 @@ int __nft_release_basechain(struct nft_ctx *ctx) + nft_chain_del(ctx->chain); + nft_use_dec(&ctx->table->use); + +- if (maybe_get_net(ctx->net)) +- call_rcu(&ctx->chain->rcu_head, nft_release_basechain_rcu); +- else ++ if (!maybe_get_net(ctx->net)) { + __nft_release_basechain_now(ctx); ++ return 0; ++ } ++ ++ /* wait for ruleset dumps to complete. Owning chain is no longer in ++ * lists, so new dumps can't find any of these rules anymore. ++ */ ++ synchronize_rcu(); + ++ __nft_release_basechain_now(ctx); ++ put_net(ctx->net); + return 0; + } + EXPORT_SYMBOL_GPL(__nft_release_basechain); +diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c +index f8b25b6f5da736..9869ef3c2ab378 100644 +--- a/net/netfilter/xt_IDLETIMER.c ++++ b/net/netfilter/xt_IDLETIMER.c +@@ -409,21 +409,23 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) + + mutex_lock(&list_mutex); + +- if (--info->timer->refcnt == 0) { +- pr_debug("deleting timer %s\n", info->label); +- +- list_del(&info->timer->entry); +- timer_shutdown_sync(&info->timer->timer); +- cancel_work_sync(&info->timer->work); +- sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); +- kfree(info->timer->attr.attr.name); +- kfree(info->timer); +- } else { ++ if (--info->timer->refcnt > 0) { + pr_debug("decreased refcnt of timer %s to %u\n", + info->label, info->timer->refcnt); ++ mutex_unlock(&list_mutex); ++ return; + } + ++ pr_debug("deleting timer %s\n", info->label); ++ ++ list_del(&info->timer->entry); + mutex_unlock(&list_mutex); ++ ++ timer_shutdown_sync(&info->timer->timer); ++ cancel_work_sync(&info->timer->work); ++ sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); ++ kfree(info->timer->attr.attr.name); ++ kfree(info->timer); + } + + static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par) +@@ -434,25 +436,27 @@ static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par) + + mutex_lock(&list_mutex); + +- if (--info->timer->refcnt == 0) { +- pr_debug("deleting timer %s\n", info->label); +- +- list_del(&info->timer->entry); +- if (info->timer->timer_type & XT_IDLETIMER_ALARM) { +- alarm_cancel(&info->timer->alarm); +- } else { +- timer_shutdown_sync(&info->timer->timer); +- } +- cancel_work_sync(&info->timer->work); +- sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); +- kfree(info->timer->attr.attr.name); +- kfree(info->timer); +- } else { ++ if (--info->timer->refcnt > 0) { + pr_debug("decreased refcnt of timer %s to %u\n", + info->label, info->timer->refcnt); ++ mutex_unlock(&list_mutex); ++ return; + } + ++ pr_debug("deleting timer %s\n", info->label); ++ ++ list_del(&info->timer->entry); + mutex_unlock(&list_mutex); ++ ++ if (info->timer->timer_type & XT_IDLETIMER_ALARM) { ++ alarm_cancel(&info->timer->alarm); ++ } else { ++ timer_shutdown_sync(&info->timer->timer); ++ } ++ cancel_work_sync(&info->timer->work); ++ sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); ++ kfree(info->timer->attr.attr.name); ++ kfree(info->timer); + } + + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 39382ee1e33108..3b519adc01259f 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -78,6 +78,8 @@ struct netem_sched_data { + struct sk_buff *t_head; + struct sk_buff *t_tail; + ++ u32 t_len; ++ + /* optional qdisc for classful handling (NULL at netem init) */ + struct Qdisc *qdisc; + +@@ -382,6 +384,7 @@ static void tfifo_reset(struct Qdisc *sch) + rtnl_kfree_skbs(q->t_head, q->t_tail); + q->t_head = NULL; + q->t_tail = NULL; ++ q->t_len = 0; + } + + static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) +@@ -411,6 +414,7 @@ static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) + rb_link_node(&nskb->rbnode, parent, p); + rb_insert_color(&nskb->rbnode, &q->t_root); + } ++ q->t_len++; + sch->q.qlen++; + } + +@@ -517,7 +521,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1<q.qlen >= sch->limit)) { ++ if (unlikely(q->t_len >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +@@ -701,8 +705,8 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) + tfifo_dequeue: + skb = __qdisc_dequeue_head(&sch->q); + if (skb) { +- qdisc_qstats_backlog_dec(sch, skb); + deliver: ++ qdisc_qstats_backlog_dec(sch, skb); + qdisc_bstats_update(sch, skb); + return skb; + } +@@ -718,8 +722,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) + + if (time_to_send <= now && q->slot.slot_next <= now) { + netem_erase_head(q, skb); +- sch->q.qlen--; +- qdisc_qstats_backlog_dec(sch, skb); ++ q->t_len--; + skb->next = NULL; + skb->prev = NULL; + /* skb->dev shares skb->rbnode area, +@@ -746,16 +749,21 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) + if (net_xmit_drop_count(err)) + qdisc_qstats_drop(sch); + qdisc_tree_reduce_backlog(sch, 1, pkt_len); ++ sch->qstats.backlog -= pkt_len; ++ sch->q.qlen--; + } + goto tfifo_dequeue; + } ++ sch->q.qlen--; + goto deliver; + } + + if (q->qdisc) { + skb = q->qdisc->ops->dequeue(q->qdisc); +- if (skb) ++ if (skb) { ++ sch->q.qlen--; + goto deliver; ++ } + } + + qdisc_watchdog_schedule_ns(&q->watchdog, +@@ -765,8 +773,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) + + if (q->qdisc) { + skb = q->qdisc->ops->dequeue(q->qdisc); +- if (skb) ++ if (skb) { ++ sch->q.qlen--; + goto deliver; ++ } + } + return NULL; + } +diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c +index b7e25e7e9933b6..108a4cc2e00107 100644 +--- a/net/tipc/udp_media.c ++++ b/net/tipc/udp_media.c +@@ -807,6 +807,7 @@ static void cleanup_bearer(struct work_struct *work) + { + struct udp_bearer *ub = container_of(work, struct udp_bearer, work); + struct udp_replicast *rcast, *tmp; ++ struct tipc_net *tn; + + list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { + dst_cache_destroy(&rcast->dst_cache); +@@ -814,10 +815,14 @@ static void cleanup_bearer(struct work_struct *work) + kfree_rcu(rcast, rcu); + } + ++ tn = tipc_net(sock_net(ub->ubsock->sk)); ++ + dst_cache_destroy(&ub->rcast.dst_cache); + udp_tunnel_sock_release(ub->ubsock); ++ ++ /* Note: could use a call_rcu() to avoid another synchronize_net() */ + synchronize_net(); +- atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); ++ atomic_dec(&tn->wq_count); + kfree(ub); + } + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 001ccc55ef0f93..6b176230044397 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2313,6 +2313,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, + fds_sent = true; + + if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; + err = skb_splice_from_iter(skb, &msg->msg_iter, size, + sk->sk_allocation); + if (err < 0) { +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 9b1b9dc5a7eb2a..1e78f575fb5630 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -814,7 +814,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [NL80211_ATTR_MLO_LINKS] = + NLA_POLICY_NESTED_ARRAY(nl80211_policy), + [NL80211_ATTR_MLO_LINK_ID] = +- NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), ++ NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS - 1), + [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), + [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index 431da30817a6f6..26817160008766 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -83,6 +83,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) + if (!request) + return -ENOMEM; + ++ request->n_channels = n_channels; + if (wdev->conn->params.channel) { + enum nl80211_band band = wdev->conn->params.channel->band; + struct ieee80211_supported_band *sband = +diff --git a/rust/Makefile b/rust/Makefile +index b5e0a73b78f3e5..9f59baacaf7730 100644 +--- a/rust/Makefile ++++ b/rust/Makefile +@@ -267,9 +267,22 @@ endif + + bindgen_c_flags_final = $(bindgen_c_flags_lto) -D__BINDGEN__ + ++# Each `bindgen` release may upgrade the list of Rust target versions. By ++# default, the highest stable release in their list is used. Thus we need to set ++# a `--rust-target` to avoid future `bindgen` releases emitting code that ++# `rustc` may not understand. On top of that, `bindgen` does not support passing ++# an unknown Rust target version. ++# ++# Therefore, the Rust target for `bindgen` can be only as high as the minimum ++# Rust version the kernel supports and only as high as the greatest stable Rust ++# target supported by the minimum `bindgen` version the kernel supports (that ++# is, if we do not test the actual `rustc`/`bindgen` versions running). ++# ++# Starting with `bindgen` 0.71.0, we will be able to set any future Rust version ++# instead, i.e. we will be able to set here our minimum supported Rust version. + quiet_cmd_bindgen = BINDGEN $@ + cmd_bindgen = \ +- $(BINDGEN) $< $(bindgen_target_flags) \ ++ $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.68 \ + --use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \ + --no-debug '.*' --enable-function-attribute-detection \ + -o $@ -- $(bindgen_c_flags_final) -DMODULE \ +diff --git a/sound/core/control_led.c b/sound/core/control_led.c +index 65a1ebe877768f..e33dfcf863cf13 100644 +--- a/sound/core/control_led.c ++++ b/sound/core/control_led.c +@@ -668,10 +668,16 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card) + goto cerr; + led->cards[card->number] = led_card; + snprintf(link_name, sizeof(link_name), "led-%s", led->name); +- WARN(sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, link_name), +- "can't create symlink to controlC%i device\n", card->number); +- WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), +- "can't create symlink to card%i\n", card->number); ++ if (sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, ++ link_name)) ++ dev_err(card->dev, ++ "%s: can't create symlink to controlC%i device\n", ++ __func__, card->number); ++ if (sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, ++ "card")) ++ dev_err(card->dev, ++ "%s: can't create symlink to card%i\n", ++ __func__, card->number); + + continue; + cerr: +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 973671e0cdb09d..192fc75b51e6db 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10127,6 +10127,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), + SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), ++ SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index e38c5885dadfbc..ecf57a6cb7c37d 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -578,14 +578,19 @@ static int acp6x_probe(struct platform_device *pdev) + + handle = ACPI_HANDLE(pdev->dev.parent); + ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status); +- if (!ACPI_FAILURE(ret)) ++ if (!ACPI_FAILURE(ret)) { + wov_en = dmic_status; ++ if (!wov_en) ++ return -ENODEV; ++ } else { ++ /* Incase of ACPI method read failure then jump to check_dmi_entry */ ++ goto check_dmi_entry; ++ } + +- if (is_dmic_enable && wov_en) ++ if (is_dmic_enable) + platform_set_drvdata(pdev, &acp6x_card); +- else +- return 0; + ++check_dmi_entry: + /* check for any DMI overrides */ + dmi_id = dmi_first_match(yc_acp_quirk_table); + if (dmi_id) +diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c +index 12d093437ba9b6..1b2f55030c3961 100644 +--- a/sound/soc/codecs/tas2781-i2c.c ++++ b/sound/soc/codecs/tas2781-i2c.c +@@ -370,7 +370,7 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, + tasdevice_dev_read(tas_priv, i, p[j].reg, + (int *)&p[j].val[0]); + } else { +- switch (p[j].reg) { ++ switch (tas2781_cali_start_reg[j].reg) { + case 0: { + if (!reg[0]) + continue; +diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c +index b6ff04f7138a2c..ee946e0d3f4969 100644 +--- a/sound/soc/fsl/fsl_spdif.c ++++ b/sound/soc/fsl/fsl_spdif.c +@@ -1204,7 +1204,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { + }, + /* DPLL lock info get controller */ + { +- .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = RX_SAMPLE_RATE_KCONTROL, + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index beede7344efd63..4341269eb97780 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -169,7 +169,7 @@ static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol, + } + + static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = { +- .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capabilities Data Structure", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = fsl_xcvr_type_capds_bytes_info, +diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c +index a58842a8c8a641..db57292c00ca1e 100644 +--- a/sound/soc/intel/boards/sof_sdw.c ++++ b/sound/soc/intel/boards/sof_sdw.c +@@ -1003,8 +1003,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) + return ret; + } + +- /* One per DAI link, worst case is a DAI link for every endpoint */ +- sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); ++ /* ++ * One per DAI link, worst case is a DAI link for every endpoint, also ++ * add one additional to act as a terminator such that code can iterate ++ * until it hits an uninitialised DAI. ++ */ ++ sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); + if (!sof_dais) + return -ENOMEM; + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 00101875d9a8d5..a0767de7f1b7ed 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2179,6 +2179,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR), ++ DEVICE_FLG(0x0499, 0x1506, /* Yamaha THR5 */ ++ QUIRK_FLAG_GENERIC_IMPLICIT_FB), + DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */ + QUIRK_FLAG_GENERIC_IMPLICIT_FB), + DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */ +diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c +index c6d67fc9e57ef0..83c43dc13313cc 100644 +--- a/tools/lib/perf/evlist.c ++++ b/tools/lib/perf/evlist.c +@@ -47,6 +47,20 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, + */ + perf_cpu_map__put(evsel->cpus); + evsel->cpus = perf_cpu_map__intersect(evlist->user_requested_cpus, evsel->own_cpus); ++ ++ /* ++ * Empty cpu lists would eventually get opened as "any" so remove ++ * genuinely empty ones before they're opened in the wrong place. ++ */ ++ if (perf_cpu_map__is_empty(evsel->cpus)) { ++ struct perf_evsel *next = perf_evlist__next(evlist, evsel); ++ ++ perf_evlist__remove(evlist, evsel); ++ /* Keep idx contiguous */ ++ if (next) ++ list_for_each_entry_from(next, &evlist->entries, node) ++ next->idx--; ++ } + } else if (!evsel->own_cpus || evlist->has_user_cpus || + (!evsel->requires_cpu && perf_cpu_map__has_any_cpu(evlist->user_requested_cpus))) { + /* +@@ -80,11 +94,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, + + static void perf_evlist__propagate_maps(struct perf_evlist *evlist) + { +- struct perf_evsel *evsel; ++ struct perf_evsel *evsel, *n; + + evlist->needs_map_propagation = true; + +- perf_evlist__for_each_evsel(evlist, evsel) ++ list_for_each_entry_safe(evsel, n, &evlist->entries, node) + __perf_evlist__propagate_maps(evlist, evsel); + } + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 6604f5d038aadf..f0d8796b984a80 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -3820,9 +3820,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + break; + + case INSN_CONTEXT_SWITCH: +- if (func && (!next_insn || !next_insn->hint)) { +- WARN_INSN(insn, "unsupported instruction in callable function"); +- return 1; ++ if (func) { ++ if (!next_insn || !next_insn->hint) { ++ WARN_INSN(insn, "unsupported instruction in callable function"); ++ return 1; ++ } ++ break; + } + return 0; + +diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c +index 272d3c70810e7d..a56cf8b0a7d405 100644 +--- a/tools/perf/builtin-ftrace.c ++++ b/tools/perf/builtin-ftrace.c +@@ -1151,8 +1151,9 @@ static int cmp_profile_data(const void *a, const void *b) + + if (v1 > v2) + return -1; +- else ++ if (v1 < v2) + return 1; ++ return 0; + } + + static void print_profile_result(struct perf_ftrace *ftrace) +diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c +index 8982f68e7230cd..e763e8d99a4367 100644 +--- a/tools/perf/util/build-id.c ++++ b/tools/perf/util/build-id.c +@@ -277,7 +277,7 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid + struct perf_record_header_build_id b; + size_t len; + +- len = sizeof(b) + name_len + 1; ++ len = name_len + 1; + len = PERF_ALIGN(len, sizeof(u64)); + + memset(&b, 0, sizeof(b)); +@@ -286,7 +286,7 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid + misc |= PERF_RECORD_MISC_BUILD_ID_SIZE; + b.pid = pid; + b.header.misc = misc; +- b.header.size = len; ++ b.header.size = sizeof(b) + len; + + err = do_write(fd, &b, sizeof(b)); + if (err < 0) +diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c +index 4f0ac998b0ccfd..27d5345d2b307a 100644 +--- a/tools/perf/util/machine.c ++++ b/tools/perf/util/machine.c +@@ -134,6 +134,8 @@ struct machine *machine__new_host(void) + + if (machine__create_kernel_maps(machine) < 0) + goto out_delete; ++ ++ machine->env = &perf_env; + } + + return machine; +diff --git a/tools/testing/selftests/arm64/abi/syscall-abi-asm.S b/tools/testing/selftests/arm64/abi/syscall-abi-asm.S +index df3230fdac3958..66ab2e0bae5fd0 100644 +--- a/tools/testing/selftests/arm64/abi/syscall-abi-asm.S ++++ b/tools/testing/selftests/arm64/abi/syscall-abi-asm.S +@@ -81,32 +81,31 @@ do_syscall: + stp x27, x28, [sp, #96] + + // Set SVCR if we're doing SME +- cbz x1, 1f ++ cbz x1, load_gpr + adrp x2, svcr_in + ldr x2, [x2, :lo12:svcr_in] + msr S3_3_C4_C2_2, x2 +-1: + + // Load ZA and ZT0 if enabled - uses x12 as scratch due to SME LDR +- tbz x2, #SVCR_ZA_SHIFT, 1f ++ tbz x2, #SVCR_ZA_SHIFT, load_gpr + mov w12, #0 + ldr x2, =za_in +-2: _ldr_za 12, 2 ++1: _ldr_za 12, 2 + add x2, x2, x1 + add x12, x12, #1 + cmp x1, x12 +- bne 2b ++ bne 1b + + // ZT0 + mrs x2, S3_0_C0_C4_5 // ID_AA64SMFR0_EL1 + ubfx x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \ + #ID_AA64SMFR0_EL1_SMEver_WIDTH +- cbz x2, 1f ++ cbz x2, load_gpr + adrp x2, zt_in + add x2, x2, :lo12:zt_in + _ldr_zt 2 +-1: + ++load_gpr: + // Load GPRs x8-x28, and save our SP/FP for later comparison + ldr x2, =gpr_in + add x2, x2, #64 +@@ -125,9 +124,9 @@ do_syscall: + str x30, [x2], #8 // LR + + // Load FPRs if we're not doing neither SVE nor streaming SVE +- cbnz x0, 1f ++ cbnz x0, check_sve_in + ldr x2, =svcr_in +- tbnz x2, #SVCR_SM_SHIFT, 1f ++ tbnz x2, #SVCR_SM_SHIFT, check_sve_in + + ldr x2, =fpr_in + ldp q0, q1, [x2] +@@ -148,8 +147,8 @@ do_syscall: + ldp q30, q31, [x2, #16 * 30] + + b 2f +-1: + ++check_sve_in: + // Load the SVE registers if we're doing SVE/SME + + ldr x2, =z_in +@@ -256,32 +255,31 @@ do_syscall: + stp q30, q31, [x2, #16 * 30] + + // Save SVCR if we're doing SME +- cbz x1, 1f ++ cbz x1, check_sve_out + mrs x2, S3_3_C4_C2_2 + adrp x3, svcr_out + str x2, [x3, :lo12:svcr_out] +-1: + + // Save ZA if it's enabled - uses x12 as scratch due to SME STR +- tbz x2, #SVCR_ZA_SHIFT, 1f ++ tbz x2, #SVCR_ZA_SHIFT, check_sve_out + mov w12, #0 + ldr x2, =za_out +-2: _str_za 12, 2 ++1: _str_za 12, 2 + add x2, x2, x1 + add x12, x12, #1 + cmp x1, x12 +- bne 2b ++ bne 1b + + // ZT0 + mrs x2, S3_0_C0_C4_5 // ID_AA64SMFR0_EL1 + ubfx x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \ + #ID_AA64SMFR0_EL1_SMEver_WIDTH +- cbz x2, 1f ++ cbz x2, check_sve_out + adrp x2, zt_out + add x2, x2, :lo12:zt_out + _str_zt 2 +-1: + ++check_sve_out: + // Save the SVE state if we have some + cbz x0, 1f + +diff --git a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c +index 5aaf2b065f86c2..bba3e37f749b86 100644 +--- a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c ++++ b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c +@@ -7,11 +7,7 @@ + #include "bpf_misc.h" + + SEC("tp_btf/bpf_testmod_test_nullable_bare") +-/* This used to be a failure test, but raw_tp nullable arguments can now +- * directly be dereferenced, whether they have nullable annotation or not, +- * and don't need to be explicitly checked. +- */ +-__success ++__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") + int BPF_PROG(handle_tp_btf_nullable_bare1, struct bpf_testmod_test_read_ctx *nullable_ctx) + { + return nullable_ctx->len; +diff --git a/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c b/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c +index a570e48b917acc..bfc3bf18fed4fe 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c ++++ b/tools/testing/selftests/bpf/progs/verifier_btf_ctx_access.c +@@ -11,7 +11,7 @@ __success __retval(0) + __naked void btf_ctx_access_accept(void) + { + asm volatile (" \ +- r2 = *(u32*)(r1 + 8); /* load 2nd argument value (int pointer) */\ ++ r2 = *(u64 *)(r1 + 8); /* load 2nd argument value (int pointer) */\ + r0 = 0; \ + exit; \ + " ::: __clobber_all); +@@ -23,7 +23,7 @@ __success __retval(0) + __naked void ctx_access_u32_pointer_accept(void) + { + asm volatile (" \ +- r2 = *(u32*)(r1 + 0); /* load 1nd argument value (u32 pointer) */\ ++ r2 = *(u64 *)(r1 + 0); /* load 1nd argument value (u32 pointer) */\ + r0 = 0; \ + exit; \ + " ::: __clobber_all); +diff --git a/tools/testing/selftests/bpf/progs/verifier_d_path.c b/tools/testing/selftests/bpf/progs/verifier_d_path.c +index ec79cbcfde91ef..87e51a215558fd 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_d_path.c ++++ b/tools/testing/selftests/bpf/progs/verifier_d_path.c +@@ -11,7 +11,7 @@ __success __retval(0) + __naked void d_path_accept(void) + { + asm volatile (" \ +- r1 = *(u32*)(r1 + 0); \ ++ r1 = *(u64 *)(r1 + 0); \ + r2 = r10; \ + r2 += -8; \ + r6 = 0; \ +@@ -31,7 +31,7 @@ __failure __msg("helper call is not allowed in probe") + __naked void d_path_reject(void) + { + asm volatile (" \ +- r1 = *(u32*)(r1 + 0); \ ++ r1 = *(u64 *)(r1 + 0); \ + r2 = r10; \ + r2 += -8; \ + r6 = 0; \ +diff --git a/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer.sh b/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer.sh +index 0c47faff9274b1..c068e6c2a580ea 100755 +--- a/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer.sh ++++ b/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer.sh +@@ -22,20 +22,34 @@ SB_ITC=0 + h1_create() + { + simple_if_init $h1 192.0.1.1/24 ++ tc qdisc add dev $h1 clsact ++ ++ # Add egress filter on $h1 that will guarantee that the packet sent, ++ # will be the only packet being passed to the device. ++ tc filter add dev $h1 egress pref 2 handle 102 matchall action drop + } + + h1_destroy() + { ++ tc filter del dev $h1 egress pref 2 handle 102 matchall action drop ++ tc qdisc del dev $h1 clsact + simple_if_fini $h1 192.0.1.1/24 + } + + h2_create() + { + simple_if_init $h2 192.0.1.2/24 ++ tc qdisc add dev $h2 clsact ++ ++ # Add egress filter on $h2 that will guarantee that the packet sent, ++ # will be the only packet being passed to the device. ++ tc filter add dev $h2 egress pref 1 handle 101 matchall action drop + } + + h2_destroy() + { ++ tc filter del dev $h2 egress pref 1 handle 101 matchall action drop ++ tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.1.2/24 + } + +@@ -101,6 +115,11 @@ port_pool_test() + local exp_max_occ=$(devlink_cell_size_get) + local max_occ + ++ tc filter add dev $h1 egress protocol ip pref 1 handle 101 flower \ ++ src_mac $h1mac dst_mac $h2mac \ ++ src_ip 192.0.1.1 dst_ip 192.0.1.2 \ ++ action pass ++ + devlink sb occupancy clearmax $DEVLINK_DEV + + $MZ $h1 -c 1 -p 10 -a $h1mac -b $h2mac -A 192.0.1.1 -B 192.0.1.2 \ +@@ -108,11 +127,6 @@ port_pool_test() + + devlink sb occupancy snapshot $DEVLINK_DEV + +- RET=0 +- max_occ=$(sb_occ_pool_check $dl_port1 $SB_POOL_ING $exp_max_occ) +- check_err $? "Expected iPool($SB_POOL_ING) max occupancy to be $exp_max_occ, but got $max_occ" +- log_test "physical port's($h1) ingress pool" +- + RET=0 + max_occ=$(sb_occ_pool_check $dl_port2 $SB_POOL_ING $exp_max_occ) + check_err $? "Expected iPool($SB_POOL_ING) max occupancy to be $exp_max_occ, but got $max_occ" +@@ -122,6 +136,11 @@ port_pool_test() + max_occ=$(sb_occ_pool_check $cpu_dl_port $SB_POOL_EGR_CPU $exp_max_occ) + check_err $? "Expected ePool($SB_POOL_EGR_CPU) max occupancy to be $exp_max_occ, but got $max_occ" + log_test "CPU port's egress pool" ++ ++ tc filter del dev $h1 egress protocol ip pref 1 handle 101 flower \ ++ src_mac $h1mac dst_mac $h2mac \ ++ src_ip 192.0.1.1 dst_ip 192.0.1.2 \ ++ action pass + } + + port_tc_ip_test() +@@ -129,6 +148,11 @@ port_tc_ip_test() + local exp_max_occ=$(devlink_cell_size_get) + local max_occ + ++ tc filter add dev $h1 egress protocol ip pref 1 handle 101 flower \ ++ src_mac $h1mac dst_mac $h2mac \ ++ src_ip 192.0.1.1 dst_ip 192.0.1.2 \ ++ action pass ++ + devlink sb occupancy clearmax $DEVLINK_DEV + + $MZ $h1 -c 1 -p 10 -a $h1mac -b $h2mac -A 192.0.1.1 -B 192.0.1.2 \ +@@ -136,11 +160,6 @@ port_tc_ip_test() + + devlink sb occupancy snapshot $DEVLINK_DEV + +- RET=0 +- max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ) +- check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ" +- log_test "physical port's($h1) ingress TC - IP packet" +- + RET=0 + max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ) + check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ" +@@ -150,6 +169,11 @@ port_tc_ip_test() + max_occ=$(sb_occ_etc_check $cpu_dl_port $SB_ITC_CPU_IP $exp_max_occ) + check_err $? "Expected egress TC($SB_ITC_CPU_IP) max occupancy to be $exp_max_occ, but got $max_occ" + log_test "CPU port's egress TC - IP packet" ++ ++ tc filter del dev $h1 egress protocol ip pref 1 handle 101 flower \ ++ src_mac $h1mac dst_mac $h2mac \ ++ src_ip 192.0.1.1 dst_ip 192.0.1.2 \ ++ action pass + } + + port_tc_arp_test() +@@ -157,17 +181,15 @@ port_tc_arp_test() + local exp_max_occ=$(devlink_cell_size_get) + local max_occ + ++ tc filter add dev $h1 egress protocol arp pref 1 handle 101 flower \ ++ src_mac $h1mac action pass ++ + devlink sb occupancy clearmax $DEVLINK_DEV + + $MZ $h1 -c 1 -p 10 -a $h1mac -A 192.0.1.1 -t arp -q + + devlink sb occupancy snapshot $DEVLINK_DEV + +- RET=0 +- max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ) +- check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ" +- log_test "physical port's($h1) ingress TC - ARP packet" +- + RET=0 + max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ) + check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ" +@@ -177,6 +199,9 @@ port_tc_arp_test() + max_occ=$(sb_occ_etc_check $cpu_dl_port $SB_ITC_CPU_ARP $exp_max_occ) + check_err $? "Expected egress TC($SB_ITC_IP2ME) max occupancy to be $exp_max_occ, but got $max_occ" + log_test "CPU port's egress TC - ARP packet" ++ ++ tc filter del dev $h1 egress protocol arp pref 1 handle 101 flower \ ++ src_mac $h1mac action pass + } + + setup_prepare() +diff --git a/tools/testing/selftests/net/netfilter/rpath.sh b/tools/testing/selftests/net/netfilter/rpath.sh +index 4485fd7675ed7e..86ec4e68594dc3 100755 +--- a/tools/testing/selftests/net/netfilter/rpath.sh ++++ b/tools/testing/selftests/net/netfilter/rpath.sh +@@ -61,9 +61,20 @@ ip -net "$ns2" a a 192.168.42.1/24 dev d0 + ip -net "$ns1" a a fec0:42::2/64 dev v0 nodad + ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad + ++# avoid neighbor lookups and enable martian IPv6 pings ++ns2_hwaddr=$(ip -net "$ns2" link show dev v0 | \ ++ sed -n 's, *link/ether \([^ ]*\) .*,\1,p') ++ns1_hwaddr=$(ip -net "$ns1" link show dev v0 | \ ++ sed -n 's, *link/ether \([^ ]*\) .*,\1,p') ++ip -net "$ns1" neigh add fec0:42::1 lladdr "$ns2_hwaddr" nud permanent dev v0 ++ip -net "$ns1" neigh add fec0:23::1 lladdr "$ns2_hwaddr" nud permanent dev v0 ++ip -net "$ns2" neigh add fec0:42::2 lladdr "$ns1_hwaddr" nud permanent dev d0 ++ip -net "$ns2" neigh add fec0:23::2 lladdr "$ns1_hwaddr" nud permanent dev v0 ++ + # firewall matches to test + [ -n "$iptables" ] && { + common='-t raw -A PREROUTING -s 192.168.0.0/16' ++ common+=' -p icmp --icmp-type echo-request' + if ! ip netns exec "$ns2" "$iptables" $common -m rpfilter;then + echo "Cannot add rpfilter rule" + exit $ksft_skip +@@ -72,6 +83,7 @@ ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad + } + [ -n "$ip6tables" ] && { + common='-t raw -A PREROUTING -s fec0::/16' ++ common+=' -p icmpv6 --icmpv6-type echo-request' + if ! ip netns exec "$ns2" "$ip6tables" $common -m rpfilter;then + echo "Cannot add rpfilter rule" + exit $ksft_skip +@@ -82,8 +94,10 @@ ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad + table inet t { + chain c { + type filter hook prerouting priority raw; +- ip saddr 192.168.0.0/16 fib saddr . iif oif exists counter +- ip6 saddr fec0::/16 fib saddr . iif oif exists counter ++ ip saddr 192.168.0.0/16 icmp type echo-request \ ++ fib saddr . iif oif exists counter ++ ip6 saddr fec0::/16 icmpv6 type echo-request \ ++ fib saddr . iif oif exists counter + } + } + EOF