From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (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 048DD1581B9 for ; Thu, 25 Sep 2025 12:02:22 +0000 (UTC) Received: from lists.gentoo.org (bobolink.gentoo.org [140.211.166.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) (Authenticated sender: relay-lists.gentoo.org@gentoo.org) by smtp.gentoo.org (Postfix) with ESMTPSA id E3D18340E18 for ; Thu, 25 Sep 2025 12:02:21 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id 5E95D110573; Thu, 25 Sep 2025 12:02:20 +0000 (UTC) Received: from smtp.gentoo.org (smtp.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) (No client certificate requested) by bobolink.gentoo.org (Postfix) with ESMTPS id 54574110573 for ; Thu, 25 Sep 2025 12:02:20 +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) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 6B115340E18 for ; Thu, 25 Sep 2025 12:02:19 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id AFE5739C3 for ; Thu, 25 Sep 2025 12:02:17 +0000 (UTC) From: "Arisu Tachibana" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Arisu Tachibana" Message-ID: <1758801724.fb4386cb8d3a0e3944fcbd135b1a7c53cd28d3ad.alicef@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.16 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1008_linux-6.16.9.patch X-VCS-Directories: / X-VCS-Committer: alicef X-VCS-Committer-Name: Arisu Tachibana X-VCS-Revision: fb4386cb8d3a0e3944fcbd135b1a7c53cd28d3ad X-VCS-Branch: 6.16 Date: Thu, 25 Sep 2025 12:02:17 +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: 1e85ca0a-00ee-4608-87d0-56ca912fd9da X-Archives-Hash: 99078ccda59a4ee1ad13ab7719b2e6a2 commit: fb4386cb8d3a0e3944fcbd135b1a7c53cd28d3ad Author: Arisu Tachibana gentoo org> AuthorDate: Thu Sep 25 12:02:04 2025 +0000 Commit: Arisu Tachibana gentoo org> CommitDate: Thu Sep 25 12:02:04 2025 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=fb4386cb Linux patch 6.16.9 Signed-off-by: Arisu Tachibana gentoo.org> 0000_README | 4 + 1008_linux-6.16.9.patch | 6546 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 6550 insertions(+) diff --git a/0000_README b/0000_README index b72d6630..48b50ad0 100644 --- a/0000_README +++ b/0000_README @@ -75,6 +75,10 @@ Patch: 1007_linux-6.16.8.patch From: https://www.kernel.org Desc: Linux 6.16.8 +Patch: 1008_linux-6.16.9.patch +From: https://www.kernel.org +Desc: Linux 6.16.9 + 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/1008_linux-6.16.9.patch b/1008_linux-6.16.9.patch new file mode 100644 index 00000000..3a65fc5a --- /dev/null +++ b/1008_linux-6.16.9.patch @@ -0,0 +1,6546 @@ +diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml +index c6bc27709bf726..f59c0b37e8ebb2 100644 +--- a/Documentation/devicetree/bindings/serial/8250.yaml ++++ b/Documentation/devicetree/bindings/serial/8250.yaml +@@ -48,6 +48,45 @@ allOf: + oneOf: + - required: [ clock-frequency ] + - required: [ clocks ] ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: nxp,lpc1850-uart ++ then: ++ properties: ++ clock-names: ++ items: ++ - const: uartclk ++ - const: reg ++ else: ++ properties: ++ clock-names: ++ items: ++ - const: core ++ - const: bus ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - spacemit,k1-uart ++ - nxp,lpc1850-uart ++ then: ++ required: ++ - clocks ++ - clock-names ++ properties: ++ clocks: ++ minItems: 2 ++ clock-names: ++ minItems: 2 ++ else: ++ properties: ++ clocks: ++ maxItems: 1 ++ clock-names: ++ maxItems: 1 + + properties: + compatible: +@@ -142,9 +181,22 @@ properties: + + clock-names: + minItems: 1 +- items: +- - const: core +- - const: bus ++ maxItems: 2 ++ oneOf: ++ - items: ++ - const: core ++ - const: bus ++ - items: ++ - const: uartclk ++ - const: reg ++ ++ dmas: ++ minItems: 1 ++ maxItems: 4 ++ ++ dma-names: ++ minItems: 1 ++ maxItems: 4 + + resets: + maxItems: 1 +@@ -233,25 +285,6 @@ required: + - reg + - interrupts + +-if: +- properties: +- compatible: +- contains: +- const: spacemit,k1-uart +-then: +- required: [clock-names] +- properties: +- clocks: +- minItems: 2 +- clock-names: +- minItems: 2 +-else: +- properties: +- clocks: +- maxItems: 1 +- clock-names: +- maxItems: 1 +- + unevaluatedProperties: false + + examples: +diff --git a/Documentation/netlink/specs/conntrack.yaml b/Documentation/netlink/specs/conntrack.yaml +index 840dc4504216bc..1865ddf01fb0f6 100644 +--- a/Documentation/netlink/specs/conntrack.yaml ++++ b/Documentation/netlink/specs/conntrack.yaml +@@ -575,8 +575,8 @@ operations: + - nat-dst + - timeout + - mark +- - counter-orig +- - counter-reply ++ - counters-orig ++ - counters-reply + - use + - id + - nat-dst +@@ -591,7 +591,6 @@ operations: + request: + value: 0x101 + attributes: +- - nfgen-family + - mark + - filter + - status +@@ -608,8 +607,8 @@ operations: + - nat-dst + - timeout + - mark +- - counter-orig +- - counter-reply ++ - counters-orig ++ - counters-reply + - use + - id + - nat-dst +diff --git a/Documentation/netlink/specs/mptcp_pm.yaml b/Documentation/netlink/specs/mptcp_pm.yaml +index ecfe5ee33de2d8..c77f32cfcae973 100644 +--- a/Documentation/netlink/specs/mptcp_pm.yaml ++++ b/Documentation/netlink/specs/mptcp_pm.yaml +@@ -28,13 +28,13 @@ definitions: + traffic-patterns it can take a long time until the + MPTCP_EVENT_ESTABLISHED is sent. + Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, sport, +- dport, server-side. ++ dport, server-side, [flags]. + - + name: established + doc: >- + A MPTCP connection is established (can start new subflows). + Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, sport, +- dport, server-side. ++ dport, server-side, [flags]. + - + name: closed + doc: >- +diff --git a/Makefile b/Makefile +index 7594f35cbc2a5a..aef2cb6ea99d8b 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 16 +-SUBLEVEL = 8 ++SUBLEVEL = 9 + EXTRAVERSION = + NAME = Baby Opossum Posse + +diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig +index 4b19f93379a153..eb13fcf095a1d4 100644 +--- a/arch/loongarch/Kconfig ++++ b/arch/loongarch/Kconfig +@@ -301,6 +301,10 @@ config AS_HAS_LVZ_EXTENSION + config CC_HAS_ANNOTATE_TABLEJUMP + def_bool $(cc-option,-mannotate-tablejump) + ++config RUSTC_HAS_ANNOTATE_TABLEJUMP ++ depends on RUST ++ def_bool $(rustc-option,-Cllvm-args=--loongarch-annotate-tablejump) ++ + menu "Kernel type and options" + + source "kernel/Kconfig.hz" +@@ -566,10 +570,14 @@ config ARCH_STRICT_ALIGN + -mstrict-align build parameter to prevent unaligned accesses. + + CPUs with h/w unaligned access support: +- Loongson-2K2000/2K3000/3A5000/3C5000/3D5000. ++ Loongson-2K2000/2K3000 and all of Loongson-3 series processors ++ based on LoongArch. + + CPUs without h/w unaligned access support: +- Loongson-2K500/2K1000. ++ Loongson-2K0300/2K0500/2K1000. ++ ++ If you want to make sure whether to support unaligned memory access ++ on your hardware, please read the bit 20 (UAL) of CPUCFG1 register. + + This option is enabled by default to make the kernel be able to run + on all LoongArch systems. But you can disable it manually if you want +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index a3a9759414f40f..ae419e32f22e2f 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -102,16 +102,21 @@ KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma) + + ifdef CONFIG_OBJTOOL + ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP ++KBUILD_CFLAGS += -mannotate-tablejump ++else ++KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers ++endif ++ifdef CONFIG_RUSTC_HAS_ANNOTATE_TABLEJUMP ++KBUILD_RUSTFLAGS += -Cllvm-args=--loongarch-annotate-tablejump ++else ++KBUILD_RUSTFLAGS += -Zno-jump-tables # keep compatibility with older compilers ++endif ++ifdef CONFIG_LTO_CLANG + # The annotate-tablejump option can not be passed to LLVM backend when LTO is enabled. + # Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' also needs to + # be passed via '-mllvm' to ld.lld. +-KBUILD_CFLAGS += -mannotate-tablejump +-ifdef CONFIG_LTO_CLANG + KBUILD_LDFLAGS += -mllvm --loongarch-annotate-tablejump + endif +-else +-KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers +-endif + endif + + KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat -Ccode-model=small +diff --git a/arch/loongarch/include/asm/acenv.h b/arch/loongarch/include/asm/acenv.h +index 52f298f7293bab..483c955f2ae50d 100644 +--- a/arch/loongarch/include/asm/acenv.h ++++ b/arch/loongarch/include/asm/acenv.h +@@ -10,9 +10,8 @@ + #ifndef _ASM_LOONGARCH_ACENV_H + #define _ASM_LOONGARCH_ACENV_H + +-/* +- * This header is required by ACPI core, but we have nothing to fill in +- * right now. Will be updated later when needed. +- */ ++#ifdef CONFIG_ARCH_STRICT_ALIGN ++#define ACPI_MISALIGNMENT_NOT_SUPPORTED ++#endif /* CONFIG_ARCH_STRICT_ALIGN */ + + #endif /* _ASM_LOONGARCH_ACENV_H */ +diff --git a/arch/loongarch/include/asm/kvm_mmu.h b/arch/loongarch/include/asm/kvm_mmu.h +index 099bafc6f797c9..e36cc7e8ed200a 100644 +--- a/arch/loongarch/include/asm/kvm_mmu.h ++++ b/arch/loongarch/include/asm/kvm_mmu.h +@@ -16,6 +16,13 @@ + */ + #define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1) + ++/* ++ * _PAGE_MODIFIED is a SW pte bit, it records page ever written on host ++ * kernel, on secondary MMU it records the page writeable attribute, in ++ * order for fast path handling. ++ */ ++#define KVM_PAGE_WRITEABLE _PAGE_MODIFIED ++ + #define _KVM_FLUSH_PGTABLE 0x1 + #define _KVM_HAS_PGMASK 0x2 + #define kvm_pfn_pte(pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) +@@ -52,10 +59,10 @@ static inline void kvm_set_pte(kvm_pte_t *ptep, kvm_pte_t val) + WRITE_ONCE(*ptep, val); + } + +-static inline int kvm_pte_write(kvm_pte_t pte) { return pte & _PAGE_WRITE; } +-static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & _PAGE_DIRTY; } + static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; } + static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; } ++static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & __WRITEABLE; } ++static inline int kvm_pte_writeable(kvm_pte_t pte) { return pte & KVM_PAGE_WRITEABLE; } + + static inline kvm_pte_t kvm_pte_mkyoung(kvm_pte_t pte) + { +@@ -69,12 +76,12 @@ static inline kvm_pte_t kvm_pte_mkold(kvm_pte_t pte) + + static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte) + { +- return pte | _PAGE_DIRTY; ++ return pte | __WRITEABLE; + } + + static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte) + { +- return pte & ~_PAGE_DIRTY; ++ return pte & ~__WRITEABLE; + } + + static inline kvm_pte_t kvm_pte_mkhuge(kvm_pte_t pte) +@@ -87,6 +94,11 @@ static inline kvm_pte_t kvm_pte_mksmall(kvm_pte_t pte) + return pte & ~_PAGE_HUGE; + } + ++static inline kvm_pte_t kvm_pte_mkwriteable(kvm_pte_t pte) ++{ ++ return pte | KVM_PAGE_WRITEABLE; ++} ++ + static inline int kvm_need_flush(kvm_ptw_ctx *ctx) + { + return ctx->flag & _KVM_FLUSH_PGTABLE; +diff --git a/arch/loongarch/kernel/env.c b/arch/loongarch/kernel/env.c +index c0a5dc9aeae287..be309a71f20491 100644 +--- a/arch/loongarch/kernel/env.c ++++ b/arch/loongarch/kernel/env.c +@@ -109,6 +109,8 @@ static int __init boardinfo_init(void) + struct kobject *loongson_kobj; + + loongson_kobj = kobject_create_and_add("loongson", firmware_kobj); ++ if (!loongson_kobj) ++ return -ENOMEM; + + return sysfs_create_file(loongson_kobj, &boardinfo_attr.attr); + } +diff --git a/arch/loongarch/kernel/stacktrace.c b/arch/loongarch/kernel/stacktrace.c +index 9a038d1070d73b..387dc4d3c4868f 100644 +--- a/arch/loongarch/kernel/stacktrace.c ++++ b/arch/loongarch/kernel/stacktrace.c +@@ -51,12 +51,13 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, + if (task == current) { + regs->regs[3] = (unsigned long)__builtin_frame_address(0); + regs->csr_era = (unsigned long)__builtin_return_address(0); ++ regs->regs[22] = 0; + } else { + regs->regs[3] = thread_saved_fp(task); + regs->csr_era = thread_saved_ra(task); ++ regs->regs[22] = task->thread.reg22; + } + regs->regs[1] = 0; +- regs->regs[22] = 0; + + for (unwind_start(&state, task, regs); + !unwind_done(&state) && !unwind_error(&state); unwind_next_frame(&state)) { +diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c +index 7b888d9085a014..dee1a15d7f4c77 100644 +--- a/arch/loongarch/kernel/vdso.c ++++ b/arch/loongarch/kernel/vdso.c +@@ -54,6 +54,9 @@ static int __init init_vdso(void) + vdso_info.code_mapping.pages = + kcalloc(vdso_info.size / PAGE_SIZE, sizeof(struct page *), GFP_KERNEL); + ++ if (!vdso_info.code_mapping.pages) ++ return -ENOMEM; ++ + pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso)); + for (i = 0; i < vdso_info.size / PAGE_SIZE; i++) + vdso_info.code_mapping.pages[i] = pfn_to_page(pfn + i); +diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c +index 0207cfe1dbd6c7..8e10393d276dc4 100644 +--- a/arch/loongarch/kvm/intc/eiointc.c ++++ b/arch/loongarch/kvm/intc/eiointc.c +@@ -810,21 +810,26 @@ static int kvm_eiointc_ctrl_access(struct kvm_device *dev, + struct loongarch_eiointc *s = dev->kvm->arch.eiointc; + + data = (void __user *)attr->addr; +- spin_lock_irqsave(&s->lock, flags); + switch (type) { + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU: ++ case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE: + if (copy_from_user(&val, data, 4)) +- ret = -EFAULT; +- else { +- if (val >= EIOINTC_ROUTE_MAX_VCPUS) +- ret = -EINVAL; +- else +- s->num_cpu = val; +- } ++ return -EFAULT; ++ break; ++ default: ++ break; ++ } ++ ++ spin_lock_irqsave(&s->lock, flags); ++ switch (type) { ++ case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU: ++ if (val >= EIOINTC_ROUTE_MAX_VCPUS) ++ ret = -EINVAL; ++ else ++ s->num_cpu = val; + break; + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE: +- if (copy_from_user(&s->features, data, 4)) +- ret = -EFAULT; ++ s->features = val; + if (!(s->features & BIT(EIOINTC_HAS_VIRT_EXTENSION))) + s->status |= BIT(EIOINTC_ENABLE); + break; +@@ -846,19 +851,17 @@ static int kvm_eiointc_ctrl_access(struct kvm_device *dev, + + static int kvm_eiointc_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, +- bool is_write) ++ bool is_write, int *data) + { + int addr, cpu, offset, ret = 0; + unsigned long flags; + void *p = NULL; +- void __user *data; + struct loongarch_eiointc *s; + + s = dev->kvm->arch.eiointc; + addr = attr->attr; + cpu = addr >> 16; + addr &= 0xffff; +- data = (void __user *)attr->addr; + switch (addr) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + offset = (addr - EIOINTC_NODETYPE_START) / 4; +@@ -897,13 +900,10 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev, + } + + spin_lock_irqsave(&s->lock, flags); +- if (is_write) { +- if (copy_from_user(p, data, 4)) +- ret = -EFAULT; +- } else { +- if (copy_to_user(data, p, 4)) +- ret = -EFAULT; +- } ++ if (is_write) ++ memcpy(p, data, 4); ++ else ++ memcpy(data, p, 4); + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +@@ -911,19 +911,17 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev, + + static int kvm_eiointc_sw_status_access(struct kvm_device *dev, + struct kvm_device_attr *attr, +- bool is_write) ++ bool is_write, int *data) + { + int addr, ret = 0; + unsigned long flags; + void *p = NULL; +- void __user *data; + struct loongarch_eiointc *s; + + s = dev->kvm->arch.eiointc; + addr = attr->attr; + addr &= 0xffff; + +- data = (void __user *)attr->addr; + switch (addr) { + case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU: + if (is_write) +@@ -945,13 +943,10 @@ static int kvm_eiointc_sw_status_access(struct kvm_device *dev, + return -EINVAL; + } + spin_lock_irqsave(&s->lock, flags); +- if (is_write) { +- if (copy_from_user(p, data, 4)) +- ret = -EFAULT; +- } else { +- if (copy_to_user(data, p, 4)) +- ret = -EFAULT; +- } ++ if (is_write) ++ memcpy(p, data, 4); ++ else ++ memcpy(data, p, 4); + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +@@ -960,11 +955,27 @@ static int kvm_eiointc_sw_status_access(struct kvm_device *dev, + static int kvm_eiointc_get_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) + { ++ int ret, data; ++ + switch (attr->group) { + case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: +- return kvm_eiointc_regs_access(dev, attr, false); ++ ret = kvm_eiointc_regs_access(dev, attr, false, &data); ++ if (ret) ++ return ret; ++ ++ if (copy_to_user((void __user *)attr->addr, &data, 4)) ++ ret = -EFAULT; ++ ++ return ret; + case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: +- return kvm_eiointc_sw_status_access(dev, attr, false); ++ ret = kvm_eiointc_sw_status_access(dev, attr, false, &data); ++ if (ret) ++ return ret; ++ ++ if (copy_to_user((void __user *)attr->addr, &data, 4)) ++ ret = -EFAULT; ++ ++ return ret; + default: + return -EINVAL; + } +@@ -973,13 +984,21 @@ static int kvm_eiointc_get_attr(struct kvm_device *dev, + static int kvm_eiointc_set_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) + { ++ int data; ++ + switch (attr->group) { + case KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL: + return kvm_eiointc_ctrl_access(dev, attr); + case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: +- return kvm_eiointc_regs_access(dev, attr, true); ++ if (copy_from_user(&data, (void __user *)attr->addr, 4)) ++ return -EFAULT; ++ ++ return kvm_eiointc_regs_access(dev, attr, true, &data); + case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: +- return kvm_eiointc_sw_status_access(dev, attr, true); ++ if (copy_from_user(&data, (void __user *)attr->addr, 4)) ++ return -EFAULT; ++ ++ return kvm_eiointc_sw_status_access(dev, attr, true, &data); + default: + return -EINVAL; + } +diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c +index ef5044796b7a6e..52f19dcf6b8814 100644 +--- a/arch/loongarch/kvm/intc/pch_pic.c ++++ b/arch/loongarch/kvm/intc/pch_pic.c +@@ -348,6 +348,7 @@ static int kvm_pch_pic_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + bool is_write) + { ++ char buf[8]; + int addr, offset, len = 8, ret = 0; + void __user *data; + void *p = NULL; +@@ -397,17 +398,23 @@ static int kvm_pch_pic_regs_access(struct kvm_device *dev, + return -EINVAL; + } + +- spin_lock(&s->lock); +- /* write or read value according to is_write */ + if (is_write) { +- if (copy_from_user(p, data, len)) +- ret = -EFAULT; +- } else { +- if (copy_to_user(data, p, len)) +- ret = -EFAULT; ++ if (copy_from_user(buf, data, len)) ++ return -EFAULT; + } ++ ++ spin_lock(&s->lock); ++ if (is_write) ++ memcpy(p, buf, len); ++ else ++ memcpy(buf, p, len); + spin_unlock(&s->lock); + ++ if (!is_write) { ++ if (copy_to_user(data, buf, len)) ++ return -EFAULT; ++ } ++ + return ret; + } + +diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c +index ed956c5cf2cc04..7c8143e79c1279 100644 +--- a/arch/loongarch/kvm/mmu.c ++++ b/arch/loongarch/kvm/mmu.c +@@ -569,7 +569,7 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ + /* Track access to pages marked old */ + new = kvm_pte_mkyoung(*ptep); + if (write && !kvm_pte_dirty(new)) { +- if (!kvm_pte_write(new)) { ++ if (!kvm_pte_writeable(new)) { + ret = -EFAULT; + goto out; + } +@@ -856,9 +856,9 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) + prot_bits |= _CACHE_SUC; + + if (writeable) { +- prot_bits |= _PAGE_WRITE; ++ prot_bits = kvm_pte_mkwriteable(prot_bits); + if (write) +- prot_bits |= __WRITEABLE; ++ prot_bits = kvm_pte_mkdirty(prot_bits); + } + + /* Disable dirty logging on HugePages */ +@@ -904,7 +904,7 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) + kvm_release_faultin_page(kvm, page, false, writeable); + spin_unlock(&kvm->mmu_lock); + +- if (prot_bits & _PAGE_DIRTY) ++ if (kvm_pte_dirty(prot_bits)) + mark_page_dirty_in_slot(kvm, memslot, gfn); + + out: +diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h +index e5f57cfe1d4582..025c6dcbf89331 100644 +--- a/arch/s390/include/asm/pci_insn.h ++++ b/arch/s390/include/asm/pci_insn.h +@@ -16,11 +16,11 @@ + #define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40 + #define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44 + +-/* Load/Store return codes */ +-#define ZPCI_PCI_LS_OK 0 +-#define ZPCI_PCI_LS_ERR 1 +-#define ZPCI_PCI_LS_BUSY 2 +-#define ZPCI_PCI_LS_INVAL_HANDLE 3 ++/* PCI instruction condition codes */ ++#define ZPCI_CC_OK 0 ++#define ZPCI_CC_ERR 1 ++#define ZPCI_CC_BUSY 2 ++#define ZPCI_CC_INVAL_HANDLE 3 + + /* Load/Store address space identifiers */ + #define ZPCI_PCIAS_MEMIO_0 0 +diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c +index ad8d78fb1d9aaf..de7867ae220d0c 100644 +--- a/arch/um/drivers/virtio_uml.c ++++ b/arch/um/drivers/virtio_uml.c +@@ -1250,10 +1250,12 @@ static int virtio_uml_probe(struct platform_device *pdev) + device_set_wakeup_capable(&vu_dev->vdev.dev, true); + + rc = register_virtio_device(&vu_dev->vdev); +- if (rc) ++ if (rc) { + put_device(&vu_dev->vdev.dev); ++ return rc; ++ } + vu_dev->registered = 1; +- return rc; ++ return 0; + + error_init: + os_close_file(vu_dev->sock); +diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c +index 617886d1fb1e91..21f0e50fb1df95 100644 +--- a/arch/um/os-Linux/file.c ++++ b/arch/um/os-Linux/file.c +@@ -535,7 +535,7 @@ ssize_t os_rcv_fd_msg(int fd, int *fds, unsigned int n_fds, + cmsg->cmsg_type != SCM_RIGHTS) + return n; + +- memcpy(fds, CMSG_DATA(cmsg), cmsg->cmsg_len); ++ memcpy(fds, CMSG_DATA(cmsg), cmsg->cmsg_len - CMSG_LEN(0)); + return n; + } + +diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h +index 14d7e0719dd5ee..8d0dfd20ac2823 100644 +--- a/arch/x86/include/asm/sev.h ++++ b/arch/x86/include/asm/sev.h +@@ -564,6 +564,24 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, + + extern struct ghcb *boot_ghcb; + ++static inline void sev_evict_cache(void *va, int npages) ++{ ++ volatile u8 val __always_unused; ++ u8 *bytes = va; ++ int page_idx; ++ ++ /* ++ * For SEV guests, a read from the first/last cache-lines of a 4K page ++ * using the guest key is sufficient to cause a flush of all cache-lines ++ * associated with that 4K page without incurring all the overhead of a ++ * full CLFLUSH sequence. ++ */ ++ for (page_idx = 0; page_idx < npages; page_idx++) { ++ val = bytes[page_idx * PAGE_SIZE]; ++ val = bytes[page_idx * PAGE_SIZE + PAGE_SIZE - 1]; ++ } ++} ++ + #else /* !CONFIG_AMD_MEM_ENCRYPT */ + + #define snp_vmpl 0 +@@ -607,6 +625,7 @@ static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_ + static inline int snp_svsm_vtpm_send_command(u8 *buffer) { return -ENODEV; } + static inline void __init snp_secure_tsc_prepare(void) { } + static inline void __init snp_secure_tsc_init(void) { } ++static inline void sev_evict_cache(void *va, int npages) {} + + #endif /* CONFIG_AMD_MEM_ENCRYPT */ + +@@ -621,24 +640,6 @@ int rmp_make_shared(u64 pfn, enum pg_level level); + void snp_leak_pages(u64 pfn, unsigned int npages); + void kdump_sev_callback(void); + void snp_fixup_e820_tables(void); +- +-static inline void sev_evict_cache(void *va, int npages) +-{ +- volatile u8 val __always_unused; +- u8 *bytes = va; +- int page_idx; +- +- /* +- * For SEV guests, a read from the first/last cache-lines of a 4K page +- * using the guest key is sufficient to cause a flush of all cache-lines +- * associated with that 4K page without incurring all the overhead of a +- * full CLFLUSH sequence. +- */ +- for (page_idx = 0; page_idx < npages; page_idx++) { +- val = bytes[page_idx * PAGE_SIZE]; +- val = bytes[page_idx * PAGE_SIZE + PAGE_SIZE - 1]; +- } +-} + #else + static inline bool snp_probe_rmptable_info(void) { return false; } + static inline int snp_rmptable_init(void) { return -ENOSYS; } +@@ -654,7 +655,6 @@ static inline int rmp_make_shared(u64 pfn, enum pg_level level) { return -ENODEV + static inline void snp_leak_pages(u64 pfn, unsigned int npages) {} + static inline void kdump_sev_callback(void) { } + static inline void snp_fixup_e820_tables(void) {} +-static inline void sev_evict_cache(void *va, int npages) {} + #endif + + #endif +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index be8c43049f4d39..268d62fa28b824 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -4204,8 +4204,7 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) + struct vcpu_svm *svm = to_svm(vcpu); + u64 cr8; + +- if (nested_svm_virtualize_tpr(vcpu) || +- kvm_vcpu_apicv_active(vcpu)) ++ if (nested_svm_virtualize_tpr(vcpu)) + return; + + cr8 = kvm_get_cr8(vcpu); +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 0da7c1ac778a0e..ca6fdcc6c54aca 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -970,6 +970,12 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, + } + + lock_sock(sk); ++ if (ctx->write) { ++ release_sock(sk); ++ return -EBUSY; ++ } ++ ctx->write = true; ++ + if (ctx->init && !ctx->more) { + if (ctx->used) { + err = -EINVAL; +@@ -1019,6 +1025,8 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, + continue; + } + ++ ctx->merge = 0; ++ + if (!af_alg_writable(sk)) { + err = af_alg_wait_for_wmem(sk, msg->msg_flags); + if (err) +@@ -1058,7 +1066,6 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, + ctx->used += plen; + copied += plen; + size -= plen; +- ctx->merge = 0; + } else { + do { + struct page *pg; +@@ -1104,6 +1111,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, + + unlock: + af_alg_data_wakeup(sk); ++ ctx->write = false; + release_sock(sk); + + return copied ?: err; +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 54c57103715f9b..0f7bcc86b6f724 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -1794,6 +1794,7 @@ static int write_same_filled_page(struct zram *zram, unsigned long fill, + u32 index) + { + zram_slot_lock(zram, index); ++ zram_free_page(zram, index); + zram_set_flag(zram, index, ZRAM_SAME); + zram_set_handle(zram, index, fill); + zram_slot_unlock(zram, index); +@@ -1831,6 +1832,7 @@ static int write_incompressible_page(struct zram *zram, struct page *page, + kunmap_local(src); + + zram_slot_lock(zram, index); ++ zram_free_page(zram, index); + zram_set_flag(zram, index, ZRAM_HUGE); + zram_set_handle(zram, index, handle); + zram_set_obj_size(zram, index, PAGE_SIZE); +@@ -1854,11 +1856,6 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) + unsigned long element; + bool same_filled; + +- /* First, free memory allocated to this slot (if any) */ +- zram_slot_lock(zram, index); +- zram_free_page(zram, index); +- zram_slot_unlock(zram, index); +- + mem = kmap_local_page(page); + same_filled = page_same_filled(mem, &element); + kunmap_local(mem); +@@ -1900,6 +1897,7 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) + zcomp_stream_put(zstrm); + + zram_slot_lock(zram, index); ++ zram_free_page(zram, index); + zram_set_handle(zram, index, handle); + zram_set_obj_size(zram, index, comp_len); + zram_slot_unlock(zram, index); +diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c +index 354c981943b6f8..4221b1888b38da 100644 +--- a/drivers/clk/sunxi-ng/ccu_mp.c ++++ b/drivers/clk/sunxi-ng/ccu_mp.c +@@ -185,7 +185,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, + p &= (1 << cmp->p.width) - 1; + + if (cmp->common.features & CCU_FEATURE_DUAL_DIV) +- rate = (parent_rate / p) / m; ++ rate = (parent_rate / (p + cmp->p.offset)) / m; + else + rate = (parent_rate >> p) / m; + +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index e058ba02779296..9f5ccc1720cbc1 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2430,7 +2430,7 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic) + { + int error; + +- __sev_platform_shutdown_locked(NULL); ++ __sev_platform_shutdown_locked(&error); + + if (sev_es_tmr) { + /* +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index c130f87147fa3f..815de752bcd384 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -173,8 +173,8 @@ static int + dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll, + struct netlink_ext_ack *extack) + { ++ DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1) = { 0 }; + const struct dpll_device_ops *ops = dpll_device_ops(dpll); +- DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) = { 0 }; + enum dpll_clock_quality_level ql; + int ret; + +@@ -183,7 +183,7 @@ dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll, + ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack); + if (ret) + return ret; +- for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) ++ for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1) + if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql)) + return -EMSGSIZE; + +diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c +index 12b24a717e43f1..d11bcaf1ae8842 100644 +--- a/drivers/gpio/gpiolib-acpi-core.c ++++ b/drivers/gpio/gpiolib-acpi-core.c +@@ -942,7 +942,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, + { + struct acpi_device *adev = to_acpi_device_node(fwnode); + bool can_fallback = acpi_can_fallback_to_crs(adev, con_id); +- struct acpi_gpio_info info; ++ struct acpi_gpio_info info = {}; + struct gpio_desc *desc; + + desc = __acpi_find_gpio(fwnode, con_id, idx, can_fallback, &info); +@@ -992,7 +992,7 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, + int ret; + + for (i = 0, idx = 0; idx <= index; i++) { +- struct acpi_gpio_info info; ++ struct acpi_gpio_info info = {}; + struct gpio_desc *desc; + + /* Ignore -EPROBE_DEFER, it only matters if idx matches */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +index fe282b85573414..31010040a12f04 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -250,16 +250,24 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev, + + void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc) + { +- if (adev->kfd.dev) +- kgd2kfd_suspend(adev->kfd.dev, suspend_proc); ++ if (adev->kfd.dev) { ++ if (adev->in_s0ix) ++ kgd2kfd_stop_sched_all_nodes(adev->kfd.dev); ++ else ++ kgd2kfd_suspend(adev->kfd.dev, suspend_proc); ++ } + } + + int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool resume_proc) + { + int r = 0; + +- if (adev->kfd.dev) +- r = kgd2kfd_resume(adev->kfd.dev, resume_proc); ++ if (adev->kfd.dev) { ++ if (adev->in_s0ix) ++ r = kgd2kfd_start_sched_all_nodes(adev->kfd.dev); ++ else ++ r = kgd2kfd_resume(adev->kfd.dev, resume_proc); ++ } + + return r; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +index b7c3ec48340721..861697490ac2e3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +@@ -426,7 +426,9 @@ void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint64_t throttle_bitmask); + int kgd2kfd_check_and_lock_kfd(void); + void kgd2kfd_unlock_kfd(void); + int kgd2kfd_start_sched(struct kfd_dev *kfd, uint32_t node_id); ++int kgd2kfd_start_sched_all_nodes(struct kfd_dev *kfd); + int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id); ++int kgd2kfd_stop_sched_all_nodes(struct kfd_dev *kfd); + bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id); + bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry, + bool retry_fault); +@@ -516,11 +518,21 @@ static inline int kgd2kfd_start_sched(struct kfd_dev *kfd, uint32_t node_id) + return 0; + } + ++static inline int kgd2kfd_start_sched_all_nodes(struct kfd_dev *kfd) ++{ ++ return 0; ++} ++ + static inline int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id) + { + return 0; + } + ++static inline int kgd2kfd_stop_sched_all_nodes(struct kfd_dev *kfd) ++{ ++ return 0; ++} ++ + static inline bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id) + { + return false; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index a57e8c5474bb00..a65591f70b15d8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -5055,7 +5055,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients) + adev->in_suspend = true; + + if (amdgpu_sriov_vf(adev)) { +- if (!adev->in_s0ix && !adev->in_runpm) ++ if (!adev->in_runpm) + amdgpu_amdkfd_suspend_process(adev); + amdgpu_virt_fini_data_exchange(adev); + r = amdgpu_virt_request_full_gpu(adev, false); +@@ -5075,10 +5075,8 @@ int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients) + + amdgpu_device_ip_suspend_phase1(adev); + +- if (!adev->in_s0ix) { +- amdgpu_amdkfd_suspend(adev, !amdgpu_sriov_vf(adev) && !adev->in_runpm); +- amdgpu_userq_suspend(adev); +- } ++ amdgpu_amdkfd_suspend(adev, !amdgpu_sriov_vf(adev) && !adev->in_runpm); ++ amdgpu_userq_suspend(adev); + + r = amdgpu_device_evict_resources(adev); + if (r) +@@ -5141,15 +5139,13 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) + goto exit; + } + +- if (!adev->in_s0ix) { +- r = amdgpu_amdkfd_resume(adev, !amdgpu_sriov_vf(adev) && !adev->in_runpm); +- if (r) +- goto exit; ++ r = amdgpu_amdkfd_resume(adev, !amdgpu_sriov_vf(adev) && !adev->in_runpm); ++ if (r) ++ goto exit; + +- r = amdgpu_userq_resume(adev); +- if (r) +- goto exit; +- } ++ r = amdgpu_userq_resume(adev); ++ if (r) ++ goto exit; + + r = amdgpu_device_ip_late_init(adev); + if (r) +@@ -5162,7 +5158,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) + amdgpu_virt_init_data_exchange(adev); + amdgpu_virt_release_full_gpu(adev, true); + +- if (!adev->in_s0ix && !r && !adev->in_runpm) ++ if (!r && !adev->in_runpm) + r = amdgpu_amdkfd_resume_process(adev); + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +index 097bf675378273..f512879cb71c65 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -1501,6 +1501,25 @@ int kgd2kfd_start_sched(struct kfd_dev *kfd, uint32_t node_id) + return ret; + } + ++int kgd2kfd_start_sched_all_nodes(struct kfd_dev *kfd) ++{ ++ struct kfd_node *node; ++ int i, r; ++ ++ if (!kfd->init_complete) ++ return 0; ++ ++ for (i = 0; i < kfd->num_nodes; i++) { ++ node = kfd->nodes[i]; ++ r = node->dqm->ops.unhalt(node->dqm); ++ if (r) { ++ dev_err(kfd_device, "Error in starting scheduler\n"); ++ return r; ++ } ++ } ++ return 0; ++} ++ + int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id) + { + struct kfd_node *node; +@@ -1518,6 +1537,23 @@ int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id) + return node->dqm->ops.halt(node->dqm); + } + ++int kgd2kfd_stop_sched_all_nodes(struct kfd_dev *kfd) ++{ ++ struct kfd_node *node; ++ int i, r; ++ ++ if (!kfd->init_complete) ++ return 0; ++ ++ for (i = 0; i < kfd->num_nodes; i++) { ++ node = kfd->nodes[i]; ++ r = node->dqm->ops.halt(node->dqm); ++ if (r) ++ return r; ++ } ++ return 0; ++} ++ + bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id) + { + struct kfd_node *node; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 312f6075e39d11..58ea351dd48b5d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -8689,7 +8689,16 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev, + static void manage_dm_interrupts(struct amdgpu_device *adev, + struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state) +-{ ++{ /* ++ * We cannot be sure that the frontend index maps to the same ++ * backend index - some even map to more than one. ++ * So we have to go through the CRTC to find the right IRQ. ++ */ ++ int irq_type = amdgpu_display_crtc_idx_to_irq_type( ++ adev, ++ acrtc->crtc_id); ++ struct drm_device *dev = adev_to_drm(adev); ++ + struct drm_vblank_crtc_config config = {0}; + struct dc_crtc_timing *timing; + int offdelay; +@@ -8742,7 +8751,35 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, + + drm_crtc_vblank_on_config(&acrtc->base, + &config); ++ /* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_get.*/ ++ switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { ++ case IP_VERSION(3, 0, 0): ++ case IP_VERSION(3, 0, 2): ++ case IP_VERSION(3, 0, 3): ++ case IP_VERSION(3, 2, 0): ++ if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n"); ++#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) ++ if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n"); ++#endif ++ } ++ + } else { ++ /* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_put.*/ ++ switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { ++ case IP_VERSION(3, 0, 0): ++ case IP_VERSION(3, 0, 2): ++ case IP_VERSION(3, 0, 3): ++ case IP_VERSION(3, 2, 0): ++#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) ++ if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n"); ++#endif ++ if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot put pageflip irq!\n"); ++ } ++ + drm_crtc_vblank_off(&acrtc->base); + } + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +index 26b8e232f85825..2278a123db23f9 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +@@ -2185,7 +2185,7 @@ static int smu_resume(struct amdgpu_ip_block *ip_block) + return ret; + } + +- if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { ++ if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL && smu->od_enabled) { + ret = smu_od_edit_dpm_table(smu, PP_OD_COMMIT_DPM_TABLE, NULL, 0); + if (ret) + return ret; +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index 8a9079c2ed5c22..8257132a8ee9d2 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -2678,7 +2678,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) + ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, + NULL, anx7625_intr_hpd_isr, + IRQF_TRIGGER_FALLING | +- IRQF_ONESHOT, ++ IRQF_ONESHOT | IRQF_NO_AUTOEN, + "anx7625-intp", platform); + if (ret) { + DRM_DEV_ERROR(dev, "fail to request irq\n"); +@@ -2747,8 +2747,10 @@ static int anx7625_i2c_probe(struct i2c_client *client) + } + + /* Add work function */ +- if (platform->pdata.intp_irq) ++ if (platform->pdata.intp_irq) { ++ enable_irq(platform->pdata.intp_irq); + queue_work(platform->workqueue, &platform->work); ++ } + + if (platform->pdata.audio_en) + anx7625_register_audio(dev, platform); +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index b431e7efd1f0d7..dbef0ca1a22a38 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -1984,8 +1984,10 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + mhdp_state = to_cdns_mhdp_bridge_state(new_state); + + mhdp_state->current_mode = drm_mode_duplicate(bridge->dev, mode); +- if (!mhdp_state->current_mode) +- return; ++ if (!mhdp_state->current_mode) { ++ ret = -EINVAL; ++ goto out; ++ } + + drm_mode_set_name(mhdp_state->current_mode); + +diff --git a/drivers/gpu/drm/xe/abi/guc_actions_abi.h b/drivers/gpu/drm/xe/abi/guc_actions_abi.h +index 448afb86e05c7d..4d9896e14649c0 100644 +--- a/drivers/gpu/drm/xe/abi/guc_actions_abi.h ++++ b/drivers/gpu/drm/xe/abi/guc_actions_abi.h +@@ -117,6 +117,7 @@ enum xe_guc_action { + XE_GUC_ACTION_ENTER_S_STATE = 0x501, + XE_GUC_ACTION_EXIT_S_STATE = 0x502, + XE_GUC_ACTION_GLOBAL_SCHED_POLICY_CHANGE = 0x506, ++ XE_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV = 0x509, + XE_GUC_ACTION_SCHED_CONTEXT = 0x1000, + XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET = 0x1001, + XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002, +@@ -142,6 +143,7 @@ enum xe_guc_action { + XE_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A, + XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER = 0x550C, + XE_GUC_ACTION_SET_FUNCTION_ENGINE_ACTIVITY_BUFFER = 0x550D, ++ XE_GUC_ACTION_OPT_IN_FEATURE_KLV = 0x550E, + XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR = 0x6000, + XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC = 0x6002, + XE_GUC_ACTION_PAGE_FAULT_RES_DESC = 0x6003, +@@ -240,4 +242,7 @@ enum xe_guc_g2g_type { + #define XE_G2G_DEREGISTER_TILE REG_GENMASK(15, 12) + #define XE_G2G_DEREGISTER_TYPE REG_GENMASK(11, 8) + ++/* invalid type for XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR */ ++#define XE_GUC_CAT_ERR_TYPE_INVALID 0xdeadbeef ++ + #endif +diff --git a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h +index 7de8f827281fcd..89034bc97ec5a4 100644 +--- a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h ++++ b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h +@@ -16,6 +16,8 @@ + * +===+=======+==============================================================+ + * | 0 | 31:16 | **KEY** - KLV key identifier | + * | | | - `GuC Self Config KLVs`_ | ++ * | | | - `GuC Opt In Feature KLVs`_ | ++ * | | | - `GuC Scheduling Policies KLVs`_ | + * | | | - `GuC VGT Policy KLVs`_ | + * | | | - `GuC VF Configuration KLVs`_ | + * | | | | +@@ -124,6 +126,44 @@ enum { + GUC_CONTEXT_POLICIES_KLV_NUM_IDS = 5, + }; + ++/** ++ * DOC: GuC Opt In Feature KLVs ++ * ++ * `GuC KLV`_ keys available for use with OPT_IN_FEATURE_KLV ++ * ++ * _`GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE` : 0x4001 ++ * Adds an extra dword to the XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR G2H ++ * containing the type of the CAT error. On HW that does not support ++ * reporting the CAT error type, the extra dword is set to 0xdeadbeef. ++ */ ++ ++#define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_KEY 0x4001 ++#define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_LEN 0u ++ ++/** ++ * DOC: GuC Scheduling Policies KLVs ++ * ++ * `GuC KLV`_ keys available for use with UPDATE_SCHEDULING_POLICIES_KLV. ++ * ++ * _`GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD` : 0x1001 ++ * Some platforms do not allow concurrent execution of RCS and CCS ++ * workloads from different address spaces. By default, the GuC prioritizes ++ * RCS submissions over CCS ones, which can lead to CCS workloads being ++ * significantly (or completely) starved of execution time. This KLV allows ++ * the driver to specify a quantum (in ms) and a ratio (percentage value ++ * between 0 and 100), and the GuC will prioritize the CCS for that ++ * percentage of each quantum. For example, specifying 100ms and 30% will ++ * make the GuC prioritize the CCS for 30ms of every 100ms. ++ * Note that this does not necessarly mean that RCS and CCS engines will ++ * only be active for their percentage of the quantum, as the restriction ++ * only kicks in if both classes are fully busy with non-compatible address ++ * spaces; i.e., if one engine is idle or running the same address space, ++ * a pending job on the other engine will still be submitted to the HW no ++ * matter what the ratio is ++ */ ++#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_KEY 0x1001 ++#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_LEN 2u ++ + /** + * DOC: GuC VGT Policy KLVs + * +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index fee22358cc09be..e5116975961461 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -151,6 +151,16 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q) + return err; + } + ++static void __xe_exec_queue_fini(struct xe_exec_queue *q) ++{ ++ int i; ++ ++ q->ops->fini(q); ++ ++ for (i = 0; i < q->width; ++i) ++ xe_lrc_put(q->lrc[i]); ++} ++ + struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm, + u32 logical_mask, u16 width, + struct xe_hw_engine *hwe, u32 flags, +@@ -181,11 +191,13 @@ struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *v + if (xe_exec_queue_uses_pxp(q)) { + err = xe_pxp_exec_queue_add(xe->pxp, q); + if (err) +- goto err_post_alloc; ++ goto err_post_init; + } + + return q; + ++err_post_init: ++ __xe_exec_queue_fini(q); + err_post_alloc: + __xe_exec_queue_free(q); + return ERR_PTR(err); +@@ -283,13 +295,11 @@ void xe_exec_queue_destroy(struct kref *ref) + xe_exec_queue_put(eq); + } + +- q->ops->fini(q); ++ q->ops->destroy(q); + } + + void xe_exec_queue_fini(struct xe_exec_queue *q) + { +- int i; +- + /* + * Before releasing our ref to lrc and xef, accumulate our run ticks + * and wakeup any waiters. +@@ -298,9 +308,7 @@ void xe_exec_queue_fini(struct xe_exec_queue *q) + if (q->xef && atomic_dec_and_test(&q->xef->exec_queue.pending_removal)) + wake_up_var(&q->xef->exec_queue.pending_removal); + +- for (i = 0; i < q->width; ++i) +- xe_lrc_put(q->lrc[i]); +- ++ __xe_exec_queue_fini(q); + __xe_exec_queue_free(q); + } + +diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h +index cc1cffb5c87f1d..1c9d03f2a3e5da 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue_types.h ++++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h +@@ -166,8 +166,14 @@ struct xe_exec_queue_ops { + int (*init)(struct xe_exec_queue *q); + /** @kill: Kill inflight submissions for backend */ + void (*kill)(struct xe_exec_queue *q); +- /** @fini: Fini exec queue for submission backend */ ++ /** @fini: Undoes the init() for submission backend */ + void (*fini)(struct xe_exec_queue *q); ++ /** ++ * @destroy: Destroy exec queue for submission backend. The backend ++ * function must call xe_exec_queue_fini() (which will in turn call the ++ * fini() backend function) to ensure the queue is properly cleaned up. ++ */ ++ void (*destroy)(struct xe_exec_queue *q); + /** @set_priority: Set priority for exec queue */ + int (*set_priority)(struct xe_exec_queue *q, + enum xe_exec_queue_priority priority); +diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c +index 788f56b066b6ad..f83d421ac9d3d2 100644 +--- a/drivers/gpu/drm/xe/xe_execlist.c ++++ b/drivers/gpu/drm/xe/xe_execlist.c +@@ -385,10 +385,20 @@ static int execlist_exec_queue_init(struct xe_exec_queue *q) + return err; + } + +-static void execlist_exec_queue_fini_async(struct work_struct *w) ++static void execlist_exec_queue_fini(struct xe_exec_queue *q) ++{ ++ struct xe_execlist_exec_queue *exl = q->execlist; ++ ++ drm_sched_entity_fini(&exl->entity); ++ drm_sched_fini(&exl->sched); ++ ++ kfree(exl); ++} ++ ++static void execlist_exec_queue_destroy_async(struct work_struct *w) + { + struct xe_execlist_exec_queue *ee = +- container_of(w, struct xe_execlist_exec_queue, fini_async); ++ container_of(w, struct xe_execlist_exec_queue, destroy_async); + struct xe_exec_queue *q = ee->q; + struct xe_execlist_exec_queue *exl = q->execlist; + struct xe_device *xe = gt_to_xe(q->gt); +@@ -401,10 +411,6 @@ static void execlist_exec_queue_fini_async(struct work_struct *w) + list_del(&exl->active_link); + spin_unlock_irqrestore(&exl->port->lock, flags); + +- drm_sched_entity_fini(&exl->entity); +- drm_sched_fini(&exl->sched); +- kfree(exl); +- + xe_exec_queue_fini(q); + } + +@@ -413,10 +419,10 @@ static void execlist_exec_queue_kill(struct xe_exec_queue *q) + /* NIY */ + } + +-static void execlist_exec_queue_fini(struct xe_exec_queue *q) ++static void execlist_exec_queue_destroy(struct xe_exec_queue *q) + { +- INIT_WORK(&q->execlist->fini_async, execlist_exec_queue_fini_async); +- queue_work(system_unbound_wq, &q->execlist->fini_async); ++ INIT_WORK(&q->execlist->destroy_async, execlist_exec_queue_destroy_async); ++ queue_work(system_unbound_wq, &q->execlist->destroy_async); + } + + static int execlist_exec_queue_set_priority(struct xe_exec_queue *q, +@@ -467,6 +473,7 @@ static const struct xe_exec_queue_ops execlist_exec_queue_ops = { + .init = execlist_exec_queue_init, + .kill = execlist_exec_queue_kill, + .fini = execlist_exec_queue_fini, ++ .destroy = execlist_exec_queue_destroy, + .set_priority = execlist_exec_queue_set_priority, + .set_timeslice = execlist_exec_queue_set_timeslice, + .set_preempt_timeout = execlist_exec_queue_set_preempt_timeout, +diff --git a/drivers/gpu/drm/xe/xe_execlist_types.h b/drivers/gpu/drm/xe/xe_execlist_types.h +index 415140936f11da..92c4ba52db0cb1 100644 +--- a/drivers/gpu/drm/xe/xe_execlist_types.h ++++ b/drivers/gpu/drm/xe/xe_execlist_types.h +@@ -42,7 +42,7 @@ struct xe_execlist_exec_queue { + + bool has_run; + +- struct work_struct fini_async; ++ struct work_struct destroy_async; + + enum xe_exec_queue_priority active_priority; + struct list_head active_link; +diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c +index e3517ce2e18c14..eaf7569a7c1d1e 100644 +--- a/drivers/gpu/drm/xe/xe_gt.c ++++ b/drivers/gpu/drm/xe/xe_gt.c +@@ -41,6 +41,7 @@ + #include "xe_gt_topology.h" + #include "xe_guc_exec_queue_types.h" + #include "xe_guc_pc.h" ++#include "xe_guc_submit.h" + #include "xe_hw_fence.h" + #include "xe_hw_engine_class_sysfs.h" + #include "xe_irq.h" +@@ -97,7 +98,7 @@ void xe_gt_sanitize(struct xe_gt *gt) + * FIXME: if xe_uc_sanitize is called here, on TGL driver will not + * reload + */ +- gt->uc.guc.submission_state.enabled = false; ++ xe_guc_submit_disable(>->uc.guc); + } + + static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) +diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +index 53a44702c04afd..c15dc600dcae7a 100644 +--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c ++++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +@@ -1600,7 +1600,6 @@ static u64 pf_estimate_fair_lmem(struct xe_gt *gt, unsigned int num_vfs) + u64 fair; + + fair = div_u64(available, num_vfs); +- fair = rounddown_pow_of_two(fair); /* XXX: ttm_vram_mgr & drm_buddy limitation */ + fair = ALIGN_DOWN(fair, alignment); + #ifdef MAX_FAIR_LMEM + fair = min_t(u64, MAX_FAIR_LMEM, fair); +diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c +index bac5471a1a7806..b9d21fdaad48ba 100644 +--- a/drivers/gpu/drm/xe/xe_guc.c ++++ b/drivers/gpu/drm/xe/xe_guc.c +@@ -29,6 +29,7 @@ + #include "xe_guc_db_mgr.h" + #include "xe_guc_engine_activity.h" + #include "xe_guc_hwconfig.h" ++#include "xe_guc_klv_helpers.h" + #include "xe_guc_log.h" + #include "xe_guc_pc.h" + #include "xe_guc_relay.h" +@@ -570,6 +571,57 @@ static int guc_g2g_start(struct xe_guc *guc) + return err; + } + ++static int __guc_opt_in_features_enable(struct xe_guc *guc, u64 addr, u32 num_dwords) ++{ ++ u32 action[] = { ++ XE_GUC_ACTION_OPT_IN_FEATURE_KLV, ++ lower_32_bits(addr), ++ upper_32_bits(addr), ++ num_dwords ++ }; ++ ++ return xe_guc_ct_send_block(&guc->ct, action, ARRAY_SIZE(action)); ++} ++ ++#define OPT_IN_MAX_DWORDS 16 ++int xe_guc_opt_in_features_enable(struct xe_guc *guc) ++{ ++ struct xe_device *xe = guc_to_xe(guc); ++ CLASS(xe_guc_buf, buf)(&guc->buf, OPT_IN_MAX_DWORDS); ++ u32 count = 0; ++ u32 *klvs; ++ int ret; ++ ++ if (!xe_guc_buf_is_valid(buf)) ++ return -ENOBUFS; ++ ++ klvs = xe_guc_buf_cpu_ptr(buf); ++ ++ /* ++ * The extra CAT error type opt-in was added in GuC v70.17.0, which maps ++ * to compatibility version v1.7.0. ++ * Note that the GuC allows enabling this KLV even on platforms that do ++ * not support the extra type; in such case the returned type variable ++ * will be set to a known invalid value which we can check against. ++ */ ++ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 7, 0)) ++ klvs[count++] = PREP_GUC_KLV_TAG(OPT_IN_FEATURE_EXT_CAT_ERR_TYPE); ++ ++ if (count) { ++ xe_assert(xe, count <= OPT_IN_MAX_DWORDS); ++ ++ ret = __guc_opt_in_features_enable(guc, xe_guc_buf_flush(buf), count); ++ if (ret < 0) { ++ xe_gt_err(guc_to_gt(guc), ++ "failed to enable GuC opt-in features: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static void guc_fini_hw(void *arg) + { + struct xe_guc *guc = arg; +@@ -763,15 +815,17 @@ int xe_guc_post_load_init(struct xe_guc *guc) + + xe_guc_ads_populate_post_load(&guc->ads); + ++ ret = xe_guc_opt_in_features_enable(guc); ++ if (ret) ++ return ret; ++ + if (xe_guc_g2g_wanted(guc_to_xe(guc))) { + ret = guc_g2g_start(guc); + if (ret) + return ret; + } + +- guc->submission_state.enabled = true; +- +- return 0; ++ return xe_guc_submit_enable(guc); + } + + int xe_guc_reset(struct xe_guc *guc) +@@ -1465,7 +1519,7 @@ void xe_guc_sanitize(struct xe_guc *guc) + { + xe_uc_fw_sanitize(&guc->fw); + xe_guc_ct_disable(&guc->ct); +- guc->submission_state.enabled = false; ++ xe_guc_submit_disable(guc); + } + + int xe_guc_reset_prepare(struct xe_guc *guc) +diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h +index 58338be4455856..4a66575f017d2d 100644 +--- a/drivers/gpu/drm/xe/xe_guc.h ++++ b/drivers/gpu/drm/xe/xe_guc.h +@@ -33,6 +33,7 @@ int xe_guc_reset(struct xe_guc *guc); + int xe_guc_upload(struct xe_guc *guc); + int xe_guc_min_load_for_hwconfig(struct xe_guc *guc); + int xe_guc_enable_communication(struct xe_guc *guc); ++int xe_guc_opt_in_features_enable(struct xe_guc *guc); + int xe_guc_suspend(struct xe_guc *guc); + void xe_guc_notify(struct xe_guc *guc); + int xe_guc_auth_huc(struct xe_guc *guc, u32 rsa_addr); +diff --git a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h +index a3f421e2adc03b..c30c0e3ccbbb93 100644 +--- a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h ++++ b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h +@@ -35,8 +35,8 @@ struct xe_guc_exec_queue { + struct xe_sched_msg static_msgs[MAX_STATIC_MSG_TYPE]; + /** @lr_tdr: long running TDR worker */ + struct work_struct lr_tdr; +- /** @fini_async: do final fini async from this worker */ +- struct work_struct fini_async; ++ /** @destroy_async: do final destroy async from this worker */ ++ struct work_struct destroy_async; + /** @resume_time: time of last resume */ + u64 resume_time; + /** @state: GuC specific state for this xe_exec_queue */ +diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c +index ef3e9e1588f7c6..18ddbb7b98a15b 100644 +--- a/drivers/gpu/drm/xe/xe_guc_submit.c ++++ b/drivers/gpu/drm/xe/xe_guc_submit.c +@@ -32,6 +32,7 @@ + #include "xe_guc_ct.h" + #include "xe_guc_exec_queue_types.h" + #include "xe_guc_id_mgr.h" ++#include "xe_guc_klv_helpers.h" + #include "xe_guc_submit_types.h" + #include "xe_hw_engine.h" + #include "xe_hw_fence.h" +@@ -316,6 +317,71 @@ int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids) + return drmm_add_action_or_reset(&xe->drm, guc_submit_fini, guc); + } + ++/* ++ * Given that we want to guarantee enough RCS throughput to avoid missing ++ * frames, we set the yield policy to 20% of each 80ms interval. ++ */ ++#define RC_YIELD_DURATION 80 /* in ms */ ++#define RC_YIELD_RATIO 20 /* in percent */ ++static u32 *emit_render_compute_yield_klv(u32 *emit) ++{ ++ *emit++ = PREP_GUC_KLV_TAG(SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD); ++ *emit++ = RC_YIELD_DURATION; ++ *emit++ = RC_YIELD_RATIO; ++ ++ return emit; ++} ++ ++#define SCHEDULING_POLICY_MAX_DWORDS 16 ++static int guc_init_global_schedule_policy(struct xe_guc *guc) ++{ ++ u32 data[SCHEDULING_POLICY_MAX_DWORDS]; ++ u32 *emit = data; ++ u32 count = 0; ++ int ret; ++ ++ if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 1, 0)) ++ return 0; ++ ++ *emit++ = XE_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV; ++ ++ if (CCS_MASK(guc_to_gt(guc))) ++ emit = emit_render_compute_yield_klv(emit); ++ ++ count = emit - data; ++ if (count > 1) { ++ xe_assert(guc_to_xe(guc), count <= SCHEDULING_POLICY_MAX_DWORDS); ++ ++ ret = xe_guc_ct_send_block(&guc->ct, data, count); ++ if (ret < 0) { ++ xe_gt_err(guc_to_gt(guc), ++ "failed to enable GuC sheduling policies: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int xe_guc_submit_enable(struct xe_guc *guc) ++{ ++ int ret; ++ ++ ret = guc_init_global_schedule_policy(guc); ++ if (ret) ++ return ret; ++ ++ guc->submission_state.enabled = true; ++ ++ return 0; ++} ++ ++void xe_guc_submit_disable(struct xe_guc *guc) ++{ ++ guc->submission_state.enabled = false; ++} ++ + static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q, u32 xa_count) + { + int i; +@@ -1269,48 +1335,57 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +-static void __guc_exec_queue_fini_async(struct work_struct *w) ++static void guc_exec_queue_fini(struct xe_exec_queue *q) ++{ ++ struct xe_guc_exec_queue *ge = q->guc; ++ struct xe_guc *guc = exec_queue_to_guc(q); ++ ++ release_guc_id(guc, q); ++ xe_sched_entity_fini(&ge->entity); ++ xe_sched_fini(&ge->sched); ++ ++ /* ++ * RCU free due sched being exported via DRM scheduler fences ++ * (timeline name). ++ */ ++ kfree_rcu(ge, rcu); ++} ++ ++static void __guc_exec_queue_destroy_async(struct work_struct *w) + { + struct xe_guc_exec_queue *ge = +- container_of(w, struct xe_guc_exec_queue, fini_async); ++ container_of(w, struct xe_guc_exec_queue, destroy_async); + struct xe_exec_queue *q = ge->q; + struct xe_guc *guc = exec_queue_to_guc(q); + + xe_pm_runtime_get(guc_to_xe(guc)); + trace_xe_exec_queue_destroy(q); + +- release_guc_id(guc, q); + if (xe_exec_queue_is_lr(q)) + cancel_work_sync(&ge->lr_tdr); + /* Confirm no work left behind accessing device structures */ + cancel_delayed_work_sync(&ge->sched.base.work_tdr); +- xe_sched_entity_fini(&ge->entity); +- xe_sched_fini(&ge->sched); + +- /* +- * RCU free due sched being exported via DRM scheduler fences +- * (timeline name). +- */ +- kfree_rcu(ge, rcu); + xe_exec_queue_fini(q); ++ + xe_pm_runtime_put(guc_to_xe(guc)); + } + +-static void guc_exec_queue_fini_async(struct xe_exec_queue *q) ++static void guc_exec_queue_destroy_async(struct xe_exec_queue *q) + { + struct xe_guc *guc = exec_queue_to_guc(q); + struct xe_device *xe = guc_to_xe(guc); + +- INIT_WORK(&q->guc->fini_async, __guc_exec_queue_fini_async); ++ INIT_WORK(&q->guc->destroy_async, __guc_exec_queue_destroy_async); + + /* We must block on kernel engines so slabs are empty on driver unload */ + if (q->flags & EXEC_QUEUE_FLAG_PERMANENT || exec_queue_wedged(q)) +- __guc_exec_queue_fini_async(&q->guc->fini_async); ++ __guc_exec_queue_destroy_async(&q->guc->destroy_async); + else +- queue_work(xe->destroy_wq, &q->guc->fini_async); ++ queue_work(xe->destroy_wq, &q->guc->destroy_async); + } + +-static void __guc_exec_queue_fini(struct xe_guc *guc, struct xe_exec_queue *q) ++static void __guc_exec_queue_destroy(struct xe_guc *guc, struct xe_exec_queue *q) + { + /* + * Might be done from within the GPU scheduler, need to do async as we +@@ -1319,7 +1394,7 @@ static void __guc_exec_queue_fini(struct xe_guc *guc, struct xe_exec_queue *q) + * this we and don't really care when everything is fini'd, just that it + * is. + */ +- guc_exec_queue_fini_async(q); ++ guc_exec_queue_destroy_async(q); + } + + static void __guc_exec_queue_process_msg_cleanup(struct xe_sched_msg *msg) +@@ -1333,7 +1408,7 @@ static void __guc_exec_queue_process_msg_cleanup(struct xe_sched_msg *msg) + if (exec_queue_registered(q)) + disable_scheduling_deregister(guc, q); + else +- __guc_exec_queue_fini(guc, q); ++ __guc_exec_queue_destroy(guc, q); + } + + static bool guc_exec_queue_allowed_to_change_state(struct xe_exec_queue *q) +@@ -1566,14 +1641,14 @@ static bool guc_exec_queue_try_add_msg(struct xe_exec_queue *q, + #define STATIC_MSG_CLEANUP 0 + #define STATIC_MSG_SUSPEND 1 + #define STATIC_MSG_RESUME 2 +-static void guc_exec_queue_fini(struct xe_exec_queue *q) ++static void guc_exec_queue_destroy(struct xe_exec_queue *q) + { + struct xe_sched_msg *msg = q->guc->static_msgs + STATIC_MSG_CLEANUP; + + if (!(q->flags & EXEC_QUEUE_FLAG_PERMANENT) && !exec_queue_wedged(q)) + guc_exec_queue_add_msg(q, msg, CLEANUP); + else +- __guc_exec_queue_fini(exec_queue_to_guc(q), q); ++ __guc_exec_queue_destroy(exec_queue_to_guc(q), q); + } + + static int guc_exec_queue_set_priority(struct xe_exec_queue *q, +@@ -1703,6 +1778,7 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = { + .init = guc_exec_queue_init, + .kill = guc_exec_queue_kill, + .fini = guc_exec_queue_fini, ++ .destroy = guc_exec_queue_destroy, + .set_priority = guc_exec_queue_set_priority, + .set_timeslice = guc_exec_queue_set_timeslice, + .set_preempt_timeout = guc_exec_queue_set_preempt_timeout, +@@ -1724,7 +1800,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) + if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q)) + xe_exec_queue_put(q); + else if (exec_queue_destroyed(q)) +- __guc_exec_queue_fini(guc, q); ++ __guc_exec_queue_destroy(guc, q); + } + if (q->guc->suspend_pending) { + set_exec_queue_suspended(q); +@@ -1981,7 +2057,7 @@ static void handle_deregister_done(struct xe_guc *guc, struct xe_exec_queue *q) + if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q)) + xe_exec_queue_put(q); + else +- __guc_exec_queue_fini(guc, q); ++ __guc_exec_queue_destroy(guc, q); + } + + int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len) +@@ -2078,12 +2154,16 @@ int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, + struct xe_gt *gt = guc_to_gt(guc); + struct xe_exec_queue *q; + u32 guc_id; ++ u32 type = XE_GUC_CAT_ERR_TYPE_INVALID; + +- if (unlikely(len < 1)) ++ if (unlikely(!len || len > 2)) + return -EPROTO; + + guc_id = msg[0]; + ++ if (len == 2) ++ type = msg[1]; ++ + if (guc_id == GUC_ID_UNKNOWN) { + /* + * GuC uses GUC_ID_UNKNOWN if it can not map the CAT fault to any PF/VF +@@ -2097,8 +2177,19 @@ int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, + if (unlikely(!q)) + return -EPROTO; + +- xe_gt_dbg(gt, "Engine memory cat error: engine_class=%s, logical_mask: 0x%x, guc_id=%d", +- xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); ++ /* ++ * The type is HW-defined and changes based on platform, so we don't ++ * decode it in the kernel and only check if it is valid. ++ * See bspec 54047 and 72187 for details. ++ */ ++ if (type != XE_GUC_CAT_ERR_TYPE_INVALID) ++ xe_gt_dbg(gt, ++ "Engine memory CAT error [%u]: class=%s, logical_mask: 0x%x, guc_id=%d", ++ type, xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); ++ else ++ xe_gt_dbg(gt, ++ "Engine memory CAT error: class=%s, logical_mask: 0x%x, guc_id=%d", ++ xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); + + trace_xe_exec_queue_memory_cat_error(q); + +diff --git a/drivers/gpu/drm/xe/xe_guc_submit.h b/drivers/gpu/drm/xe/xe_guc_submit.h +index 9b71a986c6ca69..0d126b807c1041 100644 +--- a/drivers/gpu/drm/xe/xe_guc_submit.h ++++ b/drivers/gpu/drm/xe/xe_guc_submit.h +@@ -13,6 +13,8 @@ struct xe_exec_queue; + struct xe_guc; + + int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids); ++int xe_guc_submit_enable(struct xe_guc *guc); ++void xe_guc_submit_disable(struct xe_guc *guc); + + int xe_guc_submit_reset_prepare(struct xe_guc *guc); + void xe_guc_submit_reset_wait(struct xe_guc *guc); +diff --git a/drivers/gpu/drm/xe/xe_tile_sysfs.c b/drivers/gpu/drm/xe/xe_tile_sysfs.c +index b804234a655160..9e1236a9ec6734 100644 +--- a/drivers/gpu/drm/xe/xe_tile_sysfs.c ++++ b/drivers/gpu/drm/xe/xe_tile_sysfs.c +@@ -44,16 +44,18 @@ int xe_tile_sysfs_init(struct xe_tile *tile) + kt->tile = tile; + + err = kobject_add(&kt->base, &dev->kobj, "tile%d", tile->id); +- if (err) { +- kobject_put(&kt->base); +- return err; +- } ++ if (err) ++ goto err_object; + + tile->sysfs = &kt->base; + + err = xe_vram_freq_sysfs_init(tile); + if (err) +- return err; ++ goto err_object; + + return devm_add_action_or_reset(xe->drm.dev, tile_sysfs_fini, tile); ++ ++err_object: ++ kobject_put(&kt->base); ++ return err; + } +diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c +index 3a8751a8b92dde..5c45b0f072a4c2 100644 +--- a/drivers/gpu/drm/xe/xe_uc.c ++++ b/drivers/gpu/drm/xe/xe_uc.c +@@ -165,6 +165,10 @@ static int vf_uc_init_hw(struct xe_uc *uc) + + uc->guc.submission_state.enabled = true; + ++ err = xe_guc_opt_in_features_enable(&uc->guc); ++ if (err) ++ return err; ++ + err = xe_gt_record_default_lrcs(uc_to_gt(uc)); + if (err) + return err; +diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c +index 84052b98002d14..92ce7374a79ce9 100644 +--- a/drivers/gpu/drm/xe/xe_vm.c ++++ b/drivers/gpu/drm/xe/xe_vm.c +@@ -240,8 +240,8 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) + + pfence = xe_preempt_fence_create(q, q->lr.context, + ++q->lr.seqno); +- if (!pfence) { +- err = -ENOMEM; ++ if (IS_ERR(pfence)) { ++ err = PTR_ERR(pfence); + goto out_fini; + } + +diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h +index ccbab3a4811adf..a1086b6d1f11f8 100644 +--- a/drivers/iommu/amd/amd_iommu_types.h ++++ b/drivers/iommu/amd/amd_iommu_types.h +@@ -551,6 +551,7 @@ struct gcr3_tbl_info { + }; + + struct amd_io_pgtable { ++ seqcount_t seqcount; /* Protects root/mode update */ + struct io_pgtable pgtbl; + int mode; + u64 *root; +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 7add9bcf45dc8b..eef55aa4143c1f 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -1450,12 +1450,12 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu, + PCI_FUNC(e->devid)); + + devid = e->devid; +- for (dev_i = devid_start; dev_i <= devid; ++dev_i) { +- if (alias) ++ if (alias) { ++ for (dev_i = devid_start; dev_i <= devid; ++dev_i) + pci_seg->alias_table[dev_i] = devid_to; ++ set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags); + } + set_dev_entry_from_acpi_range(iommu, devid_start, devid, flags, ext_flags); +- set_dev_entry_from_acpi(iommu, devid_to, flags, ext_flags); + break; + case IVHD_DEV_SPECIAL: { + u8 handle, type; +@@ -3048,7 +3048,8 @@ static int __init early_amd_iommu_init(void) + + if (!boot_cpu_has(X86_FEATURE_CX16)) { + pr_err("Failed to initialize. The CMPXCHG16B feature is required.\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto out; + } + + /* +diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c +index 4d308c07113495..5c6fdf38636a0c 100644 +--- a/drivers/iommu/amd/io_pgtable.c ++++ b/drivers/iommu/amd/io_pgtable.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + +@@ -130,8 +131,11 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable, + + *pte = PM_LEVEL_PDE(pgtable->mode, iommu_virt_to_phys(pgtable->root)); + ++ write_seqcount_begin(&pgtable->seqcount); + pgtable->root = pte; + pgtable->mode += 1; ++ write_seqcount_end(&pgtable->seqcount); ++ + amd_iommu_update_and_flush_device_table(domain); + + pte = NULL; +@@ -153,6 +157,7 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable, + { + unsigned long last_addr = address + (page_size - 1); + struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg; ++ unsigned int seqcount; + int level, end_lvl; + u64 *pte, *page; + +@@ -170,8 +175,14 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable, + } + + +- level = pgtable->mode - 1; +- pte = &pgtable->root[PM_LEVEL_INDEX(level, address)]; ++ do { ++ seqcount = read_seqcount_begin(&pgtable->seqcount); ++ ++ level = pgtable->mode - 1; ++ pte = &pgtable->root[PM_LEVEL_INDEX(level, address)]; ++ } while (read_seqcount_retry(&pgtable->seqcount, seqcount)); ++ ++ + address = PAGE_SIZE_ALIGN(address, page_size); + end_lvl = PAGE_SIZE_LEVEL(page_size); + +@@ -249,6 +260,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable, + unsigned long *page_size) + { + int level; ++ unsigned int seqcount; + u64 *pte; + + *page_size = 0; +@@ -256,8 +268,12 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable, + if (address > PM_LEVEL_SIZE(pgtable->mode)) + return NULL; + +- level = pgtable->mode - 1; +- pte = &pgtable->root[PM_LEVEL_INDEX(level, address)]; ++ do { ++ seqcount = read_seqcount_begin(&pgtable->seqcount); ++ level = pgtable->mode - 1; ++ pte = &pgtable->root[PM_LEVEL_INDEX(level, address)]; ++ } while (read_seqcount_retry(&pgtable->seqcount, seqcount)); ++ + *page_size = PTE_LEVEL_PAGE_SIZE(level); + + while (level > 0) { +@@ -541,6 +557,7 @@ static struct io_pgtable *v1_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo + if (!pgtable->root) + return NULL; + pgtable->mode = PAGE_MODE_3_LEVEL; ++ seqcount_init(&pgtable->seqcount); + + cfg->pgsize_bitmap = amd_iommu_pgsize_bitmap; + cfg->ias = IOMMU_IN_ADDR_BIT_SIZE; +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 34dd175a331dc7..3dd4d73fcb5dc6 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1592,6 +1592,10 @@ static void switch_to_super_page(struct dmar_domain *domain, + unsigned long lvl_pages = lvl_to_nr_pages(level); + struct dma_pte *pte = NULL; + ++ if (WARN_ON(!IS_ALIGNED(start_pfn, lvl_pages) || ++ !IS_ALIGNED(end_pfn + 1, lvl_pages))) ++ return; ++ + while (start_pfn <= end_pfn) { + if (!pte) + pte = pfn_to_dma_pte(domain, start_pfn, &level, +@@ -1667,7 +1671,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + unsigned long pages_to_remove; + + pteval |= DMA_PTE_LARGE_PAGE; +- pages_to_remove = min_t(unsigned long, nr_pages, ++ pages_to_remove = min_t(unsigned long, ++ round_down(nr_pages, lvl_pages), + nr_pte_to_next_page(pte) * lvl_pages); + end_pfn = iov_pfn + pages_to_remove - 1; + switch_to_super_page(domain, iov_pfn, end_pfn, largepage_lvl); +diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c +index 433b59f435302b..cc9ec636a7a21e 100644 +--- a/drivers/iommu/s390-iommu.c ++++ b/drivers/iommu/s390-iommu.c +@@ -611,6 +611,23 @@ static u64 get_iota_region_flag(struct s390_domain *domain) + } + } + ++static bool reg_ioat_propagate_error(int cc, u8 status) ++{ ++ /* ++ * If the device is in the error state the reset routine ++ * will register the IOAT of the newly set domain on re-enable ++ */ ++ if (cc == ZPCI_CC_ERR && status == ZPCI_PCI_ST_FUNC_NOT_AVAIL) ++ return false; ++ /* ++ * If the device was removed treat registration as success ++ * and let the subsequent error event trigger tear down. ++ */ ++ if (cc == ZPCI_CC_INVAL_HANDLE) ++ return false; ++ return cc != ZPCI_CC_OK; ++} ++ + static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev, + struct iommu_domain *domain, u8 *status) + { +@@ -695,7 +712,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, + + /* If we fail now DMA remains blocked via blocking domain */ + cc = s390_iommu_domain_reg_ioat(zdev, domain, &status); +- if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL) ++ if (reg_ioat_propagate_error(cc, status)) + return -EIO; + zdev->dma_table = s390_domain->dma_table; + zdev_s390_domain_update(zdev, domain); +@@ -1031,7 +1048,8 @@ struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev) + + lockdep_assert_held(&zdev->dom_lock); + +- if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED) ++ if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED || ++ zdev->s390_domain->type == IOMMU_DOMAIN_IDENTITY) + return NULL; + + s390_domain = to_s390_domain(zdev->s390_domain); +@@ -1122,12 +1140,7 @@ static int s390_attach_dev_identity(struct iommu_domain *domain, + + /* If we fail now DMA remains blocked via blocking domain */ + cc = s390_iommu_domain_reg_ioat(zdev, domain, &status); +- +- /* +- * If the device is undergoing error recovery the reset code +- * will re-establish the new domain. +- */ +- if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL) ++ if (reg_ioat_propagate_error(cc, status)) + return -EIO; + + zdev_s390_domain_update(zdev, domain); +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index 9835f2fe26e99f..1e09b4860a4543 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -3810,8 +3810,10 @@ static void raid_io_hints(struct dm_target *ti, struct queue_limits *limits) + struct raid_set *rs = ti->private; + unsigned int chunk_size_bytes = to_bytes(rs->md.chunk_sectors); + +- limits->io_min = chunk_size_bytes; +- limits->io_opt = chunk_size_bytes * mddev_data_stripes(rs); ++ if (chunk_size_bytes) { ++ limits->io_min = chunk_size_bytes; ++ limits->io_opt = chunk_size_bytes * mddev_data_stripes(rs); ++ } + } + + static void raid_presuspend(struct dm_target *ti) +diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c +index 5bbbdf8fc1bdef..2313dbaf642422 100644 +--- a/drivers/md/dm-stripe.c ++++ b/drivers/md/dm-stripe.c +@@ -456,11 +456,15 @@ static void stripe_io_hints(struct dm_target *ti, + struct queue_limits *limits) + { + struct stripe_c *sc = ti->private; +- unsigned int chunk_size = sc->chunk_size << SECTOR_SHIFT; ++ unsigned int io_min, io_opt; + + limits->chunk_sectors = sc->chunk_size; +- limits->io_min = chunk_size; +- limits->io_opt = chunk_size * sc->stripes; ++ ++ if (!check_shl_overflow(sc->chunk_size, SECTOR_SHIFT, &io_min) && ++ !check_mul_overflow(io_min, sc->stripes, &io_opt)) { ++ limits->io_min = io_min; ++ limits->io_opt = io_opt; ++ } + } + + static struct target_type stripe_target = { +diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c +index 101f36de7b63bd..8165fa4d0d937a 100644 +--- a/drivers/mmc/host/mvsdio.c ++++ b/drivers/mmc/host/mvsdio.c +@@ -292,7 +292,7 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data, + host->pio_ptr = NULL; + host->pio_size = 0; + } else { +- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags, ++ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + mmc_get_dma_dir(data)); + } + +diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c +index 3a1de477e9af8d..b0f91cc9e40e43 100644 +--- a/drivers/mmc/host/sdhci-pci-gli.c ++++ b/drivers/mmc/host/sdhci-pci-gli.c +@@ -283,6 +283,8 @@ + #define PCIE_GLI_9767_UHS2_CTL2_ZC_VALUE 0xb + #define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL BIT(6) + #define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL_VALUE 0x1 ++#define PCIE_GLI_9767_UHS2_CTL2_FORCE_PHY_RESETN BIT(13) ++#define PCIE_GLI_9767_UHS2_CTL2_FORCE_RESETN_VALUE BIT(14) + + #define GLI_MAX_TUNING_LOOP 40 + +@@ -1179,6 +1181,65 @@ static void gl9767_set_low_power_negotiation(struct pci_dev *pdev, bool enable) + gl9767_vhs_read(pdev); + } + ++static void sdhci_gl9767_uhs2_phy_reset(struct sdhci_host *host, bool assert) ++{ ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ struct pci_dev *pdev = slot->chip->pdev; ++ u32 value, set, clr; ++ ++ if (assert) { ++ /* Assert reset, set RESETN and clean RESETN_VALUE */ ++ set = PCIE_GLI_9767_UHS2_CTL2_FORCE_PHY_RESETN; ++ clr = PCIE_GLI_9767_UHS2_CTL2_FORCE_RESETN_VALUE; ++ } else { ++ /* De-assert reset, clean RESETN and set RESETN_VALUE */ ++ set = PCIE_GLI_9767_UHS2_CTL2_FORCE_RESETN_VALUE; ++ clr = PCIE_GLI_9767_UHS2_CTL2_FORCE_PHY_RESETN; ++ } ++ ++ gl9767_vhs_write(pdev); ++ pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, &value); ++ value |= set; ++ pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, value); ++ value &= ~clr; ++ pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, value); ++ gl9767_vhs_read(pdev); ++} ++ ++static void __gl9767_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) ++{ ++ u8 pwr = 0; ++ ++ if (mode != MMC_POWER_OFF) { ++ pwr = sdhci_get_vdd_value(vdd); ++ if (!pwr) ++ WARN(1, "%s: Invalid vdd %#x\n", ++ mmc_hostname(host->mmc), vdd); ++ pwr |= SDHCI_VDD2_POWER_180; ++ } ++ ++ if (host->pwr == pwr) ++ return; ++ ++ host->pwr = pwr; ++ ++ if (pwr == 0) { ++ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); ++ } else { ++ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); ++ ++ pwr |= SDHCI_POWER_ON; ++ sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL); ++ usleep_range(5000, 6250); ++ ++ /* Assert reset */ ++ sdhci_gl9767_uhs2_phy_reset(host, true); ++ pwr |= SDHCI_VDD2_POWER_ON; ++ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); ++ usleep_range(5000, 6250); ++ } ++} ++ + static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock) + { + struct sdhci_pci_slot *slot = sdhci_priv(host); +@@ -1205,6 +1266,11 @@ static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock) + } + + sdhci_enable_clk(host, clk); ++ ++ if (mmc_card_uhs2(host->mmc)) ++ /* De-assert reset */ ++ sdhci_gl9767_uhs2_phy_reset(host, false); ++ + gl9767_set_low_power_negotiation(pdev, true); + } + +@@ -1476,7 +1542,7 @@ static void sdhci_gl9767_set_power(struct sdhci_host *host, unsigned char mode, + gl9767_vhs_read(pdev); + + sdhci_gli_overcurrent_event_enable(host, false); +- sdhci_uhs2_set_power(host, mode, vdd); ++ __gl9767_uhs2_set_power(host, mode, vdd); + sdhci_gli_overcurrent_event_enable(host, true); + } else { + gl9767_vhs_write(pdev); +diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c +index 0efeb9d0c3765a..c459a08d01da52 100644 +--- a/drivers/mmc/host/sdhci-uhs2.c ++++ b/drivers/mmc/host/sdhci-uhs2.c +@@ -295,7 +295,8 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + else + sdhci_uhs2_set_power(host, ios->power_mode, ios->vdd); + +- sdhci_set_clock(host, host->clock); ++ host->ops->set_clock(host, ios->clock); ++ host->clock = ios->clock; + } + + static int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index e116f2db34d52b..be701eb25fec42 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -2367,23 +2367,6 @@ void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios) + (ios->power_mode == MMC_POWER_UP) && + !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) + sdhci_enable_preset_value(host, false); +- +- if (!ios->clock || ios->clock != host->clock) { +- host->ops->set_clock(host, ios->clock); +- host->clock = ios->clock; +- +- if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && +- host->clock) { +- host->timeout_clk = mmc->actual_clock ? +- mmc->actual_clock / 1000 : +- host->clock / 1000; +- mmc->max_busy_timeout = +- host->ops->get_max_timeout_count ? +- host->ops->get_max_timeout_count(host) : +- 1 << 27; +- mmc->max_busy_timeout /= host->timeout_clk; +- } +- } + } + EXPORT_SYMBOL_GPL(sdhci_set_ios_common); + +@@ -2410,6 +2393,23 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + sdhci_set_ios_common(mmc, ios); + ++ if (!ios->clock || ios->clock != host->clock) { ++ host->ops->set_clock(host, ios->clock); ++ host->clock = ios->clock; ++ ++ if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && ++ host->clock) { ++ host->timeout_clk = mmc->actual_clock ? ++ mmc->actual_clock / 1000 : ++ host->clock / 1000; ++ mmc->max_busy_timeout = ++ host->ops->get_max_timeout_count ? ++ host->ops->get_max_timeout_count(host) : ++ 1 << 27; ++ mmc->max_busy_timeout /= host->timeout_clk; ++ } ++ } ++ + if (host->ops->set_power) + host->ops->set_power(host, ios->power_mode, ios->vdd); + else +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index c4d53e8e7c152d..e23195dd747769 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -2115,6 +2115,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, + memcpy(ss.__data, bond_dev->dev_addr, bond_dev->addr_len); + } else if (bond->params.fail_over_mac == BOND_FOM_FOLLOW && + BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP && ++ bond_has_slaves(bond) && + memcmp(slave_dev->dev_addr, bond_dev->dev_addr, bond_dev->addr_len) == 0) { + /* Set slave to random address to avoid duplicate mac + * address in later fail over. +@@ -3338,7 +3339,6 @@ static void bond_ns_send_all(struct bonding *bond, struct slave *slave) + /* Find out through which dev should the packet go */ + memset(&fl6, 0, sizeof(struct flowi6)); + fl6.daddr = targets[i]; +- fl6.flowi6_oif = bond->dev->ifindex; + + dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6); + if (dst->error) { +diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c +index a9040c42d2ff97..6e97a5a7daaf9c 100644 +--- a/drivers/net/ethernet/broadcom/cnic.c ++++ b/drivers/net/ethernet/broadcom/cnic.c +@@ -4230,8 +4230,7 @@ static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) + + cnic_bnx2x_delete_wait(dev, 0); + +- cancel_delayed_work(&cp->delete_task); +- flush_workqueue(cnic_wq); ++ cancel_delayed_work_sync(&cp->delete_task); + + if (atomic_read(&cp->iscsi_conn) != 0) + netdev_warn(dev->netdev, "%d iSCSI connections not destroyed\n", +diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c +index de8a6ce86ad7e2..12105ffb5dac6d 100644 +--- a/drivers/net/ethernet/cavium/liquidio/request_manager.c ++++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c +@@ -126,7 +126,7 @@ int octeon_init_instr_queue(struct octeon_device *oct, + oct->io_qmask.iq |= BIT_ULL(iq_no); + + /* Set the 32B/64B mode for each input queue */ +- oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no); ++ oct->io_qmask.iq64B |= ((u64)(conf->instr_type == 64) << iq_no); + iq->iqcmd_64B = (conf->instr_type == 64); + + oct->fn_list.setup_iq_regs(oct, iq_no); +diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +index 4643a338061820..b1e1ad9e4b48e6 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c ++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +@@ -2736,7 +2736,7 @@ static int dpaa2_switch_setup_dpbp(struct ethsw_core *ethsw) + dev_err(dev, "dpsw_ctrl_if_set_pools() failed\n"); + goto err_get_attr; + } +- ethsw->bpid = dpbp_attrs.id; ++ ethsw->bpid = dpbp_attrs.bpid; + + return 0; + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c +index c006f716a3bdbe..ca7517a68a2c32 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c +@@ -947,9 +947,6 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, + if (!eop_desc) + break; + +- /* prevent any other reads prior to eop_desc */ +- smp_rmb(); +- + i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); + /* we have caught up to head, no work left to do */ + if (tx_head == tx_desc) +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index c50cf3ad190e9a..4766597ac55509 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -865,10 +865,6 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page, + rx_buf->page_offset, size); + sinfo->xdp_frags_size += size; +- /* remember frag count before XDP prog execution; bpf_xdp_adjust_tail() +- * can pop off frags but driver has to handle it on its own +- */ +- rx_ring->nr_frags = sinfo->nr_frags; + + if (page_is_pfmemalloc(rx_buf->page)) + xdp_buff_set_frag_pfmemalloc(xdp); +@@ -939,20 +935,20 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, + /** + * ice_get_pgcnts - grab page_count() for gathered fragments + * @rx_ring: Rx descriptor ring to store the page counts on ++ * @ntc: the next to clean element (not included in this frame!) + * + * This function is intended to be called right before running XDP + * program so that the page recycling mechanism will be able to take + * a correct decision regarding underlying pages; this is done in such + * way as XDP program can change the refcount of page + */ +-static void ice_get_pgcnts(struct ice_rx_ring *rx_ring) ++static void ice_get_pgcnts(struct ice_rx_ring *rx_ring, unsigned int ntc) + { +- u32 nr_frags = rx_ring->nr_frags + 1; + u32 idx = rx_ring->first_desc; + struct ice_rx_buf *rx_buf; + u32 cnt = rx_ring->count; + +- for (int i = 0; i < nr_frags; i++) { ++ while (idx != ntc) { + rx_buf = &rx_ring->rx_buf[idx]; + rx_buf->pgcnt = page_count(rx_buf->page); + +@@ -1125,62 +1121,51 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf) + } + + /** +- * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all frame frags ++ * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all buffers in frame + * @rx_ring: Rx ring with all the auxiliary data + * @xdp: XDP buffer carrying linear + frags part +- * @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage +- * @ntc: a current next_to_clean value to be stored at rx_ring ++ * @ntc: the next to clean element (not included in this frame!) + * @verdict: return code from XDP program execution + * +- * Walk through gathered fragments and satisfy internal page +- * recycle mechanism; we take here an action related to verdict +- * returned by XDP program; ++ * Called after XDP program is completed, or on error with verdict set to ++ * ICE_XDP_CONSUMED. ++ * ++ * Walk through buffers from first_desc to the end of the frame, releasing ++ * buffers and satisfying internal page recycle mechanism. The action depends ++ * on verdict from XDP program. + */ + static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, +- u32 *xdp_xmit, u32 ntc, u32 verdict) ++ u32 ntc, u32 verdict) + { +- u32 nr_frags = rx_ring->nr_frags + 1; + u32 idx = rx_ring->first_desc; + u32 cnt = rx_ring->count; +- u32 post_xdp_frags = 1; + struct ice_rx_buf *buf; +- int i; ++ u32 xdp_frags = 0; ++ int i = 0; + + if (unlikely(xdp_buff_has_frags(xdp))) +- post_xdp_frags += xdp_get_shared_info_from_buff(xdp)->nr_frags; ++ xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; + +- for (i = 0; i < post_xdp_frags; i++) { ++ while (idx != ntc) { + buf = &rx_ring->rx_buf[idx]; ++ if (++idx == cnt) ++ idx = 0; + +- if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) { ++ /* An XDP program could release fragments from the end of the ++ * buffer. For these, we need to keep the pagecnt_bias as-is. ++ * To do this, only adjust pagecnt_bias for fragments up to ++ * the total remaining after the XDP program has run. ++ */ ++ if (verdict != ICE_XDP_CONSUMED) + ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); +- *xdp_xmit |= verdict; +- } else if (verdict & ICE_XDP_CONSUMED) { ++ else if (i++ <= xdp_frags) + buf->pagecnt_bias++; +- } else if (verdict == ICE_XDP_PASS) { +- ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); +- } + + ice_put_rx_buf(rx_ring, buf); +- +- if (++idx == cnt) +- idx = 0; +- } +- /* handle buffers that represented frags released by XDP prog; +- * for these we keep pagecnt_bias as-is; refcount from struct page +- * has been decremented within XDP prog and we do not have to increase +- * the biased refcnt +- */ +- for (; i < nr_frags; i++) { +- buf = &rx_ring->rx_buf[idx]; +- ice_put_rx_buf(rx_ring, buf); +- if (++idx == cnt) +- idx = 0; + } + + xdp->data = NULL; + rx_ring->first_desc = ntc; +- rx_ring->nr_frags = 0; + } + + /** +@@ -1260,6 +1245,10 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + /* retrieve a buffer from the ring */ + rx_buf = ice_get_rx_buf(rx_ring, size, ntc); + ++ /* Increment ntc before calls to ice_put_rx_mbuf() */ ++ if (++ntc == cnt) ++ ntc = 0; ++ + if (!xdp->data) { + void *hard_start; + +@@ -1268,24 +1257,23 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + xdp_prepare_buff(xdp, hard_start, offset, size, !!offset); + xdp_buff_clear_frags_flag(xdp); + } else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) { +- ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc, ICE_XDP_CONSUMED); ++ ice_put_rx_mbuf(rx_ring, xdp, ntc, ICE_XDP_CONSUMED); + break; + } +- if (++ntc == cnt) +- ntc = 0; + + /* skip if it is NOP desc */ + if (ice_is_non_eop(rx_ring, rx_desc)) + continue; + +- ice_get_pgcnts(rx_ring); ++ ice_get_pgcnts(rx_ring, ntc); + xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_desc); + if (xdp_verdict == ICE_XDP_PASS) + goto construct_skb; + total_rx_bytes += xdp_get_buff_len(xdp); + total_rx_pkts++; + +- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); ++ ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); ++ xdp_xmit |= xdp_verdict & (ICE_XDP_TX | ICE_XDP_REDIR); + + continue; + construct_skb: +@@ -1298,7 +1286,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + rx_ring->ring_stats->rx_stats.alloc_buf_failed++; + xdp_verdict = ICE_XDP_CONSUMED; + } +- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); ++ ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); + + if (!skb) + break; +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h +index a4b1e95146327d..07155e615f75ab 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.h ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.h +@@ -358,7 +358,6 @@ struct ice_rx_ring { + struct ice_tx_ring *xdp_ring; + struct ice_rx_ring *next; /* pointer to next ring in q_vector */ + struct xsk_buff_pool *xsk_pool; +- u32 nr_frags; + u16 max_frame; + u16 rx_buf_len; + dma_addr_t dma; /* physical address of ring */ +diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h +index 859a15e4ccbab5..1bbe7f72757c06 100644 +--- a/drivers/net/ethernet/intel/igc/igc.h ++++ b/drivers/net/ethernet/intel/igc/igc.h +@@ -343,6 +343,7 @@ struct igc_adapter { + /* LEDs */ + struct mutex led_mutex; + struct igc_led_classdev *leds; ++ bool leds_available; + }; + + void igc_up(struct igc_adapter *adapter); +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index 1b4465d6b2b726..5b8f9b51214897 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -7301,8 +7301,14 @@ static int igc_probe(struct pci_dev *pdev, + + if (IS_ENABLED(CONFIG_IGC_LEDS)) { + err = igc_led_setup(adapter); +- if (err) +- goto err_register; ++ if (err) { ++ netdev_warn_once(netdev, ++ "LED init failed (%d); continuing without LED support\n", ++ err); ++ adapter->leds_available = false; ++ } else { ++ adapter->leds_available = true; ++ } + } + + return 0; +@@ -7358,7 +7364,7 @@ static void igc_remove(struct pci_dev *pdev) + cancel_work_sync(&adapter->watchdog_task); + hrtimer_cancel(&adapter->hrtimer); + +- if (IS_ENABLED(CONFIG_IGC_LEDS)) ++ if (IS_ENABLED(CONFIG_IGC_LEDS) && adapter->leds_available) + igc_led_free(adapter); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index cba860f0e1f154..d5c421451f3191 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -6801,6 +6801,13 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, + break; + } + ++ /* Make sure the SWFW semaphore is in a valid state */ ++ if (hw->mac.ops.init_swfw_sync) ++ hw->mac.ops.init_swfw_sync(hw); ++ ++ if (hw->mac.type == ixgbe_mac_e610) ++ mutex_init(&hw->aci.lock); ++ + #ifdef IXGBE_FCOE + /* FCoE support exists, always init the FCoE lock */ + spin_lock_init(&adapter->fcoe.lock); +@@ -11474,10 +11481,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + if (err) + goto err_sw_init; + +- /* Make sure the SWFW semaphore is in a valid state */ +- if (hw->mac.ops.init_swfw_sync) +- hw->mac.ops.init_swfw_sync(hw); +- + if (ixgbe_check_fw_error(adapter)) + return ixgbe_recovery_probe(adapter); + +@@ -11681,8 +11684,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); + ixgbe_mac_set_default_filter(adapter); + +- if (hw->mac.type == ixgbe_mac_e610) +- mutex_init(&hw->aci.lock); + timer_setup(&adapter->service_timer, ixgbe_service_timer, 0); + + if (ixgbe_removed(hw->hw_addr)) { +@@ -11838,9 +11839,9 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + devl_unlock(adapter->devlink); + ixgbe_release_hw_control(adapter); + ixgbe_clear_interrupt_scheme(adapter); ++err_sw_init: + if (hw->mac.type == ixgbe_mac_e610) + mutex_destroy(&adapter->hw.aci.lock); +-err_sw_init: + ixgbe_disable_sriov(adapter); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; + iounmap(adapter->io_addr); +@@ -11891,10 +11892,8 @@ static void ixgbe_remove(struct pci_dev *pdev) + set_bit(__IXGBE_REMOVING, &adapter->state); + cancel_work_sync(&adapter->service_task); + +- if (adapter->hw.mac.type == ixgbe_mac_e610) { ++ if (adapter->hw.mac.type == ixgbe_mac_e610) + ixgbe_disable_link_status_events(adapter); +- mutex_destroy(&adapter->hw.aci.lock); +- } + + if (adapter->mii_bus) + mdiobus_unregister(adapter->mii_bus); +@@ -11954,6 +11953,9 @@ static void ixgbe_remove(struct pci_dev *pdev) + disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); + free_netdev(netdev); + ++ if (adapter->hw.mac.type == ixgbe_mac_e610) ++ mutex_destroy(&adapter->hw.aci.lock); ++ + if (disable_dev) + pci_disable_device(pdev); + } +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +index 24499bb36c0057..bcea3fc26a8c7d 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +@@ -1124,11 +1124,24 @@ static int octep_set_features(struct net_device *dev, netdev_features_t features + return err; + } + ++static bool octep_is_vf_valid(struct octep_device *oct, int vf) ++{ ++ if (vf >= CFG_GET_ACTIVE_VFS(oct->conf)) { ++ netdev_err(oct->netdev, "Invalid VF ID %d\n", vf); ++ return false; ++ } ++ ++ return true; ++} ++ + static int octep_get_vf_config(struct net_device *dev, int vf, + struct ifla_vf_info *ivi) + { + struct octep_device *oct = netdev_priv(dev); + ++ if (!octep_is_vf_valid(oct, vf)) ++ return -EINVAL; ++ + ivi->vf = vf; + ether_addr_copy(ivi->mac, oct->vf_info[vf].mac_addr); + ivi->spoofchk = true; +@@ -1143,6 +1156,9 @@ static int octep_set_vf_mac(struct net_device *dev, int vf, u8 *mac) + struct octep_device *oct = netdev_priv(dev); + int err; + ++ if (!octep_is_vf_valid(oct, vf)) ++ return -EINVAL; ++ + if (!is_valid_ether_addr(mac)) { + dev_err(&oct->pdev->dev, "Invalid MAC Address %pM\n", mac); + return -EADDRNOTAVAIL; +diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c +index ebecdd29f3bd05..0867fab61b1905 100644 +--- a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c ++++ b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c +@@ -196,6 +196,7 @@ static void octep_pfvf_get_mac_addr(struct octep_device *oct, u32 vf_id, + vf_id); + return; + } ++ ether_addr_copy(oct->vf_info[vf_id].mac_addr, rsp->s_set_mac.mac_addr); + rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK; + } + +@@ -205,6 +206,8 @@ static void octep_pfvf_dev_remove(struct octep_device *oct, u32 vf_id, + { + int err; + ++ /* Reset VF-specific information maintained by the PF */ ++ memset(&oct->vf_info[vf_id], 0, sizeof(struct octep_pfvf_info)); + err = octep_ctrl_net_dev_remove(oct, vf_id); + if (err) { + rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK; +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c +index 63130ba37e9df1..69b435ed8fbbe9 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c +@@ -491,7 +491,7 @@ void otx2_ptp_destroy(struct otx2_nic *pfvf) + if (!ptp) + return; + +- cancel_delayed_work(&pfvf->ptp->synctstamp_work); ++ cancel_delayed_work_sync(&pfvf->ptp->synctstamp_work); + + ptp_clock_unregister(ptp->ptp_clock); + kfree(ptp); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h +index 9560fcba643f50..ac65e319148029 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h +@@ -92,6 +92,7 @@ enum { + MLX5E_ACCEL_FS_ESP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1, + MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL, + MLX5E_ACCEL_FS_POL_FT_LEVEL, ++ MLX5E_ACCEL_FS_POL_MISS_FT_LEVEL, + MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL, + #endif + }; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +index ffcd0cdeb77544..23703f28386ad9 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +@@ -185,6 +185,7 @@ struct mlx5e_ipsec_rx_create_attr { + u32 family; + int prio; + int pol_level; ++ int pol_miss_level; + int sa_level; + int status_level; + enum mlx5_flow_namespace_type chains_ns; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +index 98b6a3a623f995..65dc3529283b69 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c +@@ -747,6 +747,7 @@ static void ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec, + attr->family = family; + attr->prio = MLX5E_NIC_PRIO; + attr->pol_level = MLX5E_ACCEL_FS_POL_FT_LEVEL; ++ attr->pol_miss_level = MLX5E_ACCEL_FS_POL_MISS_FT_LEVEL; + attr->sa_level = MLX5E_ACCEL_FS_ESP_FT_LEVEL; + attr->status_level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL; + attr->chains_ns = MLX5_FLOW_NAMESPACE_KERNEL; +@@ -833,7 +834,7 @@ static int ipsec_rx_chains_create_miss(struct mlx5e_ipsec *ipsec, + + ft_attr.max_fte = 1; + ft_attr.autogroup.max_num_groups = 1; +- ft_attr.level = attr->pol_level; ++ ft_attr.level = attr->pol_miss_level; + ft_attr.prio = attr->prio; + + ft = mlx5_create_auto_grouped_flow_table(attr->ns, &ft_attr); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index e39c51cfc8e6c2..f0142d32b648f5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -136,8 +136,6 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv) + if (up) { + netdev_info(priv->netdev, "Link up\n"); + netif_carrier_on(priv->netdev); +- mlx5e_port_manual_buffer_config(priv, 0, priv->netdev->mtu, +- NULL, NULL, NULL); + } else { + netdev_info(priv->netdev, "Link down\n"); + netif_carrier_off(priv->netdev); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +index 63a7a788fb0db5..cd0242eb008c29 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +@@ -1506,12 +1506,21 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = { + static int + mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) + { +- struct mlx5e_priv *priv = netdev_priv(mlx5_uplink_netdev_get(dev)); + struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep); ++ struct net_device *netdev; ++ struct mlx5e_priv *priv; ++ int err; ++ ++ netdev = mlx5_uplink_netdev_get(dev); ++ if (!netdev) ++ return 0; + ++ priv = netdev_priv(netdev); + rpriv->netdev = priv->netdev; +- return mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile, +- rpriv); ++ err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile, ++ rpriv); ++ mlx5_uplink_netdev_put(dev, netdev); ++ return err; + } + + static void +@@ -1638,8 +1647,16 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep) + { + struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep); + struct net_device *netdev = rpriv->netdev; +- struct mlx5e_priv *priv = netdev_priv(netdev); +- void *ppriv = priv->ppriv; ++ struct mlx5e_priv *priv; ++ void *ppriv; ++ ++ if (!netdev) { ++ ppriv = rpriv; ++ goto free_ppriv; ++ } ++ ++ priv = netdev_priv(netdev); ++ ppriv = priv->ppriv; + + if (rep->vport == MLX5_VPORT_UPLINK) { + mlx5e_vport_uplink_rep_unload(rpriv); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +index ad9f6fca9b6a20..c6476e943e98d4 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +@@ -743,6 +743,7 @@ static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev) + speed = lksettings.base.speed; + + out: ++ mlx5_uplink_netdev_put(mdev, slave); + return speed; + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +index 29ce09af59aef0..3b57ef6b3de383 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +@@ -114,9 +114,9 @@ + #define ETHTOOL_NUM_PRIOS 11 + #define ETHTOOL_MIN_LEVEL (KERNEL_MIN_LEVEL + ETHTOOL_NUM_PRIOS) + /* Vlan, mac, ttc, inner ttc, {UDP/ANY/aRFS/accel/{esp, esp_err}}, IPsec policy, +- * {IPsec RoCE MPV,Alias table},IPsec RoCE policy ++ * IPsec policy miss, {IPsec RoCE MPV,Alias table},IPsec RoCE policy + */ +-#define KERNEL_NIC_PRIO_NUM_LEVELS 10 ++#define KERNEL_NIC_PRIO_NUM_LEVELS 11 + #define KERNEL_NIC_NUM_PRIOS 1 + /* One more level for tc, and one more for promisc */ + #define KERNEL_MIN_LEVEL (KERNEL_NIC_PRIO_NUM_LEVELS + 2) +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +index 37d5f445598c7b..a7486e6d0d5eff 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +@@ -52,7 +52,20 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev) + + static inline struct net_device *mlx5_uplink_netdev_get(struct mlx5_core_dev *mdev) + { +- return mdev->mlx5e_res.uplink_netdev; ++ struct mlx5e_resources *mlx5e_res = &mdev->mlx5e_res; ++ struct net_device *netdev; ++ ++ mutex_lock(&mlx5e_res->uplink_netdev_lock); ++ netdev = mlx5e_res->uplink_netdev; ++ netdev_hold(netdev, &mlx5e_res->tracker, GFP_KERNEL); ++ mutex_unlock(&mlx5e_res->uplink_netdev_lock); ++ return netdev; ++} ++ ++static inline void mlx5_uplink_netdev_put(struct mlx5_core_dev *mdev, ++ struct net_device *netdev) ++{ ++ netdev_put(netdev, &mdev->mlx5e_res.tracker); + } + + struct mlx5_sd; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c +index 2d7adf7444ba29..aa9f2b0a77d36f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c +@@ -1170,7 +1170,11 @@ const struct mlx5_link_info *mlx5_port_ptys2info(struct mlx5_core_dev *mdev, + mlx5e_port_get_link_mode_info_arr(mdev, &table, &max_size, + force_legacy); + i = find_first_bit(&temp, max_size); +- if (i < max_size) ++ ++ /* mlx5e_link_info has holes. Check speed ++ * is not zero as indication of one. ++ */ ++ if (i < max_size && table[i].speed) + return &table[i]; + + return NULL; +diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c +index 56d5464222d97a..cdbf82affa7bea 100644 +--- a/drivers/net/ethernet/natsemi/ns83820.c ++++ b/drivers/net/ethernet/natsemi/ns83820.c +@@ -820,7 +820,7 @@ static void rx_irq(struct net_device *ndev) + struct ns83820 *dev = PRIV(ndev); + struct rx_info *info = &dev->rx_info; + unsigned next_rx; +- int rx_rc, len; ++ int len; + u32 cmdsts; + __le32 *desc; + unsigned long flags; +@@ -881,8 +881,10 @@ static void rx_irq(struct net_device *ndev) + if (likely(CMDSTS_OK & cmdsts)) { + #endif + skb_put(skb, len); +- if (unlikely(!skb)) ++ if (unlikely(!skb)) { ++ ndev->stats.rx_dropped++; + goto netdev_mangle_me_harder_failed; ++ } + if (cmdsts & CMDSTS_DEST_MULTI) + ndev->stats.multicast++; + ndev->stats.rx_packets++; +@@ -901,15 +903,12 @@ static void rx_irq(struct net_device *ndev) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_IPV6), tag); + } + #endif +- rx_rc = netif_rx(skb); +- if (NET_RX_DROP == rx_rc) { +-netdev_mangle_me_harder_failed: +- ndev->stats.rx_dropped++; +- } ++ netif_rx(skb); + } else { + dev_kfree_skb_irq(skb); + } + ++netdev_mangle_me_harder_failed: + nr++; + next_rx = info->next_rx; + desc = info->descs + (DESC_SIZE * next_rx); +diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c +index 9c3d3dd2f84753..1f0cea3cae92f5 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_debug.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c +@@ -4462,10 +4462,11 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, + goto out; + } + +- /* Add override window info to buffer */ ++ /* Add override window info to buffer, preventing buffer overflow */ + override_window_dwords = +- qed_rd(p_hwfn, p_ptt, GRC_REG_NUMBER_VALID_OVERRIDE_WINDOW) * +- PROTECTION_OVERRIDE_ELEMENT_DWORDS; ++ min(qed_rd(p_hwfn, p_ptt, GRC_REG_NUMBER_VALID_OVERRIDE_WINDOW) * ++ PROTECTION_OVERRIDE_ELEMENT_DWORDS, ++ PROTECTION_OVERRIDE_DEPTH_DWORDS); + if (override_window_dwords) { + addr = BYTES_TO_DWORDS(GRC_REG_PROTECTION_OVERRIDE_WINDOW); + offset += qed_grc_dump_addr_range(p_hwfn, +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 8e6ce16ab5b88f..c9e2dca3083123 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup); + + void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid) + { +- if (test_bit(MT76_MCU_RESET, &dev->phy.state)) ++ if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta) + return; + + spin_lock_bh(&dev->sta_poll_lock); +diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c +index 131388886acbfa..cfabd5aebb5400 100644 +--- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c ++++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c +@@ -41,10 +41,10 @@ static const struct wilc_cfg_word g_cfg_word[] = { + }; + + static const struct wilc_cfg_str g_cfg_str[] = { +- {WID_FIRMWARE_VERSION, NULL}, +- {WID_MAC_ADDR, NULL}, +- {WID_ASSOC_RES_INFO, NULL}, +- {WID_NIL, NULL} ++ {WID_FIRMWARE_VERSION, 0, NULL}, ++ {WID_MAC_ADDR, 0, NULL}, ++ {WID_ASSOC_RES_INFO, 0, NULL}, ++ {WID_NIL, 0, NULL} + }; + + #define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' +@@ -147,44 +147,58 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) + + switch (FIELD_GET(WILC_WID_TYPE, wid)) { + case WID_CHAR: ++ len = 3; ++ if (len + 2 > size) ++ return; ++ + while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid) + i++; + + if (cfg->b[i].id == wid) + cfg->b[i].val = info[4]; + +- len = 3; + break; + + case WID_SHORT: ++ len = 4; ++ if (len + 2 > size) ++ return; ++ + while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid) + i++; + + if (cfg->hw[i].id == wid) + cfg->hw[i].val = get_unaligned_le16(&info[4]); + +- len = 4; + break; + + case WID_INT: ++ len = 6; ++ if (len + 2 > size) ++ return; ++ + while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid) + i++; + + if (cfg->w[i].id == wid) + cfg->w[i].val = get_unaligned_le32(&info[4]); + +- len = 6; + break; + + case WID_STR: ++ len = 2 + get_unaligned_le16(&info[2]); ++ + while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid) + i++; + +- if (cfg->s[i].id == wid) ++ if (cfg->s[i].id == wid) { ++ if (len > cfg->s[i].len || (len + 2 > size)) ++ return; ++ + memcpy(cfg->s[i].str, &info[2], +- get_unaligned_le16(&info[2]) + 2); ++ len); ++ } + +- len = 2 + get_unaligned_le16(&info[2]); + break; + + default: +@@ -384,12 +398,15 @@ int wilc_wlan_cfg_init(struct wilc *wl) + /* store the string cfg parameters */ + wl->cfg.s[i].id = WID_FIRMWARE_VERSION; + wl->cfg.s[i].str = str_vals->firmware_version; ++ wl->cfg.s[i].len = sizeof(str_vals->firmware_version); + i++; + wl->cfg.s[i].id = WID_MAC_ADDR; + wl->cfg.s[i].str = str_vals->mac_address; ++ wl->cfg.s[i].len = sizeof(str_vals->mac_address); + i++; + wl->cfg.s[i].id = WID_ASSOC_RES_INFO; + wl->cfg.s[i].str = str_vals->assoc_rsp; ++ wl->cfg.s[i].len = sizeof(str_vals->assoc_rsp); + i++; + wl->cfg.s[i].id = WID_NIL; + wl->cfg.s[i].str = NULL; +diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h +index 7038b74f8e8ff6..5ae74bced7d748 100644 +--- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h ++++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h +@@ -24,12 +24,13 @@ struct wilc_cfg_word { + + struct wilc_cfg_str { + u16 id; ++ u16 len; + u8 *str; + }; + + struct wilc_cfg_str_vals { +- u8 mac_address[7]; +- u8 firmware_version[129]; ++ u8 mac_address[8]; ++ u8 firmware_version[130]; + u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; + }; + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 895fb163d48e6a..5395623d2ba6aa 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -903,6 +903,15 @@ static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd, + u32 upper, lower; + u64 ref48; + ++ /* only type1 and type 2 PI formats have a reftag */ ++ switch (ns->head->pi_type) { ++ case NVME_NS_DPS_PI_TYPE1: ++ case NVME_NS_DPS_PI_TYPE2: ++ break; ++ default: ++ return; ++ } ++ + /* both rw and write zeroes share the same reftag format */ + switch (ns->head->guard_type) { + case NVME_NVM_NS_16B_GUARD: +@@ -942,13 +951,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns, + + if (nvme_ns_has_pi(ns->head)) { + cmnd->write_zeroes.control |= cpu_to_le16(NVME_RW_PRINFO_PRACT); +- +- switch (ns->head->pi_type) { +- case NVME_NS_DPS_PI_TYPE1: +- case NVME_NS_DPS_PI_TYPE2: +- nvme_set_ref_tag(ns, cmnd, req); +- break; +- } ++ nvme_set_ref_tag(ns, cmnd, req); + } + + return BLK_STS_OK; +@@ -1039,6 +1042,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, + if (WARN_ON_ONCE(!nvme_ns_has_pi(ns->head))) + return BLK_STS_NOTSUPP; + control |= NVME_RW_PRINFO_PRACT; ++ nvme_set_ref_tag(ns, cmnd, req); + } + + if (bio_integrity_flagged(req->bio, BIP_CHECK_GUARD)) +diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c +index 441cdf83f5a449..d6f24c7d156227 100644 +--- a/drivers/pcmcia/omap_cf.c ++++ b/drivers/pcmcia/omap_cf.c +@@ -304,7 +304,13 @@ static void __exit omap_cf_remove(struct platform_device *pdev) + kfree(cf); + } + +-static struct platform_driver omap_cf_driver = { ++/* ++ * omap_cf_remove() lives in .exit.text. For drivers registered via ++ * platform_driver_probe() this is ok because they cannot get unbound at ++ * runtime. So mark the driver struct with __refdata to prevent modpost ++ * triggering a section mismatch warning. ++ */ ++static struct platform_driver omap_cf_driver __refdata = { + .driver = { + .name = driver_name, + }, +diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c +index e6726be5890e7f..ce177c37994140 100644 +--- a/drivers/platform/x86/asus-nb-wmi.c ++++ b/drivers/platform/x86/asus-nb-wmi.c +@@ -147,7 +147,12 @@ static struct quirk_entry quirk_asus_ignore_fan = { + }; + + static struct quirk_entry quirk_asus_zenbook_duo_kbd = { +- .ignore_key_wlan = true, ++ .key_wlan_event = ASUS_WMI_KEY_IGNORE, ++}; ++ ++static struct quirk_entry quirk_asus_z13 = { ++ .key_wlan_event = ASUS_WMI_KEY_ARMOURY, ++ .tablet_switch_mode = asus_wmi_kbd_dock_devid, + }; + + static int dmi_matched(const struct dmi_system_id *dmi) +@@ -539,6 +544,15 @@ static const struct dmi_system_id asus_quirks[] = { + }, + .driver_data = &quirk_asus_zenbook_duo_kbd, + }, ++ { ++ .callback = dmi_matched, ++ .ident = "ASUS ROG Z13", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"), ++ }, ++ .driver_data = &quirk_asus_z13, ++ }, + {}, + }; + +@@ -636,6 +650,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { + { KE_IGNORE, 0xCF, }, /* AC mode */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ + { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ ++ { KE_KEY, ASUS_WMI_KEY_ARMOURY, { KEY_PROG3 } }, + { KE_END, 0}, + }; + +@@ -655,9 +670,11 @@ static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, + if (atkbd_reports_vol_keys) + *code = ASUS_WMI_KEY_IGNORE; + break; +- case 0x5F: /* Wireless console Disable */ +- if (quirks->ignore_key_wlan) +- *code = ASUS_WMI_KEY_IGNORE; ++ case 0x5D: /* Wireless console Toggle */ ++ case 0x5E: /* Wireless console Enable / Keyboard Attach, Detach */ ++ case 0x5F: /* Wireless console Disable / Special Key */ ++ if (quirks->key_wlan_event) ++ *code = quirks->key_wlan_event; + break; + } + } +diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h +index 018dfde4025e79..5cd4392b964eb8 100644 +--- a/drivers/platform/x86/asus-wmi.h ++++ b/drivers/platform/x86/asus-wmi.h +@@ -18,6 +18,7 @@ + #include + + #define ASUS_WMI_KEY_IGNORE (-1) ++#define ASUS_WMI_KEY_ARMOURY 0xffff01 + #define ASUS_WMI_BRN_DOWN 0x2e + #define ASUS_WMI_BRN_UP 0x2f + +@@ -40,7 +41,7 @@ struct quirk_entry { + bool wmi_force_als_set; + bool wmi_ignore_fan; + bool filter_i8042_e1_extended_codes; +- bool ignore_key_wlan; ++ int key_wlan_event; + enum asus_wmi_tablet_switch_mode tablet_switch_mode; + int wapf; + /* +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 93dcebbe114175..ad2d9ecf32a5ae 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1919,8 +1919,8 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; + + cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); +- if ((cache.flags & 0xff) == 0xff) +- cache.flags = -1; /* read error */ ++ if (di->chip == BQ27000 && (cache.flags & 0xff) == 0xff) ++ cache.flags = -ENODEV; /* bq27000 hdq read error */ + if (cache.flags >= 0) { + cache.capacity = bq27xxx_battery_read_soc(di); + +diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c +index 8c597fa605233a..41e4b3d4f2b581 100644 +--- a/fs/btrfs/delayed-inode.c ++++ b/fs/btrfs/delayed-inode.c +@@ -1843,7 +1843,6 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans, + + int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) + { +- struct btrfs_fs_info *fs_info = inode->root->fs_info; + struct btrfs_delayed_node *delayed_node; + struct btrfs_inode_item *inode_item; + struct inode *vfs_inode = &inode->vfs_inode; +@@ -1864,8 +1863,6 @@ int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) + i_uid_write(vfs_inode, btrfs_stack_inode_uid(inode_item)); + i_gid_write(vfs_inode, btrfs_stack_inode_gid(inode_item)); + btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item)); +- btrfs_inode_set_file_extent_range(inode, 0, +- round_up(i_size_read(vfs_inode), fs_info->sectorsize)); + vfs_inode->i_mode = btrfs_stack_inode_mode(inode_item); + set_nlink(vfs_inode, btrfs_stack_inode_nlink(inode_item)); + inode_set_bytes(vfs_inode, btrfs_stack_inode_nbytes(inode_item)); +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index e266a229484852..eb73025d4e4abb 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -3881,10 +3881,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path + bool filled = false; + int first_xattr_slot; + +- ret = btrfs_init_file_extent_tree(inode); +- if (ret) +- goto out; +- + ret = btrfs_fill_inode(inode, &rdev); + if (!ret) + filled = true; +@@ -3916,8 +3912,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path + i_uid_write(vfs_inode, btrfs_inode_uid(leaf, inode_item)); + i_gid_write(vfs_inode, btrfs_inode_gid(leaf, inode_item)); + btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item)); +- btrfs_inode_set_file_extent_range(inode, 0, +- round_up(i_size_read(vfs_inode), fs_info->sectorsize)); + + inode_set_atime(vfs_inode, btrfs_timespec_sec(leaf, &inode_item->atime), + btrfs_timespec_nsec(leaf, &inode_item->atime)); +@@ -3948,6 +3942,11 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path + btrfs_update_inode_mapping_flags(inode); + + cache_index: ++ ret = btrfs_init_file_extent_tree(inode); ++ if (ret) ++ goto out; ++ btrfs_inode_set_file_extent_range(inode, 0, ++ round_up(i_size_read(vfs_inode), fs_info->sectorsize)); + /* + * If we were modified in the current generation and evicted from memory + * and then re-read we need to do a full sync since we don't have any +diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c +index 8f4703b488b71d..b59d01b976ff1d 100644 +--- a/fs/btrfs/tree-checker.c ++++ b/fs/btrfs/tree-checker.c +@@ -1756,10 +1756,10 @@ static int check_inode_ref(struct extent_buffer *leaf, + while (ptr < end) { + u16 namelen; + +- if (unlikely(ptr + sizeof(iref) > end)) { ++ if (unlikely(ptr + sizeof(*iref) > end)) { + inode_ref_err(leaf, slot, + "inode ref overflow, ptr %lu end %lu inode_ref_size %zu", +- ptr, end, sizeof(iref)); ++ ptr, end, sizeof(*iref)); + return -EUCLEAN; + } + +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index 56d30ec0f52fca..5466a93a28f58f 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -1933,7 +1933,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, + + search_key.objectid = log_key.objectid; + search_key.type = BTRFS_INODE_EXTREF_KEY; +- search_key.offset = key->objectid; ++ search_key.offset = btrfs_extref_hash(key->objectid, name.name, name.len); + ret = backref_in_log(root->log_root, &search_key, key->objectid, &name); + if (ret < 0) { + goto out; +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index d7a1193332d941..60937127a0bc63 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -2577,9 +2577,9 @@ void btrfs_zoned_reserve_data_reloc_bg(struct btrfs_fs_info *fs_info) + spin_lock(&space_info->lock); + space_info->total_bytes -= bg->length; + space_info->disk_total -= bg->length * factor; ++ space_info->disk_total -= bg->zone_unusable; + /* There is no allocation ever happened. */ + ASSERT(bg->used == 0); +- ASSERT(bg->zone_unusable == 0); + /* No super block in a block group on the zoned setup. */ + ASSERT(bg->bytes_super == 0); + spin_unlock(&space_info->lock); +diff --git a/fs/nilfs2/sysfs.c b/fs/nilfs2/sysfs.c +index 14868a3dd592ca..bc52afbfc5c739 100644 +--- a/fs/nilfs2/sysfs.c ++++ b/fs/nilfs2/sysfs.c +@@ -1075,7 +1075,7 @@ void nilfs_sysfs_delete_device_group(struct the_nilfs *nilfs) + ************************************************************************/ + + static ssize_t nilfs_feature_revision_show(struct kobject *kobj, +- struct attribute *attr, char *buf) ++ struct kobj_attribute *attr, char *buf) + { + return sysfs_emit(buf, "%d.%d\n", + NILFS_CURRENT_REV, NILFS_MINOR_REV); +@@ -1087,7 +1087,7 @@ static const char features_readme_str[] = + "(1) revision\n\tshow current revision of NILFS file system driver.\n"; + + static ssize_t nilfs_feature_README_show(struct kobject *kobj, +- struct attribute *attr, ++ struct kobj_attribute *attr, + char *buf) + { + return sysfs_emit(buf, features_readme_str); +diff --git a/fs/nilfs2/sysfs.h b/fs/nilfs2/sysfs.h +index 78a87a016928b7..d370cd5cce3f5d 100644 +--- a/fs/nilfs2/sysfs.h ++++ b/fs/nilfs2/sysfs.h +@@ -50,16 +50,16 @@ struct nilfs_sysfs_dev_subgroups { + struct completion sg_segments_kobj_unregister; + }; + +-#define NILFS_COMMON_ATTR_STRUCT(name) \ ++#define NILFS_KOBJ_ATTR_STRUCT(name) \ + struct nilfs_##name##_attr { \ + struct attribute attr; \ +- ssize_t (*show)(struct kobject *, struct attribute *, \ ++ ssize_t (*show)(struct kobject *, struct kobj_attribute *, \ + char *); \ +- ssize_t (*store)(struct kobject *, struct attribute *, \ ++ ssize_t (*store)(struct kobject *, struct kobj_attribute *, \ + const char *, size_t); \ + } + +-NILFS_COMMON_ATTR_STRUCT(feature); ++NILFS_KOBJ_ATTR_STRUCT(feature); + + #define NILFS_DEV_ATTR_STRUCT(name) \ + struct nilfs_##name##_attr { \ +diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h +index 045227ed4efc96..0dcea9acca5442 100644 +--- a/fs/smb/client/cifsproto.h ++++ b/fs/smb/client/cifsproto.h +@@ -297,8 +297,8 @@ extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode); + + extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon); + +-extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon, +- const char *path); ++void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon, ++ struct dentry *dentry); + + extern void cifs_mark_open_handles_for_deleted_file(struct inode *inode, + const char *path); +diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c +index 11d442e8b3d622..0f0d2dae6283ad 100644 +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -1984,7 +1984,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren + } + + netfs_wait_for_outstanding_io(inode); +- cifs_close_deferred_file_under_dentry(tcon, full_path); ++ cifs_close_deferred_file_under_dentry(tcon, dentry); + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY + if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & + le64_to_cpu(tcon->fsUnixInfo.Capability))) { +@@ -2003,8 +2003,21 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren + goto psx_del_no_retry; + } + +- if (sillyrename || (server->vals->protocol_id > SMB10_PROT_ID && +- d_is_positive(dentry) && d_count(dentry) > 2)) ++ /* For SMB2+, if the file is open, we always perform a silly rename. ++ * ++ * We check for d_count() right after calling ++ * cifs_close_deferred_file_under_dentry() to make sure that the ++ * dentry's refcount gets dropped in case the file had any deferred ++ * close. ++ */ ++ if (!sillyrename && server->vals->protocol_id > SMB10_PROT_ID) { ++ spin_lock(&dentry->d_lock); ++ if (d_count(dentry) > 1) ++ sillyrename = true; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (sillyrename) + rc = -EBUSY; + else + rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry); +@@ -2538,10 +2551,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + goto cifs_rename_exit; + } + +- cifs_close_deferred_file_under_dentry(tcon, from_name); ++ cifs_close_deferred_file_under_dentry(tcon, source_dentry); + if (d_inode(target_dentry) != NULL) { + netfs_wait_for_outstanding_io(d_inode(target_dentry)); +- cifs_close_deferred_file_under_dentry(tcon, to_name); ++ cifs_close_deferred_file_under_dentry(tcon, target_dentry); + } + + rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, +diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c +index da23cc12a52caa..dda6dece802ad2 100644 +--- a/fs/smb/client/misc.c ++++ b/fs/smb/client/misc.c +@@ -832,33 +832,28 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon) + kfree(tmp_list); + } + } +-void +-cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path) ++ ++void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, ++ struct dentry *dentry) + { +- struct cifsFileInfo *cfile; + struct file_list *tmp_list, *tmp_next_list; +- void *page; +- const char *full_path; ++ struct cifsFileInfo *cfile; + LIST_HEAD(file_head); + +- page = alloc_dentry_path(); + spin_lock(&tcon->open_file_lock); + list_for_each_entry(cfile, &tcon->openFileList, tlist) { +- full_path = build_path_from_dentry(cfile->dentry, page); +- if (strstr(full_path, path)) { +- if (delayed_work_pending(&cfile->deferred)) { +- if (cancel_delayed_work(&cfile->deferred)) { +- spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); +- cifs_del_deferred_close(cfile); +- spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); +- +- tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC); +- if (tmp_list == NULL) +- break; +- tmp_list->cfile = cfile; +- list_add_tail(&tmp_list->list, &file_head); +- } +- } ++ if ((cfile->dentry == dentry) && ++ delayed_work_pending(&cfile->deferred) && ++ cancel_delayed_work(&cfile->deferred)) { ++ spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); ++ cifs_del_deferred_close(cfile); ++ spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock); ++ ++ tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC); ++ if (tmp_list == NULL) ++ break; ++ tmp_list->cfile = cfile; ++ list_add_tail(&tmp_list->list, &file_head); + } + } + spin_unlock(&tcon->open_file_lock); +@@ -868,7 +863,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path) + list_del(&tmp_list->list); + kfree(tmp_list); + } +- free_dentry_path(page); + } + + /* +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index b9bb531717a651..6dd2a1c66df3db 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -13,23 +13,23 @@ + #include "cifsproto.h" + #include "smb2proto.h" + +-static struct smbd_response *get_receive_buffer( ++static struct smbdirect_recv_io *get_receive_buffer( + struct smbd_connection *info); + static void put_receive_buffer( + struct smbd_connection *info, +- struct smbd_response *response); ++ struct smbdirect_recv_io *response); + static int allocate_receive_buffers(struct smbd_connection *info, int num_buf); + static void destroy_receive_buffers(struct smbd_connection *info); + + static void enqueue_reassembly( + struct smbd_connection *info, +- struct smbd_response *response, int data_length); +-static struct smbd_response *_get_first_reassembly( ++ struct smbdirect_recv_io *response, int data_length); ++static struct smbdirect_recv_io *_get_first_reassembly( + struct smbd_connection *info); + + static int smbd_post_recv( + struct smbd_connection *info, +- struct smbd_response *response); ++ struct smbdirect_recv_io *response); + + static int smbd_post_send_empty(struct smbd_connection *info); + +@@ -260,7 +260,7 @@ static inline void *smbd_request_payload(struct smbd_request *request) + return (void *)request->packet; + } + +-static inline void *smbd_response_payload(struct smbd_response *response) ++static inline void *smbdirect_recv_io_payload(struct smbdirect_recv_io *response) + { + return (void *)response->packet; + } +@@ -315,12 +315,13 @@ static void dump_smbdirect_negotiate_resp(struct smbdirect_negotiate_resp *resp) + * return value: true if negotiation is a success, false if failed + */ + static bool process_negotiation_response( +- struct smbd_response *response, int packet_length) ++ struct smbdirect_recv_io *response, int packet_length) + { +- struct smbd_connection *info = response->info; +- struct smbdirect_socket *sc = &info->socket; ++ struct smbdirect_socket *sc = response->socket; ++ struct smbd_connection *info = ++ container_of(sc, struct smbd_connection, socket); + struct smbdirect_socket_parameters *sp = &sc->parameters; +- struct smbdirect_negotiate_resp *packet = smbd_response_payload(response); ++ struct smbdirect_negotiate_resp *packet = smbdirect_recv_io_payload(response); + + if (packet_length < sizeof(struct smbdirect_negotiate_resp)) { + log_rdma_event(ERR, +@@ -383,6 +384,7 @@ static bool process_negotiation_response( + info->max_frmr_depth * PAGE_SIZE); + info->max_frmr_depth = sp->max_read_write_size / PAGE_SIZE; + ++ sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER; + return true; + } + +@@ -390,7 +392,7 @@ static void smbd_post_send_credits(struct work_struct *work) + { + int ret = 0; + int rc; +- struct smbd_response *response; ++ struct smbdirect_recv_io *response; + struct smbd_connection *info = + container_of(work, struct smbd_connection, + post_send_credits_work); +@@ -408,7 +410,6 @@ static void smbd_post_send_credits(struct work_struct *work) + if (!response) + break; + +- response->type = SMBD_TRANSFER_DATA; + response->first_segment = false; + rc = smbd_post_recv(info, response); + if (rc) { +@@ -442,13 +443,18 @@ static void smbd_post_send_credits(struct work_struct *work) + static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + { + struct smbdirect_data_transfer *data_transfer; +- struct smbd_response *response = +- container_of(wc->wr_cqe, struct smbd_response, cqe); +- struct smbd_connection *info = response->info; +- int data_length = 0; ++ struct smbdirect_recv_io *response = ++ container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe); ++ struct smbdirect_socket *sc = response->socket; ++ struct smbdirect_socket_parameters *sp = &sc->parameters; ++ struct smbd_connection *info = ++ container_of(sc, struct smbd_connection, socket); ++ u32 data_offset = 0; ++ u32 data_length = 0; ++ u32 remaining_data_length = 0; + + log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n", +- response, response->type, wc->status, wc->opcode, ++ response, sc->recv_io.expected, wc->status, wc->opcode, + wc->byte_len, wc->pkey_index); + + if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { +@@ -463,10 +469,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + response->sge.length, + DMA_FROM_DEVICE); + +- switch (response->type) { ++ switch (sc->recv_io.expected) { + /* SMBD negotiation response */ +- case SMBD_NEGOTIATE_RESP: +- dump_smbdirect_negotiate_resp(smbd_response_payload(response)); ++ case SMBDIRECT_EXPECT_NEGOTIATE_REP: ++ dump_smbdirect_negotiate_resp(smbdirect_recv_io_payload(response)); + info->full_packet_received = true; + info->negotiate_done = + process_negotiation_response(response, wc->byte_len); +@@ -475,9 +481,24 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + return; + + /* SMBD data transfer packet */ +- case SMBD_TRANSFER_DATA: +- data_transfer = smbd_response_payload(response); ++ case SMBDIRECT_EXPECT_DATA_TRANSFER: ++ data_transfer = smbdirect_recv_io_payload(response); ++ ++ if (wc->byte_len < ++ offsetof(struct smbdirect_data_transfer, padding)) ++ goto error; ++ ++ remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length); ++ data_offset = le32_to_cpu(data_transfer->data_offset); + data_length = le32_to_cpu(data_transfer->data_length); ++ if (wc->byte_len < data_offset || ++ (u64)wc->byte_len < (u64)data_offset + data_length) ++ goto error; ++ ++ if (remaining_data_length > sp->max_fragmented_recv_size || ++ data_length > sp->max_fragmented_recv_size || ++ (u64)remaining_data_length + (u64)data_length > (u64)sp->max_fragmented_recv_size) ++ goto error; + + if (data_length) { + if (info->full_packet_received) +@@ -526,13 +547,17 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + put_receive_buffer(info, response); + + return; ++ ++ case SMBDIRECT_EXPECT_NEGOTIATE_REQ: ++ /* Only server... */ ++ break; + } + + /* + * This is an internal error! + */ +- log_rdma_recv(ERR, "unexpected response type=%d\n", response->type); +- WARN_ON_ONCE(response->type != SMBD_TRANSFER_DATA); ++ log_rdma_recv(ERR, "unexpected response type=%d\n", sc->recv_io.expected); ++ WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); + error: + put_receive_buffer(info, response); + smbd_disconnect_rdma_connection(info); +@@ -1029,7 +1054,7 @@ static int smbd_post_send_full_iter(struct smbd_connection *info, + * The interaction is controlled by send/receive credit system + */ + static int smbd_post_recv( +- struct smbd_connection *info, struct smbd_response *response) ++ struct smbd_connection *info, struct smbdirect_recv_io *response) + { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; +@@ -1067,16 +1092,19 @@ static int smbd_post_recv( + /* Perform SMBD negotiate according to [MS-SMBD] 3.1.5.2 */ + static int smbd_negotiate(struct smbd_connection *info) + { ++ struct smbdirect_socket *sc = &info->socket; + int rc; +- struct smbd_response *response = get_receive_buffer(info); ++ struct smbdirect_recv_io *response = get_receive_buffer(info); + +- response->type = SMBD_NEGOTIATE_RESP; ++ sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REP; + rc = smbd_post_recv(info, response); + log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=0x%llx iov.length=%u iov.lkey=0x%x\n", + rc, response->sge.addr, + response->sge.length, response->sge.lkey); +- if (rc) ++ if (rc) { ++ put_receive_buffer(info, response); + return rc; ++ } + + init_completion(&info->negotiate_completion); + info->negotiate_done = false; +@@ -1113,7 +1141,7 @@ static int smbd_negotiate(struct smbd_connection *info) + */ + static void enqueue_reassembly( + struct smbd_connection *info, +- struct smbd_response *response, ++ struct smbdirect_recv_io *response, + int data_length) + { + spin_lock(&info->reassembly_queue_lock); +@@ -1137,14 +1165,14 @@ static void enqueue_reassembly( + * Caller is responsible for locking + * return value: the first entry if any, NULL if queue is empty + */ +-static struct smbd_response *_get_first_reassembly(struct smbd_connection *info) ++static struct smbdirect_recv_io *_get_first_reassembly(struct smbd_connection *info) + { +- struct smbd_response *ret = NULL; ++ struct smbdirect_recv_io *ret = NULL; + + if (!list_empty(&info->reassembly_queue)) { + ret = list_first_entry( + &info->reassembly_queue, +- struct smbd_response, list); ++ struct smbdirect_recv_io, list); + } + return ret; + } +@@ -1155,16 +1183,16 @@ static struct smbd_response *_get_first_reassembly(struct smbd_connection *info) + * pre-allocated in advance. + * return value: the receive buffer, NULL if none is available + */ +-static struct smbd_response *get_receive_buffer(struct smbd_connection *info) ++static struct smbdirect_recv_io *get_receive_buffer(struct smbd_connection *info) + { +- struct smbd_response *ret = NULL; ++ struct smbdirect_recv_io *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&info->receive_queue_lock, flags); + if (!list_empty(&info->receive_queue)) { + ret = list_first_entry( + &info->receive_queue, +- struct smbd_response, list); ++ struct smbdirect_recv_io, list); + list_del(&ret->list); + info->count_receive_queue--; + info->count_get_receive_buffer++; +@@ -1181,7 +1209,7 @@ static struct smbd_response *get_receive_buffer(struct smbd_connection *info) + * receive buffer is returned. + */ + static void put_receive_buffer( +- struct smbd_connection *info, struct smbd_response *response) ++ struct smbd_connection *info, struct smbdirect_recv_io *response) + { + struct smbdirect_socket *sc = &info->socket; + unsigned long flags; +@@ -1206,8 +1234,9 @@ static void put_receive_buffer( + /* Preallocate all receive buffer on transport establishment */ + static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) + { ++ struct smbdirect_socket *sc = &info->socket; ++ struct smbdirect_recv_io *response; + int i; +- struct smbd_response *response; + + INIT_LIST_HEAD(&info->reassembly_queue); + spin_lock_init(&info->reassembly_queue_lock); +@@ -1225,7 +1254,7 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) + if (!response) + goto allocate_failed; + +- response->info = info; ++ response->socket = sc; + response->sge.length = 0; + list_add_tail(&response->list, &info->receive_queue); + info->count_receive_queue++; +@@ -1237,7 +1266,7 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) + while (!list_empty(&info->receive_queue)) { + response = list_first_entry( + &info->receive_queue, +- struct smbd_response, list); ++ struct smbdirect_recv_io, list); + list_del(&response->list); + info->count_receive_queue--; + +@@ -1248,7 +1277,7 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) + + static void destroy_receive_buffers(struct smbd_connection *info) + { +- struct smbd_response *response; ++ struct smbdirect_recv_io *response; + + while ((response = get_receive_buffer(info))) + mempool_free(response, info->response_mempool); +@@ -1289,7 +1318,7 @@ void smbd_destroy(struct TCP_Server_Info *server) + struct smbd_connection *info = server->smbd_conn; + struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; +- struct smbd_response *response; ++ struct smbdirect_recv_io *response; + unsigned long flags; + + if (!info) { +@@ -1308,13 +1337,16 @@ void smbd_destroy(struct TCP_Server_Info *server) + sc->status == SMBDIRECT_SOCKET_DISCONNECTED); + } + ++ log_rdma_event(INFO, "cancelling post_send_credits_work\n"); ++ disable_work_sync(&info->post_send_credits_work); ++ + log_rdma_event(INFO, "destroying qp\n"); + ib_drain_qp(sc->ib.qp); + rdma_destroy_qp(sc->rdma.cm_id); + sc->ib.qp = NULL; + + log_rdma_event(INFO, "cancelling idle timer\n"); +- cancel_delayed_work_sync(&info->idle_timer_work); ++ disable_delayed_work_sync(&info->idle_timer_work); + + /* It's not possible for upper layer to get to reassembly */ + log_rdma_event(INFO, "drain the reassembly queue\n"); +@@ -1446,17 +1478,17 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) + if (!info->request_mempool) + goto out1; + +- scnprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); ++ scnprintf(name, MAX_NAME_LEN, "smbdirect_recv_io_%p", info); + + struct kmem_cache_args response_args = { +- .align = __alignof__(struct smbd_response), +- .useroffset = (offsetof(struct smbd_response, packet) + ++ .align = __alignof__(struct smbdirect_recv_io), ++ .useroffset = (offsetof(struct smbdirect_recv_io, packet) + + sizeof(struct smbdirect_data_transfer)), + .usersize = sp->max_recv_size - sizeof(struct smbdirect_data_transfer), + }; + info->response_cache = + kmem_cache_create(name, +- sizeof(struct smbd_response) + sp->max_recv_size, ++ sizeof(struct smbdirect_recv_io) + sp->max_recv_size, + &response_args, SLAB_HWCACHE_ALIGN); + if (!info->response_cache) + goto out2; +@@ -1686,7 +1718,7 @@ static struct smbd_connection *_smbd_get_connection( + return NULL; + + negotiation_failed: +- cancel_delayed_work_sync(&info->idle_timer_work); ++ disable_delayed_work_sync(&info->idle_timer_work); + destroy_caches_and_workqueue(info); + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; + rdma_disconnect(sc->rdma.cm_id); +@@ -1747,7 +1779,7 @@ struct smbd_connection *smbd_get_connection( + int smbd_recv(struct smbd_connection *info, struct msghdr *msg) + { + struct smbdirect_socket *sc = &info->socket; +- struct smbd_response *response; ++ struct smbdirect_recv_io *response; + struct smbdirect_data_transfer *data_transfer; + size_t size = iov_iter_count(&msg->msg_iter); + int to_copy, to_read, data_read, offset; +@@ -1783,7 +1815,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) + offset = info->first_entry_offset; + while (data_read < size) { + response = _get_first_reassembly(info); +- data_transfer = smbd_response_payload(response); ++ data_transfer = smbdirect_recv_io_payload(response); + data_length = le32_to_cpu(data_transfer->data_length); + remaining_data_length = + le32_to_cpu( +@@ -2045,7 +2077,7 @@ static void destroy_mr_list(struct smbd_connection *info) + struct smbdirect_socket *sc = &info->socket; + struct smbd_mr *mr, *tmp; + +- cancel_work_sync(&info->mr_recovery_work); ++ disable_work_sync(&info->mr_recovery_work); + list_for_each_entry_safe(mr, tmp, &info->mr_list, list) { + if (mr->state == MR_INVALIDATED) + ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, +diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h +index ea04ce8a9763a6..d60e445da22563 100644 +--- a/fs/smb/client/smbdirect.h ++++ b/fs/smb/client/smbdirect.h +@@ -157,11 +157,6 @@ struct smbd_connection { + unsigned int count_send_empty; + }; + +-enum smbd_message_type { +- SMBD_NEGOTIATE_RESP, +- SMBD_TRANSFER_DATA, +-}; +- + /* Maximum number of SGEs used by smbdirect.c in any send work request */ + #define SMBDIRECT_MAX_SEND_SGE 6 + +@@ -181,24 +176,6 @@ struct smbd_request { + /* Maximum number of SGEs used by smbdirect.c in any receive work request */ + #define SMBDIRECT_MAX_RECV_SGE 1 + +-/* The context for a SMBD response */ +-struct smbd_response { +- struct smbd_connection *info; +- struct ib_cqe cqe; +- struct ib_sge sge; +- +- enum smbd_message_type type; +- +- /* Link to receive queue or reassembly queue */ +- struct list_head list; +- +- /* Indicate if this is the 1st packet of a payload */ +- bool first_segment; +- +- /* SMBD packet header and payload follows this structure */ +- u8 packet[]; +-}; +- + /* Create a SMBDirect session */ + struct smbd_connection *smbd_get_connection( + struct TCP_Server_Info *server, struct sockaddr *dstaddr); +diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h +index e5b15cc44a7ba5..a7ad31c471a7b6 100644 +--- a/fs/smb/common/smbdirect/smbdirect_socket.h ++++ b/fs/smb/common/smbdirect/smbdirect_socket.h +@@ -38,6 +38,35 @@ struct smbdirect_socket { + } ib; + + struct smbdirect_socket_parameters parameters; ++ ++ /* ++ * The state for posted receive buffers ++ */ ++ struct { ++ /* ++ * The type of PDU we are expecting ++ */ ++ enum { ++ SMBDIRECT_EXPECT_NEGOTIATE_REQ = 1, ++ SMBDIRECT_EXPECT_NEGOTIATE_REP = 2, ++ SMBDIRECT_EXPECT_DATA_TRANSFER = 3, ++ } expected; ++ } recv_io; ++}; ++ ++struct smbdirect_recv_io { ++ struct smbdirect_socket *socket; ++ struct ib_cqe cqe; ++ struct ib_sge sge; ++ ++ /* Link to free or reassembly list */ ++ struct list_head list; ++ ++ /* Indicate if this is the 1st packet of a payload */ ++ bool first_segment; ++ ++ /* SMBD packet header and payload follows this structure */ ++ u8 packet[]; + }; + + #endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ */ +diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c +index 5466aa8c39b1cd..6550bd9f002c27 100644 +--- a/fs/smb/server/transport_rdma.c ++++ b/fs/smb/server/transport_rdma.c +@@ -554,7 +554,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + case SMB_DIRECT_MSG_DATA_TRANSFER: { + struct smb_direct_data_transfer *data_transfer = + (struct smb_direct_data_transfer *)recvmsg->packet; +- unsigned int data_length; ++ u32 remaining_data_length, data_offset, data_length; + int avail_recvmsg_count, receive_credits; + + if (wc->byte_len < +@@ -564,15 +564,25 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) + return; + } + ++ remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length); + data_length = le32_to_cpu(data_transfer->data_length); +- if (data_length) { +- if (wc->byte_len < sizeof(struct smb_direct_data_transfer) + +- (u64)data_length) { +- put_recvmsg(t, recvmsg); +- smb_direct_disconnect_rdma_connection(t); +- return; +- } ++ data_offset = le32_to_cpu(data_transfer->data_offset); ++ if (wc->byte_len < data_offset || ++ wc->byte_len < (u64)data_offset + data_length) { ++ put_recvmsg(t, recvmsg); ++ smb_direct_disconnect_rdma_connection(t); ++ return; ++ } ++ if (remaining_data_length > t->max_fragmented_recv_size || ++ data_length > t->max_fragmented_recv_size || ++ (u64)remaining_data_length + (u64)data_length > ++ (u64)t->max_fragmented_recv_size) { ++ put_recvmsg(t, recvmsg); ++ smb_direct_disconnect_rdma_connection(t); ++ return; ++ } + ++ if (data_length) { + if (t->full_packet_received) + recvmsg->first_segment = true; + +@@ -1209,78 +1219,130 @@ static int smb_direct_writev(struct ksmbd_transport *t, + bool need_invalidate, unsigned int remote_key) + { + struct smb_direct_transport *st = smb_trans_direct_transfort(t); +- int remaining_data_length; +- int start, i, j; +- int max_iov_size = st->max_send_size - ++ size_t remaining_data_length; ++ size_t iov_idx; ++ size_t iov_ofs; ++ size_t max_iov_size = st->max_send_size - + sizeof(struct smb_direct_data_transfer); + int ret; +- struct kvec vec; + struct smb_direct_send_ctx send_ctx; ++ int error = 0; + + if (st->status != SMB_DIRECT_CS_CONNECTED) + return -ENOTCONN; + + //FIXME: skip RFC1002 header.. ++ if (WARN_ON_ONCE(niovs <= 1 || iov[0].iov_len != 4)) ++ return -EINVAL; + buflen -= 4; ++ iov_idx = 1; ++ iov_ofs = 0; + + remaining_data_length = buflen; + ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); + + smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); +- start = i = 1; +- buflen = 0; +- while (true) { +- buflen += iov[i].iov_len; +- if (buflen > max_iov_size) { +- if (i > start) { +- remaining_data_length -= +- (buflen - iov[i].iov_len); +- ret = smb_direct_post_send_data(st, &send_ctx, +- &iov[start], i - start, +- remaining_data_length); +- if (ret) ++ while (remaining_data_length) { ++ struct kvec vecs[SMB_DIRECT_MAX_SEND_SGES - 1]; /* minus smbdirect hdr */ ++ size_t possible_bytes = max_iov_size; ++ size_t possible_vecs; ++ size_t bytes = 0; ++ size_t nvecs = 0; ++ ++ /* ++ * For the last message remaining_data_length should be ++ * have been 0 already! ++ */ ++ if (WARN_ON_ONCE(iov_idx >= niovs)) { ++ error = -EINVAL; ++ goto done; ++ } ++ ++ /* ++ * We have 2 factors which limit the arguments we pass ++ * to smb_direct_post_send_data(): ++ * ++ * 1. The number of supported sges for the send, ++ * while one is reserved for the smbdirect header. ++ * And we currently need one SGE per page. ++ * 2. The number of negotiated payload bytes per send. ++ */ ++ possible_vecs = min_t(size_t, ARRAY_SIZE(vecs), niovs - iov_idx); ++ ++ while (iov_idx < niovs && possible_vecs && possible_bytes) { ++ struct kvec *v = &vecs[nvecs]; ++ int page_count; ++ ++ v->iov_base = ((u8 *)iov[iov_idx].iov_base) + iov_ofs; ++ v->iov_len = min_t(size_t, ++ iov[iov_idx].iov_len - iov_ofs, ++ possible_bytes); ++ page_count = get_buf_page_count(v->iov_base, v->iov_len); ++ if (page_count > possible_vecs) { ++ /* ++ * If the number of pages in the buffer ++ * is to much (because we currently require ++ * one SGE per page), we need to limit the ++ * length. ++ * ++ * We know possible_vecs is at least 1, ++ * so we always keep the first page. ++ * ++ * We need to calculate the number extra ++ * pages (epages) we can also keep. ++ * ++ * We calculate the number of bytes in the ++ * first page (fplen), this should never be ++ * larger than v->iov_len because page_count is ++ * at least 2, but adding a limitation feels ++ * better. ++ * ++ * Then we calculate the number of bytes (elen) ++ * we can keep for the extra pages. ++ */ ++ size_t epages = possible_vecs - 1; ++ size_t fpofs = offset_in_page(v->iov_base); ++ size_t fplen = min_t(size_t, PAGE_SIZE - fpofs, v->iov_len); ++ size_t elen = min_t(size_t, v->iov_len - fplen, epages*PAGE_SIZE); ++ ++ v->iov_len = fplen + elen; ++ page_count = get_buf_page_count(v->iov_base, v->iov_len); ++ if (WARN_ON_ONCE(page_count > possible_vecs)) { ++ /* ++ * Something went wrong in the above ++ * logic... ++ */ ++ error = -EINVAL; + goto done; +- } else { +- /* iov[start] is too big, break it */ +- int nvec = (buflen + max_iov_size - 1) / +- max_iov_size; +- +- for (j = 0; j < nvec; j++) { +- vec.iov_base = +- (char *)iov[start].iov_base + +- j * max_iov_size; +- vec.iov_len = +- min_t(int, max_iov_size, +- buflen - max_iov_size * j); +- remaining_data_length -= vec.iov_len; +- ret = smb_direct_post_send_data(st, &send_ctx, &vec, 1, +- remaining_data_length); +- if (ret) +- goto done; + } +- i++; +- if (i == niovs) +- break; + } +- start = i; +- buflen = 0; +- } else { +- i++; +- if (i == niovs) { +- /* send out all remaining vecs */ +- remaining_data_length -= buflen; +- ret = smb_direct_post_send_data(st, &send_ctx, +- &iov[start], i - start, +- remaining_data_length); +- if (ret) +- goto done; +- break; ++ possible_vecs -= page_count; ++ nvecs += 1; ++ possible_bytes -= v->iov_len; ++ bytes += v->iov_len; ++ ++ iov_ofs += v->iov_len; ++ if (iov_ofs >= iov[iov_idx].iov_len) { ++ iov_idx += 1; ++ iov_ofs = 0; + } + } ++ ++ remaining_data_length -= bytes; ++ ++ ret = smb_direct_post_send_data(st, &send_ctx, ++ vecs, nvecs, ++ remaining_data_length); ++ if (unlikely(ret)) { ++ error = ret; ++ goto done; ++ } + } + + done: + ret = smb_direct_flush_send_list(st, &send_ctx, true); ++ if (unlikely(!ret && error)) ++ ret = error; + + /* + * As an optimization, we don't wait for individual I/O to finish +@@ -1744,6 +1806,11 @@ static int smb_direct_init_params(struct smb_direct_transport *t, + return -EINVAL; + } + ++ if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { ++ pr_err("warning: device max_send_sge = %d too small\n", ++ device->attrs.max_send_sge); ++ return -EINVAL; ++ } + if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { + pr_err("warning: device max_recv_sge = %d too small\n", + device->attrs.max_recv_sge); +@@ -1767,7 +1834,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, + + cap->max_send_wr = max_send_wrs; + cap->max_recv_wr = t->recv_credit_max; +- cap->max_send_sge = max_sge_per_wr; ++ cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; + cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; + cap->max_inline_data = 0; + cap->max_rdma_ctxs = t->max_rw_credits; +diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h +index f7b3b93f3a49a7..0c70f3a5557505 100644 +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -135,6 +135,7 @@ struct af_alg_async_req { + * SG? + * @enc: Cryptographic operation to be performed when + * recvmsg is invoked. ++ * @write: True if we are in the middle of a write. + * @init: True if metadata has been sent. + * @len: Length of memory allocated for this data structure. + * @inflight: Non-zero when AIO requests are in flight. +@@ -151,10 +152,11 @@ struct af_alg_ctx { + size_t used; + atomic_t rcvused; + +- bool more; +- bool merge; +- bool enc; +- bool init; ++ u32 more:1, ++ merge:1, ++ enc:1, ++ write:1, ++ init:1; + + unsigned int len; + +diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h +index a7efcec2e3d081..215ff20affa33f 100644 +--- a/include/linux/io_uring_types.h ++++ b/include/linux/io_uring_types.h +@@ -418,9 +418,6 @@ struct io_ring_ctx { + struct list_head defer_list; + unsigned nr_drained; + +- struct io_alloc_cache msg_cache; +- spinlock_t msg_lock; +- + #ifdef CONFIG_NET_RX_BUSY_POLL + struct list_head napi_list; /* track busy poll napi_id */ + spinlock_t napi_lock; /* napi_list lock */ +diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h +index e6ba8f4f4bd1f4..27850ebb651b30 100644 +--- a/include/linux/mlx5/driver.h ++++ b/include/linux/mlx5/driver.h +@@ -662,6 +662,7 @@ struct mlx5e_resources { + bool tisn_valid; + } hw_objs; + struct net_device *uplink_netdev; ++ netdevice_tracker tracker; + struct mutex uplink_netdev_lock; + struct mlx5_crypto_dek_priv *dek_priv; + }; +diff --git a/include/linux/swap.h b/include/linux/swap.h +index bc0e1c275fc047..8b56b2bbaa4f07 100644 +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -384,6 +384,16 @@ void folio_add_lru_vma(struct folio *, struct vm_area_struct *); + void mark_page_accessed(struct page *); + void folio_mark_accessed(struct folio *); + ++static inline bool folio_may_be_lru_cached(struct folio *folio) ++{ ++ /* ++ * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting. ++ * Holding small numbers of low-order mTHP folios in per-CPU LRU cache ++ * will be sensible, but nobody has implemented and tested that yet. ++ */ ++ return !folio_test_large(folio); ++} ++ + extern atomic_t lru_disable_count; + + static inline bool lru_cache_disabled(void) +diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h +index 4160731dcb6e3a..1fc2fb03ce3f9a 100644 +--- a/include/net/dst_metadata.h ++++ b/include/net/dst_metadata.h +@@ -3,6 +3,7 @@ + #define __NET_DST_METADATA_H 1 + + #include ++#include + #include + #include + #include +@@ -220,9 +221,15 @@ static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, + int md_size) + { + const struct iphdr *iph = ip_hdr(skb); ++ struct metadata_dst *tun_dst; ++ ++ tun_dst = __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, ++ 0, flags, tunnel_id, md_size); + +- return __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, +- 0, flags, tunnel_id, md_size); ++ if (tun_dst && (iph->frag_off & htons(IP_DF))) ++ __set_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, ++ tun_dst->u.tun_info.key.tun_flags); ++ return tun_dst; + } + + static inline struct metadata_dst *__ipv6_tun_set_dst(const struct in6_addr *saddr, +diff --git a/include/net/sock.h b/include/net/sock.h +index a348ae145eda43..6e9f4c126672d0 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -2061,6 +2061,9 @@ static inline void sk_set_socket(struct sock *sk, struct socket *sock) + if (sock) { + WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid); + WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino); ++ } else { ++ /* Note: sk_uid is unchanged. */ ++ WRITE_ONCE(sk->sk_ino, 0); + } + } + +@@ -2082,8 +2085,6 @@ static inline void sock_orphan(struct sock *sk) + sock_set_flag(sk, SOCK_DEAD); + sk_set_socket(sk, NULL); + sk->sk_wq = NULL; +- /* Note: sk_uid is unchanged. */ +- WRITE_ONCE(sk->sk_ino, 0); + write_unlock_bh(&sk->sk_callback_lock); + } + +diff --git a/include/sound/sdca.h b/include/sound/sdca.h +index 5a5d6de78d7283..9c6a351c9d474f 100644 +--- a/include/sound/sdca.h ++++ b/include/sound/sdca.h +@@ -46,6 +46,7 @@ struct sdca_device_data { + + enum sdca_quirk { + SDCA_QUIRKS_RT712_VB, ++ SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING, + }; + + #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA) +diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h +index 67d015df8893cc..5fd5b4cf75ca1e 100644 +--- a/include/uapi/linux/mptcp.h ++++ b/include/uapi/linux/mptcp.h +@@ -31,6 +31,8 @@ + #define MPTCP_INFO_FLAG_FALLBACK _BITUL(0) + #define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED _BITUL(1) + ++#define MPTCP_PM_EV_FLAG_DENY_JOIN_ID0 _BITUL(0) ++ + #define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) + #define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) + #define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) +diff --git a/include/uapi/linux/mptcp_pm.h b/include/uapi/linux/mptcp_pm.h +index 6ac84b2f636ca2..7359d34da446b9 100644 +--- a/include/uapi/linux/mptcp_pm.h ++++ b/include/uapi/linux/mptcp_pm.h +@@ -16,10 +16,10 @@ + * good time to allocate memory and send ADD_ADDR if needed. Depending on the + * traffic-patterns it can take a long time until the MPTCP_EVENT_ESTABLISHED + * is sent. Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, +- * sport, dport, server-side. ++ * sport, dport, server-side, [flags]. + * @MPTCP_EVENT_ESTABLISHED: A MPTCP connection is established (can start new + * subflows). Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, +- * sport, dport, server-side. ++ * sport, dport, server-side, [flags]. + * @MPTCP_EVENT_CLOSED: A MPTCP connection has stopped. Attribute: token. + * @MPTCP_EVENT_ANNOUNCED: A new address has been announced by the peer. + * Attributes: token, rem_id, family, daddr4 | daddr6 [, dport]. +diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c +index 17dfaa0395c46b..1d03b2fc4b2594 100644 +--- a/io_uring/io-wq.c ++++ b/io_uring/io-wq.c +@@ -352,16 +352,16 @@ static void create_worker_cb(struct callback_head *cb) + struct io_wq *wq; + + struct io_wq_acct *acct; +- bool do_create = false; ++ bool activated_free_worker, do_create = false; + + worker = container_of(cb, struct io_worker, create_work); + wq = worker->wq; + acct = worker->acct; + + rcu_read_lock(); +- do_create = !io_acct_activate_free_worker(acct); ++ activated_free_worker = io_acct_activate_free_worker(acct); + rcu_read_unlock(); +- if (!do_create) ++ if (activated_free_worker) + goto no_need_create; + + raw_spin_lock(&acct->workers_lock); +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index 5111ec040c5342..eaa5410e5a70a1 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -290,7 +290,6 @@ static void io_free_alloc_caches(struct io_ring_ctx *ctx) + io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free); + io_alloc_cache_free(&ctx->rw_cache, io_rw_cache_free); + io_alloc_cache_free(&ctx->cmd_cache, io_cmd_cache_free); +- io_alloc_cache_free(&ctx->msg_cache, kfree); + io_futex_cache_free(ctx); + io_rsrc_cache_free(ctx); + } +@@ -337,9 +336,6 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p) + ret |= io_alloc_cache_init(&ctx->cmd_cache, IO_ALLOC_CACHE_MAX, + sizeof(struct io_async_cmd), + sizeof(struct io_async_cmd)); +- spin_lock_init(&ctx->msg_lock); +- ret |= io_alloc_cache_init(&ctx->msg_cache, IO_ALLOC_CACHE_MAX, +- sizeof(struct io_kiocb), 0); + ret |= io_futex_cache_init(ctx); + ret |= io_rsrc_cache_init(ctx); + if (ret) +@@ -1371,8 +1367,10 @@ static void io_req_task_cancel(struct io_kiocb *req, io_tw_token_t tw) + + void io_req_task_submit(struct io_kiocb *req, io_tw_token_t tw) + { +- io_tw_lock(req->ctx, tw); +- if (unlikely(io_should_terminate_tw())) ++ struct io_ring_ctx *ctx = req->ctx; ++ ++ io_tw_lock(ctx, tw); ++ if (unlikely(io_should_terminate_tw(ctx))) + io_req_defer_failed(req, -EFAULT); + else if (req->flags & REQ_F_FORCE_ASYNC) + io_queue_iowq(req); +diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h +index 66c1ca73f55ee5..336689752d9fe1 100644 +--- a/io_uring/io_uring.h ++++ b/io_uring/io_uring.h +@@ -470,9 +470,9 @@ static inline bool io_allowed_run_tw(struct io_ring_ctx *ctx) + * 2) PF_KTHREAD is set, in which case the invoker of the task_work is + * our fallback task_work. + */ +-static inline bool io_should_terminate_tw(void) ++static inline bool io_should_terminate_tw(struct io_ring_ctx *ctx) + { +- return current->flags & (PF_KTHREAD | PF_EXITING); ++ return (current->flags & (PF_KTHREAD | PF_EXITING)) || percpu_ref_is_dying(&ctx->refs); + } + + static inline void io_req_queue_tw_complete(struct io_kiocb *req, s32 res) +diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c +index 4c2578f2efcb0e..5e5b94236d7204 100644 +--- a/io_uring/msg_ring.c ++++ b/io_uring/msg_ring.c +@@ -11,7 +11,6 @@ + #include "io_uring.h" + #include "rsrc.h" + #include "filetable.h" +-#include "alloc_cache.h" + #include "msg_ring.h" + + /* All valid masks for MSG_RING */ +@@ -76,13 +75,7 @@ static void io_msg_tw_complete(struct io_kiocb *req, io_tw_token_t tw) + struct io_ring_ctx *ctx = req->ctx; + + io_add_aux_cqe(ctx, req->cqe.user_data, req->cqe.res, req->cqe.flags); +- if (spin_trylock(&ctx->msg_lock)) { +- if (io_alloc_cache_put(&ctx->msg_cache, req)) +- req = NULL; +- spin_unlock(&ctx->msg_lock); +- } +- if (req) +- kfree_rcu(req, rcu_head); ++ kfree_rcu(req, rcu_head); + percpu_ref_put(&ctx->refs); + } + +@@ -104,26 +97,13 @@ static int io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req, + return 0; + } + +-static struct io_kiocb *io_msg_get_kiocb(struct io_ring_ctx *ctx) +-{ +- struct io_kiocb *req = NULL; +- +- if (spin_trylock(&ctx->msg_lock)) { +- req = io_alloc_cache_get(&ctx->msg_cache); +- spin_unlock(&ctx->msg_lock); +- if (req) +- return req; +- } +- return kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); +-} +- + static int io_msg_data_remote(struct io_ring_ctx *target_ctx, + struct io_msg *msg) + { + struct io_kiocb *target; + u32 flags = 0; + +- target = io_msg_get_kiocb(target_ctx); ++ target = kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO) ; + if (unlikely(!target)) + return -ENOMEM; + +diff --git a/io_uring/notif.c b/io_uring/notif.c +index 9a6f6e92d74242..ea9c0116cec2df 100644 +--- a/io_uring/notif.c ++++ b/io_uring/notif.c +@@ -85,7 +85,7 @@ static int io_link_skb(struct sk_buff *skb, struct ubuf_info *uarg) + return -EEXIST; + + prev_nd = container_of(prev_uarg, struct io_notif_data, uarg); +- prev_notif = cmd_to_io_kiocb(nd); ++ prev_notif = cmd_to_io_kiocb(prev_nd); + + /* make sure all noifications can be finished in the same task_work */ + if (unlikely(notif->ctx != prev_notif->ctx || +diff --git a/io_uring/poll.c b/io_uring/poll.c +index 20e9b46a4adfd5..1b79c268725d47 100644 +--- a/io_uring/poll.c ++++ b/io_uring/poll.c +@@ -224,7 +224,7 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw) + { + int v; + +- if (unlikely(io_should_terminate_tw())) ++ if (unlikely(io_should_terminate_tw(req->ctx))) + return -ECANCELED; + + do { +diff --git a/io_uring/timeout.c b/io_uring/timeout.c +index 7f13bfa9f2b617..17e3aab0af3676 100644 +--- a/io_uring/timeout.c ++++ b/io_uring/timeout.c +@@ -324,7 +324,7 @@ static void io_req_task_link_timeout(struct io_kiocb *req, io_tw_token_t tw) + int ret; + + if (prev) { +- if (!io_should_terminate_tw()) { ++ if (!io_should_terminate_tw(req->ctx)) { + struct io_cancel_data cd = { + .ctx = req->ctx, + .data = prev->cqe.user_data, +diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c +index 929cad6ee32628..b2b4f62c90ce80 100644 +--- a/io_uring/uring_cmd.c ++++ b/io_uring/uring_cmd.c +@@ -123,7 +123,7 @@ static void io_uring_cmd_work(struct io_kiocb *req, io_tw_token_t tw) + struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); + unsigned int flags = IO_URING_F_COMPLETE_DEFER; + +- if (io_should_terminate_tw()) ++ if (io_should_terminate_tw(req->ctx)) + flags |= IO_URING_F_TASK_DEAD; + + /* task_work executor checks the deffered list completion */ +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index a723b7dc6e4e28..20f76b21765016 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -126,8 +126,31 @@ DEFINE_PERCPU_RWSEM(cgroup_threadgroup_rwsem); + * of concurrent destructions. Use a separate workqueue so that cgroup + * destruction work items don't end up filling up max_active of system_wq + * which may lead to deadlock. ++ * ++ * A cgroup destruction should enqueue work sequentially to: ++ * cgroup_offline_wq: use for css offline work ++ * cgroup_release_wq: use for css release work ++ * cgroup_free_wq: use for free work ++ * ++ * Rationale for using separate workqueues: ++ * The cgroup root free work may depend on completion of other css offline ++ * operations. If all tasks were enqueued to a single workqueue, this could ++ * create a deadlock scenario where: ++ * - Free work waits for other css offline work to complete. ++ * - But other css offline work is queued after free work in the same queue. ++ * ++ * Example deadlock scenario with single workqueue (cgroup_destroy_wq): ++ * 1. umount net_prio ++ * 2. net_prio root destruction enqueues work to cgroup_destroy_wq (CPUx) ++ * 3. perf_event CSS A offline enqueues work to same cgroup_destroy_wq (CPUx) ++ * 4. net_prio cgroup_destroy_root->cgroup_lock_and_drain_offline. ++ * 5. net_prio root destruction blocks waiting for perf_event CSS A offline, ++ * which can never complete as it's behind in the same queue and ++ * workqueue's max_active is 1. + */ +-static struct workqueue_struct *cgroup_destroy_wq; ++static struct workqueue_struct *cgroup_offline_wq; ++static struct workqueue_struct *cgroup_release_wq; ++static struct workqueue_struct *cgroup_free_wq; + + /* generate an array of cgroup subsystem pointers */ + #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, +@@ -5553,7 +5576,7 @@ static void css_release_work_fn(struct work_struct *work) + cgroup_unlock(); + + INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); +- queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); ++ queue_rcu_work(cgroup_free_wq, &css->destroy_rwork); + } + + static void css_release(struct percpu_ref *ref) +@@ -5562,7 +5585,7 @@ static void css_release(struct percpu_ref *ref) + container_of(ref, struct cgroup_subsys_state, refcnt); + + INIT_WORK(&css->destroy_work, css_release_work_fn); +- queue_work(cgroup_destroy_wq, &css->destroy_work); ++ queue_work(cgroup_release_wq, &css->destroy_work); + } + + static void init_and_link_css(struct cgroup_subsys_state *css, +@@ -5696,7 +5719,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, + list_del_rcu(&css->sibling); + err_free_css: + INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); +- queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); ++ queue_rcu_work(cgroup_free_wq, &css->destroy_rwork); + return ERR_PTR(err); + } + +@@ -5934,7 +5957,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) + + if (atomic_dec_and_test(&css->online_cnt)) { + INIT_WORK(&css->destroy_work, css_killed_work_fn); +- queue_work(cgroup_destroy_wq, &css->destroy_work); ++ queue_work(cgroup_offline_wq, &css->destroy_work); + } + } + +@@ -6320,8 +6343,14 @@ static int __init cgroup_wq_init(void) + * We would prefer to do this in cgroup_init() above, but that + * is called before init_workqueues(): so leave this until after. + */ +- cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1); +- BUG_ON(!cgroup_destroy_wq); ++ cgroup_offline_wq = alloc_workqueue("cgroup_offline", 0, 1); ++ BUG_ON(!cgroup_offline_wq); ++ ++ cgroup_release_wq = alloc_workqueue("cgroup_release", 0, 1); ++ BUG_ON(!cgroup_release_wq); ++ ++ cgroup_free_wq = alloc_workqueue("cgroup_free", 0, 1); ++ BUG_ON(!cgroup_free_wq); + return 0; + } + core_initcall(cgroup_wq_init); +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 717e3d1d6a2fa2..f3a97005713db7 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -6794,12 +6794,8 @@ __bpf_kfunc u32 scx_bpf_reenqueue_local(void) + * CPUs disagree, they use %ENQUEUE_RESTORE which is bypassed to + * the current local DSQ for running tasks and thus are not + * visible to the BPF scheduler. +- * +- * Also skip re-enqueueing tasks that can only run on this +- * CPU, as they would just be re-added to the same local +- * DSQ without any benefit. + */ +- if (p->migration_pending || is_migration_disabled(p) || p->nr_cpus_allowed == 1) ++ if (p->migration_pending) + continue; + + dispatch_dequeue(rq, p); +diff --git a/mm/gup.c b/mm/gup.c +index 3c39cbbeebef1f..10e46ff0904b05 100644 +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -2300,6 +2300,31 @@ static void pofs_unpin(struct pages_or_folios *pofs) + unpin_user_pages(pofs->pages, pofs->nr_entries); + } + ++static struct folio *pofs_next_folio(struct folio *folio, ++ struct pages_or_folios *pofs, long *index_ptr) ++{ ++ long i = *index_ptr + 1; ++ ++ if (!pofs->has_folios && folio_test_large(folio)) { ++ const unsigned long start_pfn = folio_pfn(folio); ++ const unsigned long end_pfn = start_pfn + folio_nr_pages(folio); ++ ++ for (; i < pofs->nr_entries; i++) { ++ unsigned long pfn = page_to_pfn(pofs->pages[i]); ++ ++ /* Is this page part of this folio? */ ++ if (pfn < start_pfn || pfn >= end_pfn) ++ break; ++ } ++ } ++ ++ if (unlikely(i == pofs->nr_entries)) ++ return NULL; ++ *index_ptr = i; ++ ++ return pofs_get_folio(pofs, i); ++} ++ + /* + * Returns the number of collected folios. Return value is always >= 0. + */ +@@ -2307,16 +2332,13 @@ static unsigned long collect_longterm_unpinnable_folios( + struct list_head *movable_folio_list, + struct pages_or_folios *pofs) + { +- unsigned long i, collected = 0; +- struct folio *prev_folio = NULL; +- bool drain_allow = true; +- +- for (i = 0; i < pofs->nr_entries; i++) { +- struct folio *folio = pofs_get_folio(pofs, i); ++ unsigned long collected = 0; ++ struct folio *folio; ++ int drained = 0; ++ long i = 0; + +- if (folio == prev_folio) +- continue; +- prev_folio = folio; ++ for (folio = pofs_get_folio(pofs, i); folio; ++ folio = pofs_next_folio(folio, pofs, &i)) { + + if (folio_is_longterm_pinnable(folio)) + continue; +@@ -2331,9 +2353,17 @@ static unsigned long collect_longterm_unpinnable_folios( + continue; + } + +- if (!folio_test_lru(folio) && drain_allow) { ++ if (drained == 0 && folio_may_be_lru_cached(folio) && ++ folio_ref_count(folio) != ++ folio_expected_ref_count(folio) + 1) { ++ lru_add_drain(); ++ drained = 1; ++ } ++ if (drained == 1 && folio_may_be_lru_cached(folio) && ++ folio_ref_count(folio) != ++ folio_expected_ref_count(folio) + 1) { + lru_add_drain_all(); +- drain_allow = false; ++ drained = 2; + } + + if (!folio_isolate_lru(folio)) +diff --git a/mm/mlock.c b/mm/mlock.c +index 3cb72b579ffd33..2f454ed6e51041 100644 +--- a/mm/mlock.c ++++ b/mm/mlock.c +@@ -255,7 +255,7 @@ void mlock_folio(struct folio *folio) + + folio_get(folio); + if (!folio_batch_add(fbatch, mlock_lru(folio)) || +- folio_test_large(folio) || lru_cache_disabled()) ++ !folio_may_be_lru_cached(folio) || lru_cache_disabled()) + mlock_folio_batch(fbatch); + local_unlock(&mlock_fbatch.lock); + } +@@ -278,7 +278,7 @@ void mlock_new_folio(struct folio *folio) + + folio_get(folio); + if (!folio_batch_add(fbatch, mlock_new(folio)) || +- folio_test_large(folio) || lru_cache_disabled()) ++ !folio_may_be_lru_cached(folio) || lru_cache_disabled()) + mlock_folio_batch(fbatch); + local_unlock(&mlock_fbatch.lock); + } +@@ -299,7 +299,7 @@ void munlock_folio(struct folio *folio) + */ + folio_get(folio); + if (!folio_batch_add(fbatch, folio) || +- folio_test_large(folio) || lru_cache_disabled()) ++ !folio_may_be_lru_cached(folio) || lru_cache_disabled()) + mlock_folio_batch(fbatch); + local_unlock(&mlock_fbatch.lock); + } +diff --git a/mm/swap.c b/mm/swap.c +index 4fc322f7111a98..a524736323c8b7 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -164,6 +164,10 @@ static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn) + for (i = 0; i < folio_batch_count(fbatch); i++) { + struct folio *folio = fbatch->folios[i]; + ++ /* block memcg migration while the folio moves between lru */ ++ if (move_fn != lru_add && !folio_test_clear_lru(folio)) ++ continue; ++ + folio_lruvec_relock_irqsave(folio, &lruvec, &flags); + move_fn(lruvec, folio); + +@@ -176,14 +180,10 @@ static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn) + } + + static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, +- struct folio *folio, move_fn_t move_fn, +- bool on_lru, bool disable_irq) ++ struct folio *folio, move_fn_t move_fn, bool disable_irq) + { + unsigned long flags; + +- if (on_lru && !folio_test_clear_lru(folio)) +- return; +- + folio_get(folio); + + if (disable_irq) +@@ -191,8 +191,8 @@ static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, + else + local_lock(&cpu_fbatches.lock); + +- if (!folio_batch_add(this_cpu_ptr(fbatch), folio) || folio_test_large(folio) || +- lru_cache_disabled()) ++ if (!folio_batch_add(this_cpu_ptr(fbatch), folio) || ++ !folio_may_be_lru_cached(folio) || lru_cache_disabled()) + folio_batch_move_lru(this_cpu_ptr(fbatch), move_fn); + + if (disable_irq) +@@ -201,13 +201,13 @@ static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, + local_unlock(&cpu_fbatches.lock); + } + +-#define folio_batch_add_and_move(folio, op, on_lru) \ +- __folio_batch_add_and_move( \ +- &cpu_fbatches.op, \ +- folio, \ +- op, \ +- on_lru, \ +- offsetof(struct cpu_fbatches, op) >= offsetof(struct cpu_fbatches, lock_irq) \ ++#define folio_batch_add_and_move(folio, op) \ ++ __folio_batch_add_and_move( \ ++ &cpu_fbatches.op, \ ++ folio, \ ++ op, \ ++ offsetof(struct cpu_fbatches, op) >= \ ++ offsetof(struct cpu_fbatches, lock_irq) \ + ) + + static void lru_move_tail(struct lruvec *lruvec, struct folio *folio) +@@ -231,10 +231,10 @@ static void lru_move_tail(struct lruvec *lruvec, struct folio *folio) + void folio_rotate_reclaimable(struct folio *folio) + { + if (folio_test_locked(folio) || folio_test_dirty(folio) || +- folio_test_unevictable(folio)) ++ folio_test_unevictable(folio) || !folio_test_lru(folio)) + return; + +- folio_batch_add_and_move(folio, lru_move_tail, true); ++ folio_batch_add_and_move(folio, lru_move_tail); + } + + void lru_note_cost(struct lruvec *lruvec, bool file, +@@ -323,10 +323,11 @@ static void folio_activate_drain(int cpu) + + void folio_activate(struct folio *folio) + { +- if (folio_test_active(folio) || folio_test_unevictable(folio)) ++ if (folio_test_active(folio) || folio_test_unevictable(folio) || ++ !folio_test_lru(folio)) + return; + +- folio_batch_add_and_move(folio, lru_activate, true); ++ folio_batch_add_and_move(folio, lru_activate); + } + + #else +@@ -502,7 +503,7 @@ void folio_add_lru(struct folio *folio) + lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) + folio_set_active(folio); + +- folio_batch_add_and_move(folio, lru_add, false); ++ folio_batch_add_and_move(folio, lru_add); + } + EXPORT_SYMBOL(folio_add_lru); + +@@ -680,13 +681,13 @@ void lru_add_drain_cpu(int cpu) + void deactivate_file_folio(struct folio *folio) + { + /* Deactivating an unevictable folio will not accelerate reclaim */ +- if (folio_test_unevictable(folio)) ++ if (folio_test_unevictable(folio) || !folio_test_lru(folio)) + return; + + if (lru_gen_enabled() && lru_gen_clear_refs(folio)) + return; + +- folio_batch_add_and_move(folio, lru_deactivate_file, true); ++ folio_batch_add_and_move(folio, lru_deactivate_file); + } + + /* +@@ -699,13 +700,13 @@ void deactivate_file_folio(struct folio *folio) + */ + void folio_deactivate(struct folio *folio) + { +- if (folio_test_unevictable(folio)) ++ if (folio_test_unevictable(folio) || !folio_test_lru(folio)) + return; + + if (lru_gen_enabled() ? lru_gen_clear_refs(folio) : !folio_test_active(folio)) + return; + +- folio_batch_add_and_move(folio, lru_deactivate, true); ++ folio_batch_add_and_move(folio, lru_deactivate); + } + + /** +@@ -718,10 +719,11 @@ void folio_deactivate(struct folio *folio) + void folio_mark_lazyfree(struct folio *folio) + { + if (!folio_test_anon(folio) || !folio_test_swapbacked(folio) || ++ !folio_test_lru(folio) || + folio_test_swapcache(folio) || folio_test_unevictable(folio)) + return; + +- folio_batch_add_and_move(folio, lru_lazyfree, true); ++ folio_batch_add_and_move(folio, lru_lazyfree); + } + + void lru_add_drain(void) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 424412680cfcc6..b7ed263e6dd701 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4505,7 +4505,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c + } + + /* ineligible */ +- if (!folio_test_lru(folio) || zone > sc->reclaim_idx) { ++ if (zone > sc->reclaim_idx) { + gen = folio_inc_gen(lruvec, folio, false); + list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]); + return true; +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 461a9ab540af02..98da33e0c308b0 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3330,6 +3330,7 @@ int tcp_disconnect(struct sock *sk, int flags) + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + int old_state = sk->sk_state; ++ struct request_sock *req; + u32 seq; + + if (old_state != TCP_CLOSE) +@@ -3445,6 +3446,10 @@ int tcp_disconnect(struct sock *sk, int flags) + + + /* Clean up fastopen related fields */ ++ req = rcu_dereference_protected(tp->fastopen_rsk, ++ lockdep_sock_is_held(sk)); ++ if (req) ++ reqsk_fastopen_remove(sk, req, false); + tcp_free_fastopen_req(tp); + inet_clear_bit(DEFER_CONNECT, sk); + tp->fastopen_client_fail = 0; +diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c +index bbb8d5f0eae7d3..3338b6cc85c487 100644 +--- a/net/ipv4/tcp_ao.c ++++ b/net/ipv4/tcp_ao.c +@@ -1178,7 +1178,9 @@ void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb) + if (!ao) + return; + +- WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); ++ /* sk with TCP_REPAIR_ON does not have skb in tcp_finish_connect */ ++ if (skb) ++ WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); + ao->rcv_sne = 0; + + hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) +diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h +index 307587c8a0037b..7964a7c5f0b2b5 100644 +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1389,7 +1389,7 @@ drv_get_ftm_responder_stats(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_ftm_responder_stats *ftm_stats) + { +- u32 ret = -EOPNOTSUPP; ++ int ret = -EOPNOTSUPP; + + might_sleep(); + lockdep_assert_wiphy(local->hw.wiphy); +diff --git a/net/mac80211/main.c b/net/mac80211/main.c +index 1bad353d8a772b..35c6755b817a83 100644 +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1136,7 +1136,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + int result, i; + enum nl80211_band band; + int channels, max_bitrates; +- bool supp_ht, supp_vht, supp_he, supp_eht; ++ bool supp_ht, supp_vht, supp_he, supp_eht, supp_s1g; + struct cfg80211_chan_def dflt_chandef = {}; + + if (ieee80211_hw_check(hw, QUEUE_CONTROL) && +@@ -1252,6 +1252,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + supp_vht = false; + supp_he = false; + supp_eht = false; ++ supp_s1g = false; + for (band = 0; band < NUM_NL80211_BANDS; band++) { + const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_supported_band *sband; +@@ -1299,6 +1300,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + max_bitrates = sband->n_bitrates; + supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; ++ supp_s1g = supp_s1g || sband->s1g_cap.s1g; + + for_each_sband_iftype_data(sband, i, iftd) { + u8 he_40_mhz_cap; +@@ -1432,6 +1434,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + local->scan_ies_len += + 2 + sizeof(struct ieee80211_vht_cap); + ++ if (supp_s1g) ++ local->scan_ies_len += 2 + sizeof(struct ieee80211_s1g_cap); ++ + /* + * HE cap element is variable in size - set len to allow max size */ + if (supp_he) { +diff --git a/net/mptcp/options.c b/net/mptcp/options.c +index c6983471dca552..bb4253aa675a61 100644 +--- a/net/mptcp/options.c ++++ b/net/mptcp/options.c +@@ -984,13 +984,13 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, + return false; + } + +- if (mp_opt->deny_join_id0) +- WRITE_ONCE(msk->pm.remote_deny_join_id0, true); +- + if (unlikely(!READ_ONCE(msk->pm.server_side))) + pr_warn_once("bogus mpc option on established client sk"); + + set_fully_established: ++ if (mp_opt->deny_join_id0) ++ WRITE_ONCE(msk->pm.remote_deny_join_id0, true); ++ + mptcp_data_lock((struct sock *)msk); + __mptcp_subflow_fully_established(msk, subflow, mp_opt); + mptcp_data_unlock((struct sock *)msk); +diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c +index 50aaf259959aea..ce7d42d3bd007b 100644 +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -408,6 +408,7 @@ static int mptcp_event_created(struct sk_buff *skb, + const struct sock *ssk) + { + int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)); ++ u16 flags = 0; + + if (err) + return err; +@@ -415,6 +416,12 @@ static int mptcp_event_created(struct sk_buff *skb, + if (nla_put_u8(skb, MPTCP_ATTR_SERVER_SIDE, READ_ONCE(msk->pm.server_side))) + return -EMSGSIZE; + ++ if (READ_ONCE(msk->pm.remote_deny_join_id0)) ++ flags |= MPTCP_PM_EV_FLAG_DENY_JOIN_ID0; ++ ++ if (flags && nla_put_u16(skb, MPTCP_ATTR_FLAGS, flags)) ++ return -EMSGSIZE; ++ + return mptcp_event_add_subflow(skb, ssk); + } + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 1063c53850c057..b895e3ecdc9b7c 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -350,6 +350,20 @@ static void mptcp_close_wake_up(struct sock *sk) + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); + } + ++static void mptcp_shutdown_subflows(struct mptcp_sock *msk) ++{ ++ struct mptcp_subflow_context *subflow; ++ ++ mptcp_for_each_subflow(msk, subflow) { ++ struct sock *ssk = mptcp_subflow_tcp_sock(subflow); ++ bool slow; ++ ++ slow = lock_sock_fast(ssk); ++ tcp_shutdown(ssk, SEND_SHUTDOWN); ++ unlock_sock_fast(ssk, slow); ++ } ++} ++ + /* called under the msk socket lock */ + static bool mptcp_pending_data_fin_ack(struct sock *sk) + { +@@ -374,6 +388,7 @@ static void mptcp_check_data_fin_ack(struct sock *sk) + break; + case TCP_CLOSING: + case TCP_LAST_ACK: ++ mptcp_shutdown_subflows(msk); + mptcp_set_state(sk, TCP_CLOSE); + break; + } +@@ -542,6 +557,7 @@ static bool mptcp_check_data_fin(struct sock *sk) + mptcp_set_state(sk, TCP_CLOSING); + break; + case TCP_FIN_WAIT2: ++ mptcp_shutdown_subflows(msk); + mptcp_set_state(sk, TCP_CLOSE); + break; + default: +diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c +index 1802bc5435a1aa..d77a2e374a7ae8 100644 +--- a/net/mptcp/subflow.c ++++ b/net/mptcp/subflow.c +@@ -882,6 +882,10 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, + + ctx->subflow_id = 1; + owner = mptcp_sk(ctx->conn); ++ ++ if (mp_opt.deny_join_id0) ++ WRITE_ONCE(owner->pm.remote_deny_join_id0, true); ++ + mptcp_pm_new_connection(owner, child, 1); + + /* with OoO packets we can reach here without ingress +diff --git a/net/rds/ib_frmr.c b/net/rds/ib_frmr.c +index 28c1b00221780f..bd861191157b54 100644 +--- a/net/rds/ib_frmr.c ++++ b/net/rds/ib_frmr.c +@@ -133,12 +133,15 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) + + ret = ib_map_mr_sg_zbva(frmr->mr, ibmr->sg, ibmr->sg_dma_len, + &off, PAGE_SIZE); +- if (unlikely(ret != ibmr->sg_dma_len)) +- return ret < 0 ? ret : -EINVAL; ++ if (unlikely(ret != ibmr->sg_dma_len)) { ++ ret = ret < 0 ? ret : -EINVAL; ++ goto out_inc; ++ } + +- if (cmpxchg(&frmr->fr_state, +- FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE) +- return -EBUSY; ++ if (cmpxchg(&frmr->fr_state, FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE) { ++ ret = -EBUSY; ++ goto out_inc; ++ } + + atomic_inc(&ibmr->ic->i_fastreg_inuse_count); + +@@ -166,11 +169,10 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) + /* Failure here can be because of -ENOMEM as well */ + rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE); + +- atomic_inc(&ibmr->ic->i_fastreg_wrs); + if (printk_ratelimit()) + pr_warn("RDS/IB: %s returned error(%d)\n", + __func__, ret); +- goto out; ++ goto out_inc; + } + + /* Wait for the registration to complete in order to prevent an invalid +@@ -179,8 +181,10 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) + */ + wait_event(frmr->fr_reg_done, !frmr->fr_reg); + +-out: ++ return ret; + ++out_inc: ++ atomic_inc(&ibmr->ic->i_fastreg_wrs); + return ret; + } + +diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c +index 41e657e977618a..cf2dcec6ce5afc 100644 +--- a/net/rfkill/rfkill-gpio.c ++++ b/net/rfkill/rfkill-gpio.c +@@ -94,10 +94,10 @@ static const struct dmi_system_id rfkill_gpio_deny_table[] = { + static int rfkill_gpio_probe(struct platform_device *pdev) + { + struct rfkill_gpio_data *rfkill; +- struct gpio_desc *gpio; ++ const char *type_name = NULL; + const char *name_property; + const char *type_property; +- const char *type_name; ++ struct gpio_desc *gpio; + int ret; + + if (dmi_check_system(rfkill_gpio_deny_table)) +diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c +index 1e19c605bcc829..dce5a3d8a964f8 100644 +--- a/net/rxrpc/rxgk.c ++++ b/net/rxrpc/rxgk.c +@@ -475,7 +475,7 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call, + struct krb5_buffer metadata; + unsigned int offset = sp->offset, len = sp->len; + size_t data_offset = 0, data_len = len; +- u32 ac; ++ u32 ac = 0; + int ret = -ENOMEM; + + _enter(""); +@@ -499,9 +499,10 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call, + ret = rxgk_verify_mic_skb(gk->krb5, gk->rx_Kc, &metadata, + skb, &offset, &len, &ac); + kfree(hdr); +- if (ret == -EPROTO) { +- rxrpc_abort_eproto(call, skb, ac, +- rxgk_abort_1_verify_mic_eproto); ++ if (ret < 0) { ++ if (ret != -ENOMEM) ++ rxrpc_abort_eproto(call, skb, ac, ++ rxgk_abort_1_verify_mic_eproto); + } else { + sp->offset = offset; + sp->len = len; +@@ -524,15 +525,16 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call, + struct rxgk_header hdr; + unsigned int offset = sp->offset, len = sp->len; + int ret; +- u32 ac; ++ u32 ac = 0; + + _enter(""); + + ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac); +- if (ret == -EPROTO) +- rxrpc_abort_eproto(call, skb, ac, rxgk_abort_2_decrypt_eproto); +- if (ret < 0) ++ if (ret < 0) { ++ if (ret != -ENOMEM) ++ rxrpc_abort_eproto(call, skb, ac, rxgk_abort_2_decrypt_eproto); + goto error; ++ } + + if (len < sizeof(hdr)) { + ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT, +diff --git a/net/rxrpc/rxgk_app.c b/net/rxrpc/rxgk_app.c +index b94b77a1c31780..30275cb5ba3e25 100644 +--- a/net/rxrpc/rxgk_app.c ++++ b/net/rxrpc/rxgk_app.c +@@ -54,6 +54,10 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb, + + _enter(""); + ++ if (ticket_len < 10 * sizeof(__be32)) ++ return rxrpc_abort_conn(conn, skb, RXGK_INCONSISTENCY, -EPROTO, ++ rxgk_abort_resp_short_yfs_tkt); ++ + /* Get the session key length */ + ret = skb_copy_bits(skb, ticket_offset, tmp, sizeof(tmp)); + if (ret < 0) +@@ -187,7 +191,7 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, + struct key *server_key; + unsigned int ticket_offset, ticket_len; + u32 kvno, enctype; +- int ret, ec; ++ int ret, ec = 0; + + struct { + __be32 kvno; +@@ -195,22 +199,23 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, + __be32 token_len; + } container; + ++ if (token_len < sizeof(container)) ++ goto short_packet; ++ + /* Decode the RXGK_TokenContainer object. This tells us which server + * key we should be using. We can then fetch the key, get the secret + * and set up the crypto to extract the token. + */ + if (skb_copy_bits(skb, token_offset, &container, sizeof(container)) < 0) +- return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, +- rxgk_abort_resp_tok_short); ++ goto short_packet; + + kvno = ntohl(container.kvno); + enctype = ntohl(container.enctype); + ticket_len = ntohl(container.token_len); + ticket_offset = token_offset + sizeof(container); + +- if (xdr_round_up(ticket_len) > token_len - 3 * 4) +- return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, +- rxgk_abort_resp_tok_short); ++ if (xdr_round_up(ticket_len) > token_len - sizeof(container)) ++ goto short_packet; + + _debug("KVNO %u", kvno); + _debug("ENC %u", enctype); +@@ -236,9 +241,11 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, + &ticket_offset, &ticket_len, &ec); + crypto_free_aead(token_enc); + token_enc = NULL; +- if (ret < 0) +- return rxrpc_abort_conn(conn, skb, ec, ret, +- rxgk_abort_resp_tok_dec); ++ if (ret < 0) { ++ if (ret != -ENOMEM) ++ return rxrpc_abort_conn(conn, skb, ec, ret, ++ rxgk_abort_resp_tok_dec); ++ } + + ret = conn->security->default_decode_ticket(conn, skb, ticket_offset, + ticket_len, _key); +@@ -283,4 +290,8 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, + * also come out this way if the ticket decryption fails. + */ + return ret; ++ ++short_packet: ++ return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, ++ rxgk_abort_resp_tok_short); + } +diff --git a/net/rxrpc/rxgk_common.h b/net/rxrpc/rxgk_common.h +index 7370a56559853f..80164d89e19c03 100644 +--- a/net/rxrpc/rxgk_common.h ++++ b/net/rxrpc/rxgk_common.h +@@ -88,11 +88,16 @@ int rxgk_decrypt_skb(const struct krb5_enctype *krb5, + *_offset += offset; + *_len = len; + break; ++ case -EBADMSG: /* Checksum mismatch. */ + case -EPROTO: +- case -EBADMSG: + *_error_code = RXGK_SEALEDINCON; + break; ++ case -EMSGSIZE: ++ *_error_code = RXGK_PACKETSHORT; ++ break; ++ case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */ + default: ++ *_error_code = RXGK_INCONSISTENCY; + break; + } + +@@ -127,11 +132,16 @@ int rxgk_verify_mic_skb(const struct krb5_enctype *krb5, + *_offset += offset; + *_len = len; + break; ++ case -EBADMSG: /* Checksum mismatch */ + case -EPROTO: +- case -EBADMSG: + *_error_code = RXGK_SEALEDINCON; + break; ++ case -EMSGSIZE: ++ *_error_code = RXGK_PACKETSHORT; ++ break; ++ case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */ + default: ++ *_error_code = RXGK_INCONSISTENCY; + break; + } + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index 4e077068e6d98a..e4c42731ce39ae 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -141,6 +141,7 @@ void update_sk_prot(struct sock *sk, struct tls_context *ctx); + + int wait_on_pending_writer(struct sock *sk, long *timeo); + void tls_err_abort(struct sock *sk, int err); ++void tls_strp_abort_strp(struct tls_strparser *strp, int err); + + int init_prot_info(struct tls_prot_info *prot, + const struct tls_crypto_info *crypto_info, +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index d71643b494a1ae..98e12f0ff57e51 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -13,7 +13,7 @@ + + static struct workqueue_struct *tls_strp_wq; + +-static void tls_strp_abort_strp(struct tls_strparser *strp, int err) ++void tls_strp_abort_strp(struct tls_strparser *strp, int err) + { + if (strp->stopped) + return; +@@ -211,11 +211,17 @@ static int tls_strp_copyin_frag(struct tls_strparser *strp, struct sk_buff *skb, + struct sk_buff *in_skb, unsigned int offset, + size_t in_len) + { ++ unsigned int nfrag = skb->len / PAGE_SIZE; + size_t len, chunk; + skb_frag_t *frag; + int sz; + +- frag = &skb_shinfo(skb)->frags[skb->len / PAGE_SIZE]; ++ if (unlikely(nfrag >= skb_shinfo(skb)->nr_frags)) { ++ DEBUG_NET_WARN_ON_ONCE(1); ++ return -EMSGSIZE; ++ } ++ ++ frag = &skb_shinfo(skb)->frags[nfrag]; + + len = in_len; + /* First make sure we got the header */ +@@ -520,10 +526,8 @@ static int tls_strp_read_sock(struct tls_strparser *strp) + tls_strp_load_anchor_with_queue(strp, inq); + if (!strp->stm.full_len) { + sz = tls_rx_msg_size(strp, strp->anchor); +- if (sz < 0) { +- tls_strp_abort_strp(strp, sz); ++ if (sz < 0) + return sz; +- } + + strp->stm.full_len = sz; + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index bac65d0d4e3e1e..daac9fd4be7eb5 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2474,8 +2474,7 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) + return data_len + TLS_HEADER_SIZE; + + read_failure: +- tls_err_abort(strp->sk, ret); +- ++ tls_strp_abort_strp(strp, ret); + return ret; + } + +diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c +index ed6bed8b3d4d99..88156145172f17 100644 +--- a/samples/damon/mtier.c ++++ b/samples/damon/mtier.c +@@ -27,14 +27,14 @@ module_param(node1_end_addr, ulong, 0600); + static int damon_sample_mtier_enable_store( + const char *val, const struct kernel_param *kp); + +-static const struct kernel_param_ops enable_param_ops = { ++static const struct kernel_param_ops enabled_param_ops = { + .set = damon_sample_mtier_enable_store, + .get = param_get_bool, + }; + +-static bool enable __read_mostly; +-module_param_cb(enable, &enable_param_ops, &enable, 0600); +-MODULE_PARM_DESC(enable, "Enable of disable DAMON_SAMPLE_MTIER"); ++static bool enabled __read_mostly; ++module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); ++MODULE_PARM_DESC(enabled, "Enable or disable DAMON_SAMPLE_MTIER"); + + static struct damon_ctx *ctxs[2]; + +@@ -156,20 +156,23 @@ static bool init_called; + static int damon_sample_mtier_enable_store( + const char *val, const struct kernel_param *kp) + { +- bool enabled = enable; ++ bool is_enabled = enabled; + int err; + +- err = kstrtobool(val, &enable); ++ err = kstrtobool(val, &enabled); + if (err) + return err; + +- if (enable == enabled) ++ if (enabled == is_enabled) + return 0; + +- if (enable) { ++ if (!init_called) ++ return 0; ++ ++ if (enabled) { + err = damon_sample_mtier_start(); + if (err) +- enable = false; ++ enabled = false; + return err; + } + damon_sample_mtier_stop(); +@@ -181,10 +184,10 @@ static int __init damon_sample_mtier_init(void) + int err = 0; + + init_called = true; +- if (enable) { ++ if (enabled) { + err = damon_sample_mtier_start(); + if (err) +- enable = false; ++ enabled = false; + } + return 0; + } +diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c +index 5597e6a08ab226..f971e61e6c5c00 100644 +--- a/samples/damon/prcl.c ++++ b/samples/damon/prcl.c +@@ -17,14 +17,14 @@ module_param(target_pid, int, 0600); + static int damon_sample_prcl_enable_store( + const char *val, const struct kernel_param *kp); + +-static const struct kernel_param_ops enable_param_ops = { ++static const struct kernel_param_ops enabled_param_ops = { + .set = damon_sample_prcl_enable_store, + .get = param_get_bool, + }; + +-static bool enable __read_mostly; +-module_param_cb(enable, &enable_param_ops, &enable, 0600); +-MODULE_PARM_DESC(enable, "Enable of disable DAMON_SAMPLE_WSSE"); ++static bool enabled __read_mostly; ++module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); ++MODULE_PARM_DESC(enabled, "Enable or disable DAMON_SAMPLE_PRCL"); + + static struct damon_ctx *ctx; + static struct pid *target_pidp; +@@ -109,23 +109,28 @@ static void damon_sample_prcl_stop(void) + put_pid(target_pidp); + } + ++static bool init_called; ++ + static int damon_sample_prcl_enable_store( + const char *val, const struct kernel_param *kp) + { +- bool enabled = enable; ++ bool is_enabled = enabled; + int err; + +- err = kstrtobool(val, &enable); ++ err = kstrtobool(val, &enabled); + if (err) + return err; + +- if (enable == enabled) ++ if (enabled == is_enabled) ++ return 0; ++ ++ if (!init_called) + return 0; + +- if (enable) { ++ if (enabled) { + err = damon_sample_prcl_start(); + if (err) +- enable = false; ++ enabled = false; + return err; + } + damon_sample_prcl_stop(); +@@ -134,6 +139,14 @@ static int damon_sample_prcl_enable_store( + + static int __init damon_sample_prcl_init(void) + { ++ int err = 0; ++ ++ init_called = true; ++ if (enabled) { ++ err = damon_sample_prcl_start(); ++ if (err) ++ enabled = false; ++ } + return 0; + } + +diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c +index e941958b103249..d50730ee65a7e7 100644 +--- a/samples/damon/wsse.c ++++ b/samples/damon/wsse.c +@@ -18,14 +18,14 @@ module_param(target_pid, int, 0600); + static int damon_sample_wsse_enable_store( + const char *val, const struct kernel_param *kp); + +-static const struct kernel_param_ops enable_param_ops = { ++static const struct kernel_param_ops enabled_param_ops = { + .set = damon_sample_wsse_enable_store, + .get = param_get_bool, + }; + +-static bool enable __read_mostly; +-module_param_cb(enable, &enable_param_ops, &enable, 0600); +-MODULE_PARM_DESC(enable, "Enable or disable DAMON_SAMPLE_WSSE"); ++static bool enabled __read_mostly; ++module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); ++MODULE_PARM_DESC(enabled, "Enable or disable DAMON_SAMPLE_WSSE"); + + static struct damon_ctx *ctx; + static struct pid *target_pidp; +@@ -94,20 +94,20 @@ static bool init_called; + static int damon_sample_wsse_enable_store( + const char *val, const struct kernel_param *kp) + { +- bool enabled = enable; ++ bool is_enabled = enabled; + int err; + +- err = kstrtobool(val, &enable); ++ err = kstrtobool(val, &enabled); + if (err) + return err; + +- if (enable == enabled) ++ if (enabled == is_enabled) + return 0; + +- if (enable) { ++ if (enabled) { + err = damon_sample_wsse_start(); + if (err) +- enable = false; ++ enabled = false; + return err; + } + damon_sample_wsse_stop(); +@@ -119,10 +119,10 @@ static int __init damon_sample_wsse_init(void) + int err = 0; + + init_called = true; +- if (enable) { ++ if (enabled) { + err = damon_sample_wsse_start(); + if (err) +- enable = false; ++ enabled = false; + } + return err; + } +diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c +index 88d1f4b56e4be4..a220ac0c8eb831 100644 +--- a/sound/firewire/motu/motu-hwdep.c ++++ b/sound/firewire/motu/motu-hwdep.c +@@ -111,7 +111,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, + events = 0; + spin_unlock_irq(&motu->lock); + +- return events | EPOLLOUT; ++ return events; + } + + static int hwdep_get_info(struct snd_motu *motu, void __user *arg) +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 8458ca4d8d9dab..4819bd332f0390 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10752,6 +10752,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8992, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8994, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x103c, 0x89a0, "HP Laptop 15-dw4xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89aa, "HP EliteBook 630 G9", ALC236_FIXUP_HP_GPIO_LED), +diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c +index 70fa54d568ef68..4d9589b67099ef 100644 +--- a/sound/soc/amd/acp/acp-i2s.c ++++ b/sound/soc/amd/acp/acp-i2s.c +@@ -72,7 +72,7 @@ static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) + { + struct device *dev = cpu_dai->component->dev; +- struct acp_chip_info *chip = dev_get_platdata(dev); ++ struct acp_chip_info *chip = dev_get_drvdata(dev->parent); + int mode; + + mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; +@@ -196,7 +196,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ + u32 reg_val, fmt_reg, tdm_fmt; + u32 lrclk_div_val, bclk_div_val; + +- chip = dev_get_platdata(dev); ++ chip = dev_get_drvdata(dev->parent); + rsrc = chip->rsrc; + + /* These values are as per Hardware Spec */ +@@ -383,7 +383,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct + { + struct acp_stream *stream = substream->runtime->private_data; + struct device *dev = dai->component->dev; +- struct acp_chip_info *chip = dev_get_platdata(dev); ++ struct acp_chip_info *chip = dev_get_drvdata(dev->parent); + struct acp_resource *rsrc = chip->rsrc; + u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg; + +@@ -513,14 +513,13 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct + static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) + { + struct device *dev = dai->component->dev; +- struct acp_chip_info *chip = dev_get_platdata(dev); ++ struct acp_chip_info *chip = dev_get_drvdata(dev->parent); + struct acp_resource *rsrc = chip->rsrc; + struct acp_stream *stream = substream->runtime->private_data; + u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0; + u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl; + unsigned int dir = substream->stream; + +- chip = dev_get_platdata(dev); + switch (dai->driver->id) { + case I2S_SP_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { +@@ -629,7 +628,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d + { + struct acp_stream *stream = substream->runtime->private_data; + struct device *dev = dai->component->dev; +- struct acp_chip_info *chip = dev_get_platdata(dev); ++ struct acp_chip_info *chip = dev_get_drvdata(dev->parent); + struct acp_resource *rsrc = chip->rsrc; + unsigned int dir = substream->stream; + unsigned int irq_bit = 0; +diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c +index b3d401ada17601..2d993428f87e3c 100644 +--- a/sound/soc/codecs/sma1307.c ++++ b/sound/soc/codecs/sma1307.c +@@ -1737,9 +1737,10 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil + sma1307->set.checksum = data[sma1307->set.header_size - 2]; + sma1307->set.num_mode = data[sma1307->set.header_size - 1]; + num_mode = sma1307->set.num_mode; +- sma1307->set.header = devm_kzalloc(sma1307->dev, +- sma1307->set.header_size, +- GFP_KERNEL); ++ sma1307->set.header = devm_kmalloc_array(sma1307->dev, ++ sma1307->set.header_size, ++ sizeof(int), ++ GFP_KERNEL); + if (!sma1307->set.header) { + sma1307->set.status = false; + return; +diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c +index 401ee20897b1ba..94873ea630146b 100644 +--- a/sound/soc/codecs/wm8940.c ++++ b/sound/soc/codecs/wm8940.c +@@ -220,7 +220,7 @@ static const struct snd_kcontrol_new wm8940_snd_controls[] = { + SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL, + 0, 255, 0, wm8940_adc_tlv), + SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum), +- SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST, ++ SOC_SINGLE_TLV("Capture Boost Volume", WM8940_ADCBOOST, + 8, 1, 0, wm8940_capture_boost_vol_tlv), + SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL, + 0, 63, 0, wm8940_spk_vol_tlv), +@@ -693,7 +693,12 @@ static int wm8940_update_clocks(struct snd_soc_dai *dai) + f = wm8940_get_mclkdiv(priv->mclk, fs256, &mclkdiv); + if (f != priv->mclk) { + /* The PLL performs best around 90MHz */ +- fpll = wm8940_get_mclkdiv(22500000, fs256, &mclkdiv); ++ if (fs256 % 8000) ++ f = 22579200; ++ else ++ f = 24576000; ++ ++ fpll = wm8940_get_mclkdiv(f, fs256, &mclkdiv); + } + + wm8940_set_dai_pll(dai, 0, 0, priv->mclk, fpll); +diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c +index bdf437a5403fe2..db16d893a23514 100644 +--- a/sound/soc/codecs/wm8974.c ++++ b/sound/soc/codecs/wm8974.c +@@ -419,10 +419,14 @@ static int wm8974_update_clocks(struct snd_soc_dai *dai) + fs256 = 256 * priv->fs; + + f = wm8974_get_mclkdiv(priv->mclk, fs256, &mclkdiv); +- + if (f != priv->mclk) { + /* The PLL performs best around 90MHz */ +- fpll = wm8974_get_mclkdiv(22500000, fs256, &mclkdiv); ++ if (fs256 % 8000) ++ f = 22579200; ++ else ++ f = 24576000; ++ ++ fpll = wm8974_get_mclkdiv(f, fs256, &mclkdiv); + } + + wm8974_set_dai_pll(dai, 0, 0, priv->mclk, fpll); +diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c +index 81a2f0339e0552..ff1fa01acb85b2 100644 +--- a/sound/soc/intel/catpt/pcm.c ++++ b/sound/soc/intel/catpt/pcm.c +@@ -568,8 +568,9 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = { + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + .formats = SNDRV_PCM_FMTBIT_S16_LE | +- SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN, + .periods_min = CATPT_PCM_PERIODS_MIN, +@@ -699,14 +700,18 @@ static struct snd_soc_dai_driver dai_drivers[] = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, +- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + }, + .capture = { + .stream_name = "Analog Capture", + .channels_min = 2, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, +- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + }, + }, + { +@@ -718,7 +723,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, +- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + }, + }, + { +@@ -730,7 +737,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, +- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + }, + }, + { +@@ -742,7 +751,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, +- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | ++ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, + }, + }, + { +diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c +index 4ebaaf736fb98a..3f5eed5afce55e 100644 +--- a/sound/soc/qcom/qdsp6/audioreach.c ++++ b/sound/soc/qcom/qdsp6/audioreach.c +@@ -971,6 +971,7 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, + param_data->param_id = PARAM_ID_I2S_INTF_CFG; + param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; + ++ intf_cfg->cfg.lpaif_type = module->hw_interface_type; + intf_cfg->cfg.intf_idx = module->hw_interface_idx; + intf_cfg->cfg.sd_line_idx = module->sd_line_idx; + +diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +index a0d90462fd6a38..528756f1332bcf 100644 +--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c ++++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +@@ -213,8 +213,10 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s + + return 0; + err: +- q6apm_graph_close(dai_data->graph[dai->id]); +- dai_data->graph[dai->id] = NULL; ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ q6apm_graph_close(dai_data->graph[dai->id]); ++ dai_data->graph[dai->id] = NULL; ++ } + return rc; + } + +@@ -260,6 +262,7 @@ static const struct snd_soc_dai_ops q6i2s_ops = { + .shutdown = q6apm_lpass_dai_shutdown, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, ++ .set_fmt = q6i2s_set_fmt, + }; + + static const struct snd_soc_dai_ops q6hdmi_ops = { +diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c +index 0244cdcdd109a7..4798ce2c8f0b40 100644 +--- a/sound/soc/sdca/sdca_device.c ++++ b/sound/soc/sdca/sdca_device.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -55,11 +56,30 @@ static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) + return false; + } + ++static bool sdca_device_quirk_skip_func_type_patching(struct sdw_slave *slave) ++{ ++ const char *vendor, *sku; ++ ++ vendor = dmi_get_system_info(DMI_SYS_VENDOR); ++ sku = dmi_get_system_info(DMI_PRODUCT_SKU); ++ ++ if (vendor && sku && ++ !strcmp(vendor, "Dell Inc.") && ++ (!strcmp(sku, "0C62") || !strcmp(sku, "0C63") || !strcmp(sku, "0C6B")) && ++ slave->sdca_data.interface_revision == 0x061c && ++ slave->id.mfg_id == 0x01fa && slave->id.part_id == 0x4243) ++ return true; ++ ++ return false; ++} ++ + bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) + { + switch (quirk) { + case SDCA_QUIRKS_RT712_VB: + return sdca_device_quirk_rt712_vb(slave); ++ case SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING: ++ return sdca_device_quirk_skip_func_type_patching(slave); + default: + break; + } +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index 050f7338aca95a..ea793869c03858 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -89,6 +89,7 @@ static int find_sdca_function(struct acpi_device *adev, void *data) + { + struct fwnode_handle *function_node = acpi_fwnode_handle(adev); + struct sdca_device_data *sdca_data = data; ++ struct sdw_slave *slave = container_of(sdca_data, struct sdw_slave, sdca_data); + struct device *dev = &adev->dev; + struct fwnode_handle *control5; /* used to identify function type */ + const char *function_name; +@@ -136,11 +137,13 @@ static int find_sdca_function(struct acpi_device *adev, void *data) + return ret; + } + +- ret = patch_sdca_function_type(sdca_data->interface_revision, &function_type); +- if (ret < 0) { +- dev_err(dev, "SDCA version %#x invalid function type %d\n", +- sdca_data->interface_revision, function_type); +- return ret; ++ if (!sdca_device_quirk_match(slave, SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING)) { ++ ret = patch_sdca_function_type(sdca_data->interface_revision, &function_type); ++ if (ret < 0) { ++ dev_err(dev, "SDCA version %#x invalid function type %d\n", ++ sdca_data->interface_revision, function_type); ++ return ret; ++ } + } + + function_name = get_sdca_function_name(function_type); +diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c +index c41c67c2204a41..ff1f8fe2a39bb7 100644 +--- a/sound/soc/sdca/sdca_regmap.c ++++ b/sound/soc/sdca/sdca_regmap.c +@@ -196,7 +196,7 @@ int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg) + + control = function_find_control(function, reg); + if (!control) +- return false; ++ return -EINVAL; + + return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32)); + } +diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c +index aa6b0247d5c99e..a34f472ef1751f 100644 +--- a/sound/soc/sof/intel/hda-stream.c ++++ b/sound/soc/sof/intel/hda-stream.c +@@ -890,7 +890,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) + + if (num_capture >= SOF_HDA_CAPTURE_STREAMS) { + dev_err(sdev->dev, "error: too many capture streams %d\n", +- num_playback); ++ num_capture); + return -EINVAL; + } + +diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c +index a25c5a5316901c..9ad76fff741b8d 100644 +--- a/sound/usb/qcom/qc_audio_offload.c ++++ b/sound/usb/qcom/qc_audio_offload.c +@@ -538,38 +538,33 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long iova, + umap_size, iova, mapped_iova_size); + } + ++static int uaudio_iommu_map_prot(bool dma_coherent) ++{ ++ int prot = IOMMU_READ | IOMMU_WRITE; ++ ++ if (dma_coherent) ++ prot |= IOMMU_CACHE; ++ return prot; ++} ++ + /** +- * uaudio_iommu_map() - maps iommu memory for adsp ++ * uaudio_iommu_map_pa() - maps iommu memory for adsp + * @mtype: ring type + * @dma_coherent: dma coherent + * @pa: physical address for ring/buffer + * @size: size of memory region +- * @sgt: sg table for memory region + * + * Maps the XHCI related resources to a memory region that is assigned to be + * used by the adsp. This will be mapped to the domain, which is created by + * the ASoC USB backend driver. + * + */ +-static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, +- phys_addr_t pa, size_t size, +- struct sg_table *sgt) ++static unsigned long uaudio_iommu_map_pa(enum mem_type mtype, bool dma_coherent, ++ phys_addr_t pa, size_t size) + { +- struct scatterlist *sg; + unsigned long iova = 0; +- size_t total_len = 0; +- unsigned long iova_sg; +- phys_addr_t pa_sg; + bool map = true; +- size_t sg_len; +- int prot; +- int ret; +- int i; +- +- prot = IOMMU_READ | IOMMU_WRITE; +- +- if (dma_coherent) +- prot |= IOMMU_CACHE; ++ int prot = uaudio_iommu_map_prot(dma_coherent); + + switch (mtype) { + case MEM_EVENT_RING: +@@ -583,20 +578,41 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, + &uaudio_qdev->xfer_ring_iova_size, + &uaudio_qdev->xfer_ring_list, size); + break; +- case MEM_XFER_BUF: +- iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, +- &uaudio_qdev->xfer_buf_iova_size, +- &uaudio_qdev->xfer_buf_list, size); +- break; + default: + dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype); + } + + if (!iova || !map) +- goto done; ++ return 0; ++ ++ iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); + +- if (!sgt) +- goto skip_sgt_map; ++ return iova; ++} ++ ++static unsigned long uaudio_iommu_map_xfer_buf(bool dma_coherent, size_t size, ++ struct sg_table *sgt) ++{ ++ struct scatterlist *sg; ++ unsigned long iova = 0; ++ size_t total_len = 0; ++ unsigned long iova_sg; ++ phys_addr_t pa_sg; ++ size_t sg_len; ++ int prot = uaudio_iommu_map_prot(dma_coherent); ++ int ret; ++ int i; ++ ++ prot = IOMMU_READ | IOMMU_WRITE; ++ ++ if (dma_coherent) ++ prot |= IOMMU_CACHE; ++ ++ iova = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, ++ &uaudio_qdev->xfer_buf_iova_size, ++ &uaudio_qdev->xfer_buf_list, size); ++ if (!iova) ++ goto done; + + iova_sg = iova; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { +@@ -618,11 +634,6 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent, + uaudio_iommu_unmap(MEM_XFER_BUF, iova, size, total_len); + iova = 0; + } +- return iova; +- +-skip_sgt_map: +- iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); +- + done: + return iova; + } +@@ -1020,7 +1031,6 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs, + struct sg_table xfer_buf_sgt; + dma_addr_t xfer_buf_dma; + void *xfer_buf; +- phys_addr_t xfer_buf_pa; + u32 len = xfer_buf_len; + bool dma_coherent; + dma_addr_t xfer_buf_dma_sysdev; +@@ -1051,18 +1061,12 @@ static int uaudio_transfer_buffer_setup(struct snd_usb_substream *subs, + if (!xfer_buf) + return -ENOMEM; + +- /* Remapping is not possible if xfer_buf is outside of linear map */ +- xfer_buf_pa = virt_to_phys(xfer_buf); +- if (WARN_ON(!page_is_ram(PFN_DOWN(xfer_buf_pa)))) { +- ret = -ENXIO; +- goto unmap_sync; +- } + dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, + xfer_buf_dma, len); + + /* map the physical buffer into sysdev as well */ +- xfer_buf_dma_sysdev = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent, +- xfer_buf_pa, len, &xfer_buf_sgt); ++ xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent, ++ len, &xfer_buf_sgt); + if (!xfer_buf_dma_sysdev) { + ret = -ENOMEM; + goto unmap_sync; +@@ -1143,8 +1147,8 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs, + sg_free_table(sgt); + + /* data transfer ring */ +- iova = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_pa, +- PAGE_SIZE, NULL); ++ iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa, ++ PAGE_SIZE); + if (!iova) { + ret = -ENOMEM; + goto clear_pa; +@@ -1207,8 +1211,8 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs, + mem_info->dma = sg_dma_address(sgt->sgl); + sg_free_table(sgt); + +- iova = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, er_pa, +- PAGE_SIZE, NULL); ++ iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa, ++ PAGE_SIZE); + if (!iova) { + ret = -ENOMEM; + goto clear_pa; +diff --git a/tools/arch/loongarch/include/asm/inst.h b/tools/arch/loongarch/include/asm/inst.h +index c25b5853181dba..d68fad63c8b732 100644 +--- a/tools/arch/loongarch/include/asm/inst.h ++++ b/tools/arch/loongarch/include/asm/inst.h +@@ -51,6 +51,10 @@ enum reg2i16_op { + bgeu_op = 0x1b, + }; + ++enum reg3_op { ++ amswapw_op = 0x70c0, ++}; ++ + struct reg0i15_format { + unsigned int immediate : 15; + unsigned int opcode : 17; +@@ -96,6 +100,13 @@ struct reg2i16_format { + unsigned int opcode : 6; + }; + ++struct reg3_format { ++ unsigned int rd : 5; ++ unsigned int rj : 5; ++ unsigned int rk : 5; ++ unsigned int opcode : 17; ++}; ++ + union loongarch_instruction { + unsigned int word; + struct reg0i15_format reg0i15_format; +@@ -105,6 +116,7 @@ union loongarch_instruction { + struct reg2i12_format reg2i12_format; + struct reg2i14_format reg2i14_format; + struct reg2i16_format reg2i16_format; ++ struct reg3_format reg3_format; + }; + + #define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction) +diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c +index b6fdc68053cc4e..2e555c4060c5e4 100644 +--- a/tools/objtool/arch/loongarch/decode.c ++++ b/tools/objtool/arch/loongarch/decode.c +@@ -278,6 +278,25 @@ static bool decode_insn_reg2i16_fomat(union loongarch_instruction inst, + return true; + } + ++static bool decode_insn_reg3_fomat(union loongarch_instruction inst, ++ struct instruction *insn) ++{ ++ switch (inst.reg3_format.opcode) { ++ case amswapw_op: ++ if (inst.reg3_format.rd == LOONGARCH_GPR_ZERO && ++ inst.reg3_format.rk == LOONGARCH_GPR_RA && ++ inst.reg3_format.rj == LOONGARCH_GPR_ZERO) { ++ /* amswap.w $zero, $ra, $zero */ ++ insn->type = INSN_BUG; ++ } ++ break; ++ default: ++ return false; ++ } ++ ++ return true; ++} ++ + int arch_decode_instruction(struct objtool_file *file, const struct section *sec, + unsigned long offset, unsigned int maxlen, + struct instruction *insn) +@@ -309,11 +328,19 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec + return 0; + if (decode_insn_reg2i16_fomat(inst, insn)) + return 0; ++ if (decode_insn_reg3_fomat(inst, insn)) ++ return 0; + +- if (inst.word == 0) ++ if (inst.word == 0) { ++ /* andi $zero, $zero, 0x0 */ + insn->type = INSN_NOP; +- else if (inst.reg0i15_format.opcode == break_op) { +- /* break */ ++ } else if (inst.reg0i15_format.opcode == break_op && ++ inst.reg0i15_format.immediate == 0x0) { ++ /* break 0x0 */ ++ insn->type = INSN_TRAP; ++ } else if (inst.reg0i15_format.opcode == break_op && ++ inst.reg0i15_format.immediate == 0x1) { ++ /* break 0x1 */ + insn->type = INSN_BUG; + } else if (inst.reg2_format.opcode == ertn_op) { + /* ertn */ +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index 85b2a93a59ac65..779f6230130af2 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -477,6 +477,7 @@ static int __maps__insert(struct maps *maps, struct map *new) + } + /* Insert the value at the end. */ + maps_by_address[nr_maps] = map__get(new); ++ map__set_kmap_maps(new, maps); + if (maps_by_name) + maps_by_name[nr_maps] = map__get(new); + +@@ -502,8 +503,6 @@ static int __maps__insert(struct maps *maps, struct map *new) + if (map__end(new) < map__start(new)) + RC_CHK_ACCESS(maps)->ends_broken = true; + +- map__set_kmap_maps(new, maps); +- + return 0; + } + +@@ -891,6 +890,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + if (before) { + map__put(maps_by_address[i]); + maps_by_address[i] = before; ++ map__set_kmap_maps(before, maps); + + if (maps_by_name) { + map__put(maps_by_name[ni]); +@@ -918,6 +918,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + */ + map__put(maps_by_address[i]); + maps_by_address[i] = map__get(new); ++ map__set_kmap_maps(new, maps); + + if (maps_by_name) { + map__put(maps_by_name[ni]); +@@ -942,14 +943,13 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + */ + map__put(maps_by_address[i]); + maps_by_address[i] = map__get(new); ++ map__set_kmap_maps(new, maps); + + if (maps_by_name) { + map__put(maps_by_name[ni]); + maps_by_name[ni] = map__get(new); + } + +- map__set_kmap_maps(new, maps); +- + check_invariants(maps); + return err; + } +@@ -1019,6 +1019,7 @@ int maps__copy_from(struct maps *dest, struct maps *parent) + err = unwind__prepare_access(dest, new, NULL); + if (!err) { + dest_maps_by_address[i] = new; ++ map__set_kmap_maps(new, dest); + if (dest_maps_by_name) + dest_maps_by_name[i] = map__get(new); + RC_CHK_ACCESS(dest)->nr_maps = i + 1; +diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c +index 4f07ac9fa207cb..b148cadb96d0b7 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c ++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c +@@ -1093,6 +1093,7 @@ int main_loop_s(int listensock) + struct pollfd polls; + socklen_t salen; + int remotesock; ++ int err = 0; + int fd = 0; + + again: +@@ -1125,7 +1126,7 @@ int main_loop_s(int listensock) + SOCK_TEST_TCPULP(remotesock, 0); + + memset(&winfo, 0, sizeof(winfo)); +- copyfd_io(fd, remotesock, 1, true, &winfo); ++ err = copyfd_io(fd, remotesock, 1, true, &winfo); + } else { + perror("accept"); + return 1; +@@ -1134,10 +1135,10 @@ int main_loop_s(int listensock) + if (cfg_input) + close(fd); + +- if (--cfg_repeat > 0) ++ if (!err && --cfg_repeat > 0) + goto again; + +- return 0; ++ return err; + } + + static void init_rng(void) +@@ -1247,7 +1248,7 @@ void xdisconnect(int fd) + else + xerror("bad family"); + +- strcpy(cmd, "ss -M | grep -q "); ++ strcpy(cmd, "ss -Mnt | grep -q "); + cmdlen = strlen(cmd); + if (!inet_ntop(addr.ss_family, raw_addr, &cmd[cmdlen], + sizeof(cmd) - cmdlen)) +@@ -1257,7 +1258,7 @@ void xdisconnect(int fd) + + /* + * wait until the pending data is completely flushed and all +- * the MPTCP sockets reached the closed status. ++ * the sockets reached the closed status. + * disconnect will bypass/ignore/drop any pending data. + */ + for (i = 0; ; i += msec_sleep) { +diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +index e934dd26a59d9b..112c07c4c37a3c 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c ++++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +@@ -667,22 +667,26 @@ static void process_one_client(int fd, int pipefd) + + do_getsockopts(&s, fd, ret, ret2); + if (s.mptcpi_rcv_delta != (uint64_t)ret + 1) +- xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); ++ xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64 ", diff %" PRId64, ++ s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - (ret + 1)); + + /* be nice when running on top of older kernel */ + if (s.pkt_stats_avail) { + if (s.last_sample.mptcpi_bytes_sent != ret2) +- xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64, ++ xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64 ++ ", diff %" PRId64, + s.last_sample.mptcpi_bytes_sent, ret2, + s.last_sample.mptcpi_bytes_sent - ret2); + if (s.last_sample.mptcpi_bytes_received != ret) +- xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64, ++ xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64 ++ ", diff %" PRId64, + s.last_sample.mptcpi_bytes_received, ret, + s.last_sample.mptcpi_bytes_received - ret); + if (s.last_sample.mptcpi_bytes_acked != ret) +- xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64, +- s.last_sample.mptcpi_bytes_acked, ret2, +- s.last_sample.mptcpi_bytes_acked - ret2); ++ xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64 ++ ", diff %" PRId64, ++ s.last_sample.mptcpi_bytes_acked, ret, ++ s.last_sample.mptcpi_bytes_acked - ret); + } + + close(fd); +diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +index 994a556f46c151..93fea3442216c8 100644 +--- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c ++++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +@@ -188,6 +188,13 @@ static int capture_events(int fd, int event_group) + fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE) + fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs)); ++ else if (attrs->rta_type == MPTCP_ATTR_FLAGS) { ++ __u16 flags = *(__u16 *)RTA_DATA(attrs); ++ ++ /* only print when present, easier */ ++ if (flags & MPTCP_PM_EV_FLAG_DENY_JOIN_ID0) ++ fprintf(stderr, ",deny_join_id0:1"); ++ } + + attrs = RTA_NEXT(attrs, msg_len); + } +diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh +index 333064b0b5ac03..97819e18578f4d 100755 +--- a/tools/testing/selftests/net/mptcp/userspace_pm.sh ++++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh +@@ -201,6 +201,9 @@ make_connection() + is_v6="v4" + fi + ++ # set this on the client side only: will not affect the rest ++ ip netns exec "$ns2" sysctl -q net.mptcp.allow_join_initial_addr_port=0 ++ + :>"$client_evts" + :>"$server_evts" + +@@ -223,23 +226,28 @@ make_connection() + local client_token + local client_port + local client_serverside ++ local client_nojoin + local server_token + local server_serverside ++ local server_nojoin + + client_token=$(mptcp_lib_evts_get_info token "$client_evts") + client_port=$(mptcp_lib_evts_get_info sport "$client_evts") + client_serverside=$(mptcp_lib_evts_get_info server_side "$client_evts") ++ client_nojoin=$(mptcp_lib_evts_get_info deny_join_id0 "$client_evts") + server_token=$(mptcp_lib_evts_get_info token "$server_evts") + server_serverside=$(mptcp_lib_evts_get_info server_side "$server_evts") ++ server_nojoin=$(mptcp_lib_evts_get_info deny_join_id0 "$server_evts") + + print_test "Established IP${is_v6} MPTCP Connection ns2 => ns1" +- if [ "$client_token" != "" ] && [ "$server_token" != "" ] && [ "$client_serverside" = 0 ] && +- [ "$server_serverside" = 1 ] ++ if [ "${client_token}" != "" ] && [ "${server_token}" != "" ] && ++ [ "${client_serverside}" = 0 ] && [ "${server_serverside}" = 1 ] && ++ [ "${client_nojoin:-0}" = 0 ] && [ "${server_nojoin:-0}" = 1 ] + then + test_pass + print_title "Connection info: ${client_addr}:${client_port} -> ${connect_addr}:${app_port}" + else +- test_fail "Expected tokens (c:${client_token} - s:${server_token}) and server (c:${client_serverside} - s:${server_serverside})" ++ test_fail "Expected tokens (c:${client_token} - s:${server_token}), server (c:${client_serverside} - s:${server_serverside}), nojoin (c:${client_nojoin} - s:${server_nojoin})" + mptcp_lib_result_print_all_tap + exit ${KSFT_FAIL} + fi