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 419BC158091 for ; Fri, 27 Jun 2025 11:17:13 +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 1CE02340E13 for ; Fri, 27 Jun 2025 11:17:13 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id 9F20A11055B; Fri, 27 Jun 2025 11:17:10 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.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 8E48F11055B for ; Fri, 27 Jun 2025 11:17:10 +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) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 4A1FD340E13 for ; Fri, 27 Jun 2025 11:17:09 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id DAB1C2A80 for ; Fri, 27 Jun 2025 11:17:07 +0000 (UTC) From: "Mike Pagano" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Pagano" Message-ID: <1751023013.36e39a5f6ac91aa1bf8fb9910a76bd73add9feef.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.15 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1003_linux-6.15.4.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: 36e39a5f6ac91aa1bf8fb9910a76bd73add9feef X-VCS-Branch: 6.15 Date: Fri, 27 Jun 2025 11:17:07 +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: 52bd1056-5942-4a4a-9c09-998616b67a6f X-Archives-Hash: 6c4c593cfaa317c9861cfbf8d0c73985 commit: 36e39a5f6ac91aa1bf8fb9910a76bd73add9feef Author: Mike Pagano gentoo org> AuthorDate: Fri Jun 27 11:16:53 2025 +0000 Commit: Mike Pagano gentoo org> CommitDate: Fri Jun 27 11:16:53 2025 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=36e39a5f Linux patch 6.15.4 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1003_linux-6.15.4.patch | 24203 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 24207 insertions(+) diff --git a/0000_README b/0000_README index 2eed9e1f..703fe152 100644 --- a/0000_README +++ b/0000_README @@ -54,6 +54,10 @@ Patch: 1002_linux-6.15.3.patch From: https://www.kernel.org Desc: Linux 6.15.3 +Patch: 1003_linux-6.15.4.patch +From: https://www.kernel.org +Desc: Linux 6.15.4 + 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/1003_linux-6.15.4.patch b/1003_linux-6.15.4.patch new file mode 100644 index 00000000..996196dd --- /dev/null +++ b/1003_linux-6.15.4.patch @@ -0,0 +1,24203 @@ +diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.yaml b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.yaml +index b57ae6963e6298..6b6f6762d122f9 100644 +--- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.yaml ++++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.yaml +@@ -97,7 +97,10 @@ properties: + + resets: + items: +- - description: module reset ++ - description: ++ Module reset. This property is optional for controllers in Tegra194, ++ Tegra234 etc where an internal software reset is available as an ++ alternative. + + reset-names: + items: +@@ -116,6 +119,13 @@ properties: + - const: rx + - const: tx + ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ + allOf: + - $ref: /schemas/i2c/i2c-controller.yaml + - if: +@@ -169,6 +179,18 @@ allOf: + properties: + power-domains: false + ++ - if: ++ not: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - nvidia,tegra194-i2c ++ then: ++ required: ++ - resets ++ - reset-names ++ + unevaluatedProperties: false + + examples: +diff --git a/Documentation/gpu/nouveau.rst b/Documentation/gpu/nouveau.rst +index 0f34131ccc2788..cab2e81013bc5f 100644 +--- a/Documentation/gpu/nouveau.rst ++++ b/Documentation/gpu/nouveau.rst +@@ -25,5 +25,8 @@ providing a consistent API to upper layers of the driver stack. + GSP Support + ------------------------ + +-.. kernel-doc:: drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c ++.. kernel-doc:: drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c + :doc: GSP message queue element ++ ++.. kernel-doc:: drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h ++ :doc: GSP message handling policy +diff --git a/Makefile b/Makefile +index 01ddb4eb3659f4..c1bde4eef2bfb2 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 15 +-SUBLEVEL = 3 ++SUBLEVEL = 4 + EXTRAVERSION = + NAME = Baby Opossum Posse + +diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h +index c36fb27212615a..86a2f9e5d0ef9d 100644 +--- a/arch/arm/mach-omap2/clockdomain.h ++++ b/arch/arm/mach-omap2/clockdomain.h +@@ -48,6 +48,7 @@ + #define CLKDM_NO_AUTODEPS (1 << 4) + #define CLKDM_ACTIVE_WITH_MPU (1 << 5) + #define CLKDM_MISSING_IDLE_REPORTING (1 << 6) ++#define CLKDM_STANDBY_FORCE_WAKEUP BIT(7) + + #define CLKDM_CAN_HWSUP (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO) + #define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP) +diff --git a/arch/arm/mach-omap2/clockdomains33xx_data.c b/arch/arm/mach-omap2/clockdomains33xx_data.c +index 87f4e927eb1830..c05a3c07d44863 100644 +--- a/arch/arm/mach-omap2/clockdomains33xx_data.c ++++ b/arch/arm/mach-omap2/clockdomains33xx_data.c +@@ -19,7 +19,7 @@ static struct clockdomain l4ls_am33xx_clkdm = { + .pwrdm = { .name = "per_pwrdm" }, + .cm_inst = AM33XX_CM_PER_MOD, + .clkdm_offs = AM33XX_CM_PER_L4LS_CLKSTCTRL_OFFSET, +- .flags = CLKDM_CAN_SWSUP, ++ .flags = CLKDM_CAN_SWSUP | CLKDM_STANDBY_FORCE_WAKEUP, + }; + + static struct clockdomain l3s_am33xx_clkdm = { +diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c +index acdf72a541c02a..a4dd42abda89b0 100644 +--- a/arch/arm/mach-omap2/cm33xx.c ++++ b/arch/arm/mach-omap2/cm33xx.c +@@ -20,6 +20,9 @@ + #include "cm-regbits-34xx.h" + #include "cm-regbits-33xx.h" + #include "prm33xx.h" ++#if IS_ENABLED(CONFIG_SUSPEND) ++#include ++#endif + + /* + * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield: +@@ -328,8 +331,17 @@ static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm) + { + bool hwsup = false; + ++#if IS_ENABLED(CONFIG_SUSPEND) ++ /* ++ * In case of standby, Don't put the l4ls clk domain to sleep. ++ * Since CM3 PM FW doesn't wake-up/enable the l4ls clk domain ++ * upon wake-up, CM3 PM FW fails to wake-up th MPU. ++ */ ++ if (pm_suspend_target_state == PM_SUSPEND_STANDBY && ++ (clkdm->flags & CLKDM_STANDBY_FORCE_WAKEUP)) ++ return 0; ++#endif + hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs); +- + if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) + am33xx_clkdm_sleep(clkdm); + +diff --git a/arch/arm/mach-omap2/pmic-cpcap.c b/arch/arm/mach-omap2/pmic-cpcap.c +index 4f31e61c0c90ca..9f9a20274db848 100644 +--- a/arch/arm/mach-omap2/pmic-cpcap.c ++++ b/arch/arm/mach-omap2/pmic-cpcap.c +@@ -264,7 +264,11 @@ int __init omap4_cpcap_init(void) + + static int __init cpcap_late_init(void) + { +- omap4_vc_set_pmic_signaling(PWRDM_POWER_RET); ++ if (!of_find_compatible_node(NULL, NULL, "motorola,cpcap")) ++ return 0; ++ ++ if (soc_is_omap443x() || soc_is_omap446x() || soc_is_omap447x()) ++ omap4_vc_set_pmic_signaling(PWRDM_POWER_RET); + + return 0; + } +diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c +index 748698e91a4b46..27e64f782cb3dc 100644 +--- a/arch/arm/mm/ioremap.c ++++ b/arch/arm/mm/ioremap.c +@@ -515,7 +515,5 @@ void __init early_ioremap_init(void) + bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, + unsigned long flags) + { +- unsigned long pfn = PHYS_PFN(offset); +- +- return memblock_is_map_memory(pfn); ++ return memblock_is_map_memory(offset); + } +diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h +index eba1a98657f132..aa9efee17277d4 100644 +--- a/arch/arm64/include/asm/tlbflush.h ++++ b/arch/arm64/include/asm/tlbflush.h +@@ -323,13 +323,14 @@ static inline bool arch_tlbbatch_should_defer(struct mm_struct *mm) + } + + /* +- * If mprotect/munmap/etc occurs during TLB batched flushing, we need to +- * synchronise all the TLBI issued with a DSB to avoid the race mentioned in +- * flush_tlb_batched_pending(). ++ * If mprotect/munmap/etc occurs during TLB batched flushing, we need to ensure ++ * all the previously issued TLBIs targeting mm have completed. But since we ++ * can be executing on a remote CPU, a DSB cannot guarantee this like it can ++ * for arch_tlbbatch_flush(). Our only option is to flush the entire mm. + */ + static inline void arch_flush_tlb_batched_pending(struct mm_struct *mm) + { +- dsb(ish); ++ flush_tlb_mm(mm); + } + + /* +diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c +index f79b0d5f71ac94..f8345c39c70541 100644 +--- a/arch/arm64/kernel/ptrace.c ++++ b/arch/arm64/kernel/ptrace.c +@@ -141,7 +141,7 @@ unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) + + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) +- return *addr; ++ return READ_ONCE_NOCHECK(*addr); + else + return 0; + } +diff --git a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h +index 502a5b73ee70c2..73881e1dc26794 100644 +--- a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h ++++ b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h +@@ -167,6 +167,9 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu) + + __debug_save_state(guest_dbg, guest_ctxt); + __debug_restore_state(host_dbg, host_ctxt); ++ ++ if (has_vhe()) ++ isb(); + } + + #endif /* __ARM64_KVM_HYP_DEBUG_SR_H__ */ +diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c +index ea6695d53fb967..5a9bf291c649b4 100644 +--- a/arch/arm64/mm/mmu.c ++++ b/arch/arm64/mm/mmu.c +@@ -1286,7 +1286,8 @@ int pud_free_pmd_page(pud_t *pudp, unsigned long addr) + next = addr; + end = addr + PUD_SIZE; + do { +- pmd_free_pte_page(pmdp, next); ++ if (pmd_present(pmdp_get(pmdp))) ++ pmd_free_pte_page(pmdp, next); + } while (pmdp++, next += PMD_SIZE, next != end); + + pud_clear(pudp); +diff --git a/arch/loongarch/include/asm/irqflags.h b/arch/loongarch/include/asm/irqflags.h +index 319a8c616f1f5b..003172b8406be7 100644 +--- a/arch/loongarch/include/asm/irqflags.h ++++ b/arch/loongarch/include/asm/irqflags.h +@@ -14,40 +14,48 @@ + static inline void arch_local_irq_enable(void) + { + u32 flags = CSR_CRMD_IE; ++ register u32 mask asm("t0") = CSR_CRMD_IE; ++ + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) +- : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) ++ : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + } + + static inline void arch_local_irq_disable(void) + { + u32 flags = 0; ++ register u32 mask asm("t0") = CSR_CRMD_IE; ++ + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) +- : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) ++ : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + } + + static inline unsigned long arch_local_irq_save(void) + { + u32 flags = 0; ++ register u32 mask asm("t0") = CSR_CRMD_IE; ++ + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) +- : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) ++ : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + return flags; + } + + static inline void arch_local_irq_restore(unsigned long flags) + { ++ register u32 mask asm("t0") = CSR_CRMD_IE; ++ + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) +- : [mask] "r" (CSR_CRMD_IE), [reg] "i" (LOONGARCH_CSR_CRMD) ++ : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); + } + +diff --git a/arch/loongarch/include/asm/vdso/getrandom.h b/arch/loongarch/include/asm/vdso/getrandom.h +index 48c43f55b039b4..a81724b69f291e 100644 +--- a/arch/loongarch/include/asm/vdso/getrandom.h ++++ b/arch/loongarch/include/asm/vdso/getrandom.h +@@ -20,7 +20,7 @@ static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, uns + + asm volatile( + " syscall 0\n" +- : "+r" (ret) ++ : "=r" (ret) + : "r" (nr), "r" (buffer), "r" (len), "r" (flags) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", + "memory"); +diff --git a/arch/loongarch/include/asm/vdso/gettimeofday.h b/arch/loongarch/include/asm/vdso/gettimeofday.h +index 88cfcf13311630..f15503e3336ca1 100644 +--- a/arch/loongarch/include/asm/vdso/gettimeofday.h ++++ b/arch/loongarch/include/asm/vdso/gettimeofday.h +@@ -25,7 +25,7 @@ static __always_inline long gettimeofday_fallback( + + asm volatile( + " syscall 0\n" +- : "+r" (ret) ++ : "=r" (ret) + : "r" (nr), "r" (tv), "r" (tz) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); +@@ -44,7 +44,7 @@ static __always_inline long clock_gettime_fallback( + + asm volatile( + " syscall 0\n" +- : "+r" (ret) ++ : "=r" (ret) + : "r" (nr), "r" (clkid), "r" (ts) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); +@@ -63,7 +63,7 @@ static __always_inline int clock_getres_fallback( + + asm volatile( + " syscall 0\n" +- : "+r" (ret) ++ : "=r" (ret) + : "r" (nr), "r" (clkid), "r" (ts) + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$t8", "memory"); +diff --git a/arch/loongarch/mm/hugetlbpage.c b/arch/loongarch/mm/hugetlbpage.c +index cea84d7f2b91a1..02dad4624fe329 100644 +--- a/arch/loongarch/mm/hugetlbpage.c ++++ b/arch/loongarch/mm/hugetlbpage.c +@@ -47,7 +47,8 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, + pmd = pmd_offset(pud, addr); + } + } +- return pmd_none(pmdp_get(pmd)) ? NULL : (pte_t *) pmd; ++ ++ return (!pmd || pmd_none(pmdp_get(pmd))) ? NULL : (pte_t *) pmd; + } + + uint64_t pmd_to_entrylo(unsigned long pmd_val) +diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile +index fb4c493aaffa90..69d4593f64fee5 100644 +--- a/arch/mips/vdso/Makefile ++++ b/arch/mips/vdso/Makefile +@@ -27,6 +27,7 @@ endif + # offsets. + cflags-vdso := $(ccflags-vdso) \ + $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ ++ $(filter -std=%,$(KBUILD_CFLAGS)) \ + -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ + -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \ + -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ +diff --git a/arch/nios2/include/asm/pgtable.h b/arch/nios2/include/asm/pgtable.h +index eab87c6beacb5a..e5d64c84aadf7d 100644 +--- a/arch/nios2/include/asm/pgtable.h ++++ b/arch/nios2/include/asm/pgtable.h +@@ -291,4 +291,20 @@ void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma, + #define update_mmu_cache(vma, addr, ptep) \ + update_mmu_cache_range(NULL, vma, addr, ptep, 1) + ++static inline int pte_same(pte_t pte_a, pte_t pte_b); ++ ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++static inline int ptep_set_access_flags(struct vm_area_struct *vma, ++ unsigned long address, pte_t *ptep, ++ pte_t entry, int dirty) ++{ ++ if (!pte_same(*ptep, entry)) ++ set_ptes(vma->vm_mm, address, ptep, entry, 1); ++ /* ++ * update_mmu_cache will unconditionally execute, handling both ++ * the case that the PTE changed and the spurious fault case. ++ */ ++ return true; ++} ++ + #endif /* _ASM_NIOS2_PGTABLE_H */ +diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile +index 92227fa813dc34..17c42d718eb336 100644 +--- a/arch/parisc/boot/compressed/Makefile ++++ b/arch/parisc/boot/compressed/Makefile +@@ -18,6 +18,7 @@ KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os + ifndef CONFIG_64BIT + KBUILD_CFLAGS += -mfast-indirect-calls + endif ++KBUILD_CFLAGS += -std=gnu11 + + LDFLAGS_vmlinux := -X -e startup --as-needed -T + $(obj)/vmlinux: $(obj)/vmlinux.lds $(addprefix $(obj)/, $(OBJECTS)) $(LIBGCC) FORCE +diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c +index f4626943633adc..00e97204783eda 100644 +--- a/arch/parisc/kernel/unaligned.c ++++ b/arch/parisc/kernel/unaligned.c +@@ -25,7 +25,7 @@ + #define DPRINTF(fmt, args...) + #endif + +-#define RFMT "%#08lx" ++#define RFMT "0x%08lx" + + /* 1111 1100 0000 0000 0001 0011 1100 0000 */ + #define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) +diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h +index 02897f4b0dbf81..b891910fce8a69 100644 +--- a/arch/powerpc/include/asm/ppc_asm.h ++++ b/arch/powerpc/include/asm/ppc_asm.h +@@ -183,7 +183,7 @@ + /* + * Used to name C functions called from asm + */ +-#ifdef CONFIG_PPC_KERNEL_PCREL ++#if defined(__powerpc64__) && defined(CONFIG_PPC_KERNEL_PCREL) + #define CFUNC(name) name@notoc + #else + #define CFUNC(name) name +diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c +index 83fe99861eb178..ca7f7bb2b47869 100644 +--- a/arch/powerpc/kernel/eeh.c ++++ b/arch/powerpc/kernel/eeh.c +@@ -1509,6 +1509,8 @@ int eeh_pe_configure(struct eeh_pe *pe) + /* Invalid PE ? */ + if (!pe) + return -ENODEV; ++ else ++ ret = eeh_ops->configure_bridge(pe); + + return ret; + } +diff --git a/arch/powerpc/kernel/trace/ftrace_entry.S b/arch/powerpc/kernel/trace/ftrace_entry.S +index 2c1b24100eca29..3565c67fc63859 100644 +--- a/arch/powerpc/kernel/trace/ftrace_entry.S ++++ b/arch/powerpc/kernel/trace/ftrace_entry.S +@@ -212,10 +212,10 @@ + bne- 1f + + mr r3, r15 ++1: mtlr r3 + .if \allregs == 0 + REST_GPR(15, r1) + .endif +-1: mtlr r3 + #endif + + /* Restore gprs */ +diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile +index e8824f93332610..8834dfe9d72796 100644 +--- a/arch/powerpc/kernel/vdso/Makefile ++++ b/arch/powerpc/kernel/vdso/Makefile +@@ -53,7 +53,7 @@ ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WAR + ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) + + CC32FLAGS := -m32 +-CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc ++CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc -mpcrel + ifdef CONFIG_CC_IS_CLANG + # This flag is supported by clang for 64-bit but not 32-bit so it will cause + # an unused command line flag warning for this file. +diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h +index 6beacaec63d303..4c26912c2e3c36 100644 +--- a/arch/powerpc/net/bpf_jit.h ++++ b/arch/powerpc/net/bpf_jit.h +@@ -51,8 +51,16 @@ + EMIT(PPC_INST_BRANCH_COND | (((cond) & 0x3ff) << 16) | (offset & 0xfffc)); \ + } while (0) + +-/* Sign-extended 32-bit immediate load */ ++/* ++ * Sign-extended 32-bit immediate load ++ * ++ * If this is a dummy pass (!image), account for ++ * maximum possible instructions. ++ */ + #define PPC_LI32(d, i) do { \ ++ if (!image) \ ++ ctx->idx += 2; \ ++ else { \ + if ((int)(uintptr_t)(i) >= -32768 && \ + (int)(uintptr_t)(i) < 32768) \ + EMIT(PPC_RAW_LI(d, i)); \ +@@ -60,10 +68,15 @@ + EMIT(PPC_RAW_LIS(d, IMM_H(i))); \ + if (IMM_L(i)) \ + EMIT(PPC_RAW_ORI(d, d, IMM_L(i))); \ +- } } while(0) ++ } \ ++ } } while (0) + + #ifdef CONFIG_PPC64 ++/* If dummy pass (!image), account for maximum possible instructions */ + #define PPC_LI64(d, i) do { \ ++ if (!image) \ ++ ctx->idx += 5; \ ++ else { \ + if ((long)(i) >= -2147483648 && \ + (long)(i) < 2147483648) \ + PPC_LI32(d, i); \ +@@ -84,7 +97,8 @@ + if ((uintptr_t)(i) & 0x000000000000ffffULL) \ + EMIT(PPC_RAW_ORI(d, d, (uintptr_t)(i) & \ + 0xffff)); \ +- } } while (0) ++ } \ ++ } } while (0) + #define PPC_LI_ADDR PPC_LI64 + + #ifndef CONFIG_PPC_KERNEL_PCREL +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 2991bb171a9bbe..c0684733e9d6ac 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -504,10 +504,11 @@ static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ct + EMIT(PPC_RAW_ADDI(_R3, _R1, regs_off)); + if (!p->jited) + PPC_LI_ADDR(_R4, (unsigned long)p->insnsi); +- if (!create_branch(&branch_insn, (u32 *)&ro_image[ctx->idx], (unsigned long)p->bpf_func, +- BRANCH_SET_LINK)) { +- if (image) +- image[ctx->idx] = ppc_inst_val(branch_insn); ++ /* Account for max possible instructions during dummy pass for size calculation */ ++ if (image && !create_branch(&branch_insn, (u32 *)&ro_image[ctx->idx], ++ (unsigned long)p->bpf_func, ++ BRANCH_SET_LINK)) { ++ image[ctx->idx] = ppc_inst_val(branch_insn); + ctx->idx++; + } else { + EMIT(PPC_RAW_LL(_R12, _R25, offsetof(struct bpf_prog, bpf_func))); +@@ -889,7 +890,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im + bpf_trampoline_restore_tail_call_cnt(image, ctx, func_frame_offset, r4_off); + + /* Reserve space to patch branch instruction to skip fexit progs */ +- im->ip_after_call = &((u32 *)ro_image)[ctx->idx]; ++ if (ro_image) /* image is NULL for dummy pass */ ++ im->ip_after_call = &((u32 *)ro_image)[ctx->idx]; + EMIT(PPC_RAW_NOP()); + } + +@@ -912,7 +914,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im + } + + if (flags & BPF_TRAMP_F_CALL_ORIG) { +- im->ip_epilogue = &((u32 *)ro_image)[ctx->idx]; ++ if (ro_image) /* image is NULL for dummy pass */ ++ im->ip_epilogue = &((u32 *)ro_image)[ctx->idx]; + PPC_LI_ADDR(_R3, im); + ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx, + (unsigned long)__bpf_tramp_exit); +@@ -973,25 +976,9 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) + { + struct bpf_tramp_image im; +- void *image; + int ret; + +- /* +- * Allocate a temporary buffer for __arch_prepare_bpf_trampoline(). +- * This will NOT cause fragmentation in direct map, as we do not +- * call set_memory_*() on this buffer. +- * +- * We cannot use kvmalloc here, because we need image to be in +- * module memory range. +- */ +- image = bpf_jit_alloc_exec(PAGE_SIZE); +- if (!image) +- return -ENOMEM; +- +- ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, image, +- m, flags, tlinks, func_addr); +- bpf_jit_free_exec(image); +- ++ ret = __arch_prepare_bpf_trampoline(&im, NULL, NULL, NULL, m, flags, tlinks, func_addr); + return ret; + } + +diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c +index c4db278dae3609..0aace304dfe191 100644 +--- a/arch/powerpc/net/bpf_jit_comp32.c ++++ b/arch/powerpc/net/bpf_jit_comp32.c +@@ -313,7 +313,6 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code + u64 func_addr; + u32 true_cond; + u32 tmp_idx; +- int j; + + if (i && (BPF_CLASS(code) == BPF_ALU64 || BPF_CLASS(code) == BPF_ALU) && + (BPF_CLASS(prevcode) == BPF_ALU64 || BPF_CLASS(prevcode) == BPF_ALU) && +@@ -1099,13 +1098,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code + * 16 byte instruction that uses two 'struct bpf_insn' + */ + case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ +- tmp_idx = ctx->idx; + PPC_LI32(dst_reg_h, (u32)insn[i + 1].imm); + PPC_LI32(dst_reg, (u32)insn[i].imm); +- /* padding to allow full 4 instructions for later patching */ +- if (!image) +- for (j = ctx->idx - tmp_idx; j < 4; j++) +- EMIT(PPC_RAW_NOP()); + /* Adjust for two bpf instructions */ + addrs[++i] = ctx->idx * 4; + break; +diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c +index 233703b06d7c97..5daa77aee7f720 100644 +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -227,7 +227,14 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context * + #ifdef CONFIG_PPC_KERNEL_PCREL + reladdr = func_addr - local_paca->kernelbase; + +- if (reladdr < (long)SZ_8G && reladdr >= -(long)SZ_8G) { ++ /* ++ * If fimage is NULL (the initial pass to find image size), ++ * account for the maximum no. of instructions possible. ++ */ ++ if (!fimage) { ++ ctx->idx += 7; ++ return 0; ++ } else if (reladdr < (long)SZ_8G && reladdr >= -(long)SZ_8G) { + EMIT(PPC_RAW_LD(_R12, _R13, offsetof(struct paca_struct, kernelbase))); + /* Align for subsequent prefix instruction */ + if (!IS_ALIGNED((unsigned long)fimage + CTX_NIA(ctx), 8)) +@@ -412,7 +419,6 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code + u64 imm64; + u32 true_cond; + u32 tmp_idx; +- int j; + + /* + * addrs[] maps a BPF bytecode address into a real offset from +@@ -1046,12 +1052,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code + case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ + imm64 = ((u64)(u32) insn[i].imm) | + (((u64)(u32) insn[i+1].imm) << 32); +- tmp_idx = ctx->idx; + PPC_LI64(dst_reg, imm64); +- /* padding to allow full 5 instructions for later patching */ +- if (!image) +- for (j = ctx->idx - tmp_idx; j < 5; j++) +- EMIT(PPC_RAW_NOP()); + /* Adjust for two bpf instructions */ + addrs[++i] = ctx->idx * 4; + break; +diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c +index f9d80111c322f2..957c0c03d25904 100644 +--- a/arch/powerpc/platforms/pseries/msi.c ++++ b/arch/powerpc/platforms/pseries/msi.c +@@ -525,7 +525,12 @@ static struct msi_domain_info pseries_msi_domain_info = { + + static void pseries_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) + { +- __pci_read_msi_msg(irq_data_get_msi_desc(data), msg); ++ struct pci_dev *dev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data)); ++ ++ if (dev->current_state == PCI_D0) ++ __pci_read_msi_msg(irq_data_get_msi_desc(data), msg); ++ else ++ get_cached_msi_msg(data->irq, msg); + } + + static struct irq_chip pseries_msi_irq_chip = { +diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c +index 5fbf3f94f1e855..b17fad091babdc 100644 +--- a/arch/riscv/kvm/vcpu_sbi_replace.c ++++ b/arch/riscv/kvm/vcpu_sbi_replace.c +@@ -103,7 +103,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run + kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_FENCE_I_SENT); + break; + case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: +- if (cp->a2 == 0 && cp->a3 == 0) ++ if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL) + kvm_riscv_hfence_vvma_all(vcpu->kvm, hbase, hmask); + else + kvm_riscv_hfence_vvma_gva(vcpu->kvm, hbase, hmask, +@@ -111,7 +111,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run + kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_SENT); + break; + case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: +- if (cp->a2 == 0 && cp->a3 == 0) ++ if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL) + kvm_riscv_hfence_vvma_asid_all(vcpu->kvm, + hbase, hmask, cp->a4); + else +@@ -127,9 +127,9 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run + case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: + /* + * Until nested virtualization is implemented, the +- * SBI HFENCE calls should be treated as NOPs ++ * SBI HFENCE calls should return not supported ++ * hence fallthrough. + */ +- break; + default: + retdata->err_val = SBI_ERR_NOT_SUPPORTED; + } +diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c +index f6fded15633ad8..4e5654ad1604fd 100644 +--- a/arch/s390/kvm/gaccess.c ++++ b/arch/s390/kvm/gaccess.c +@@ -318,7 +318,7 @@ enum prot_type { + PROT_TYPE_DAT = 3, + PROT_TYPE_IEP = 4, + /* Dummy value for passing an initialized value when code != PGM_PROTECTION */ +- PROT_NONE, ++ PROT_TYPE_DUMMY, + }; + + static int trans_exc_ending(struct kvm_vcpu *vcpu, int code, unsigned long gva, u8 ar, +@@ -334,7 +334,7 @@ static int trans_exc_ending(struct kvm_vcpu *vcpu, int code, unsigned long gva, + switch (code) { + case PGM_PROTECTION: + switch (prot) { +- case PROT_NONE: ++ case PROT_TYPE_DUMMY: + /* We should never get here, acts like termination */ + WARN_ON_ONCE(1); + break; +@@ -804,7 +804,7 @@ static int guest_range_to_gpas(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, + gpa = kvm_s390_real_to_abs(vcpu, ga); + if (!kvm_is_gpa_in_memslot(vcpu->kvm, gpa)) { + rc = PGM_ADDRESSING; +- prot = PROT_NONE; ++ prot = PROT_TYPE_DUMMY; + } + } + if (rc) +@@ -962,7 +962,7 @@ int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, + if (rc == PGM_PROTECTION) + prot = PROT_TYPE_KEYC; + else +- prot = PROT_NONE; ++ prot = PROT_TYPE_DUMMY; + rc = trans_exc_ending(vcpu, rc, ga, ar, mode, prot, terminate); + } + out_unlock: +diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c +index 5bbdc4190b8b82..cd6676c2d6022d 100644 +--- a/arch/s390/pci/pci.c ++++ b/arch/s390/pci/pci.c +@@ -45,6 +45,7 @@ + /* list of all detected zpci devices */ + static LIST_HEAD(zpci_list); + static DEFINE_SPINLOCK(zpci_list_lock); ++static DEFINE_MUTEX(zpci_add_remove_lock); + + static DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE); + static DEFINE_SPINLOCK(zpci_domain_lock); +@@ -70,6 +71,15 @@ EXPORT_SYMBOL_GPL(zpci_aipb); + struct airq_iv *zpci_aif_sbv; + EXPORT_SYMBOL_GPL(zpci_aif_sbv); + ++void zpci_zdev_put(struct zpci_dev *zdev) ++{ ++ if (!zdev) ++ return; ++ mutex_lock(&zpci_add_remove_lock); ++ kref_put_lock(&zdev->kref, zpci_release_device, &zpci_list_lock); ++ mutex_unlock(&zpci_add_remove_lock); ++} ++ + struct zpci_dev *get_zdev_by_fid(u32 fid) + { + struct zpci_dev *tmp, *zdev = NULL; +@@ -837,6 +847,7 @@ int zpci_add_device(struct zpci_dev *zdev) + { + int rc; + ++ mutex_lock(&zpci_add_remove_lock); + zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", zdev->fid, zdev->fh, zdev->state); + rc = zpci_init_iommu(zdev); + if (rc) +@@ -850,12 +861,14 @@ int zpci_add_device(struct zpci_dev *zdev) + spin_lock(&zpci_list_lock); + list_add_tail(&zdev->entry, &zpci_list); + spin_unlock(&zpci_list_lock); ++ mutex_unlock(&zpci_add_remove_lock); + return 0; + + error_destroy_iommu: + zpci_destroy_iommu(zdev); + error: + zpci_dbg(0, "add fid:%x, rc:%d\n", zdev->fid, rc); ++ mutex_unlock(&zpci_add_remove_lock); + return rc; + } + +@@ -925,21 +938,20 @@ int zpci_deconfigure_device(struct zpci_dev *zdev) + * @zdev: the zpci_dev that was reserved + * + * Handle the case that a given zPCI function was reserved by another system. +- * After a call to this function the zpci_dev can not be found via +- * get_zdev_by_fid() anymore but may still be accessible via existing +- * references though it will not be functional anymore. + */ + void zpci_device_reserved(struct zpci_dev *zdev) + { +- /* +- * Remove device from zpci_list as it is going away. This also +- * makes sure we ignore subsequent zPCI events for this device. +- */ +- spin_lock(&zpci_list_lock); +- list_del(&zdev->entry); +- spin_unlock(&zpci_list_lock); ++ lockdep_assert_held(&zdev->state_lock); ++ /* We may declare the device reserved multiple times */ ++ if (zdev->state == ZPCI_FN_STATE_RESERVED) ++ return; + zdev->state = ZPCI_FN_STATE_RESERVED; + zpci_dbg(3, "rsv fid:%x\n", zdev->fid); ++ /* ++ * The underlying device is gone. Allow the zdev to be freed ++ * as soon as all other references are gone by accounting for ++ * the removal as a dropped reference. ++ */ + zpci_zdev_put(zdev); + } + +@@ -947,13 +959,14 @@ void zpci_release_device(struct kref *kref) + { + struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref); + ++ lockdep_assert_held(&zpci_add_remove_lock); + WARN_ON(zdev->state != ZPCI_FN_STATE_RESERVED); +- +- if (zdev->zbus->bus) +- zpci_bus_remove_device(zdev, false); +- +- if (zdev_enabled(zdev)) +- zpci_disable_device(zdev); ++ /* ++ * We already hold zpci_list_lock thanks to kref_put_lock(). ++ * This makes sure no new reference can be taken from the list. ++ */ ++ list_del(&zdev->entry); ++ spin_unlock(&zpci_list_lock); + + if (zdev->has_hp_slot) + zpci_exit_slot(zdev); +diff --git a/arch/s390/pci/pci_bus.h b/arch/s390/pci/pci_bus.h +index e86a9419d233f7..ae3d7a9159bde1 100644 +--- a/arch/s390/pci/pci_bus.h ++++ b/arch/s390/pci/pci_bus.h +@@ -21,11 +21,8 @@ int zpci_bus_scan_device(struct zpci_dev *zdev); + void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error); + + void zpci_release_device(struct kref *kref); +-static inline void zpci_zdev_put(struct zpci_dev *zdev) +-{ +- if (zdev) +- kref_put(&zdev->kref, zpci_release_device); +-} ++ ++void zpci_zdev_put(struct zpci_dev *zdev); + + static inline void zpci_zdev_get(struct zpci_dev *zdev) + { +diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c +index 7bd7721c1239a2..2fbee3887d13aa 100644 +--- a/arch/s390/pci/pci_event.c ++++ b/arch/s390/pci/pci_event.c +@@ -335,6 +335,22 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh) + zdev->state = ZPCI_FN_STATE_STANDBY; + } + ++static void zpci_event_reappear(struct zpci_dev *zdev) ++{ ++ lockdep_assert_held(&zdev->state_lock); ++ /* ++ * The zdev is in the reserved state. This means that it was presumed to ++ * go away but there are still undropped references. Now, the platform ++ * announced its availability again. Bring back the lingering zdev ++ * to standby. This is safe because we hold a temporary reference ++ * now so that it won't go away. Account for the re-appearance of the ++ * underlying device by incrementing the reference count. ++ */ ++ zdev->state = ZPCI_FN_STATE_STANDBY; ++ zpci_zdev_get(zdev); ++ zpci_dbg(1, "rea fid:%x, fh:%x\n", zdev->fid, zdev->fh); ++} ++ + static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) + { + struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); +@@ -358,8 +374,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) + break; + } + } else { ++ if (zdev->state == ZPCI_FN_STATE_RESERVED) ++ zpci_event_reappear(zdev); + /* the configuration request may be stale */ +- if (zdev->state != ZPCI_FN_STATE_STANDBY) ++ else if (zdev->state != ZPCI_FN_STATE_STANDBY) + break; + zdev->state = ZPCI_FN_STATE_CONFIGURED; + } +@@ -375,6 +393,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) + break; + } + } else { ++ if (zdev->state == ZPCI_FN_STATE_RESERVED) ++ zpci_event_reappear(zdev); + zpci_update_fh(zdev, ccdf->fh); + } + break; +diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c +index 5fcc1a3b04bd0b..91e72b0044bc04 100644 +--- a/arch/s390/pci/pci_mmio.c ++++ b/arch/s390/pci/pci_mmio.c +@@ -236,7 +236,7 @@ static inline int __pcilg_mio_inuser( + : [ioaddr_len] "+&d" (ioaddr_len.pair), [exc] "+d" (exception), + CC_OUT(cc, cc), [val] "=d" (val), + [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), +- [shift] "+d" (shift) ++ [shift] "+a" (shift) + : + : CC_CLOBBER_LIST("memory")); + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index e21cca404943e7..47932d5f44990a 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -88,7 +88,7 @@ config X86 + select ARCH_HAS_DMA_OPS if GART_IOMMU || XEN + select ARCH_HAS_EARLY_DEBUG if KGDB + select ARCH_HAS_ELF_RANDOMIZE +- select ARCH_HAS_EXECMEM_ROX if X86_64 ++ select ARCH_HAS_EXECMEM_ROX if X86_64 && STRICT_MODULE_RWX + select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FORTIFY_SOURCE + select ARCH_HAS_GCOV_PROFILE_ALL +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index c5f385413392b1..d69af2687ed73b 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -2810,7 +2810,7 @@ static void intel_pmu_read_event(struct perf_event *event) + * If the PEBS counters snapshotting is enabled, + * the topdown event is available in PEBS records. + */ +- if (is_topdown_event(event) && !is_pebs_counter_event_group(event)) ++ if (is_topdown_count(event) && !is_pebs_counter_event_group(event)) + static_call(intel_pmu_update_topdown_event)(event, NULL); + else + intel_pmu_drain_pebs_buffer(); +diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h +index e988bac0a4a1c3..3c2de4ce3b10de 100644 +--- a/arch/x86/include/asm/module.h ++++ b/arch/x86/include/asm/module.h +@@ -5,12 +5,20 @@ + #include + #include + ++struct its_array { ++#ifdef CONFIG_MITIGATION_ITS ++ void **pages; ++ int num; ++#endif ++}; ++ + struct mod_arch_specific { + #ifdef CONFIG_UNWINDER_ORC + unsigned int num_orcs; + int *orc_unwind_ip; + struct orc_entry *orc_unwind; + #endif ++ struct its_array its_pages; + }; + + #endif /* _ASM_X86_MODULE_H */ +diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h +index 4a1922ec80cf76..e70bb1f46e064c 100644 +--- a/arch/x86/include/asm/tdx.h ++++ b/arch/x86/include/asm/tdx.h +@@ -100,7 +100,7 @@ void tdx_init(void); + + typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args); + +-static inline u64 sc_retry(sc_func_t func, u64 fn, ++static __always_inline u64 sc_retry(sc_func_t func, u64 fn, + struct tdx_module_args *args) + { + int retry = RDRAND_RETRY_LOOPS; +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index 45bcff181cbae9..4dc21a34e67d65 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -138,6 +138,24 @@ static struct module *its_mod; + #endif + static void *its_page; + static unsigned int its_offset; ++struct its_array its_pages; ++ ++static void *__its_alloc(struct its_array *pages) ++{ ++ void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE); ++ if (!page) ++ return NULL; ++ ++ void *tmp = krealloc(pages->pages, (pages->num+1) * sizeof(void *), ++ GFP_KERNEL); ++ if (!tmp) ++ return NULL; ++ ++ pages->pages = tmp; ++ pages->pages[pages->num++] = page; ++ ++ return no_free_ptr(page); ++} + + /* Initialize a thunk with the "jmp *reg; int3" instructions. */ + static void *its_init_thunk(void *thunk, int reg) +@@ -173,6 +191,21 @@ static void *its_init_thunk(void *thunk, int reg) + return thunk + offset; + } + ++static void its_pages_protect(struct its_array *pages) ++{ ++ for (int i = 0; i < pages->num; i++) { ++ void *page = pages->pages[i]; ++ execmem_restore_rox(page, PAGE_SIZE); ++ } ++} ++ ++static void its_fini_core(void) ++{ ++ if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) ++ its_pages_protect(&its_pages); ++ kfree(its_pages.pages); ++} ++ + #ifdef CONFIG_MODULES + void its_init_mod(struct module *mod) + { +@@ -195,10 +228,8 @@ void its_fini_mod(struct module *mod) + its_page = NULL; + mutex_unlock(&text_mutex); + +- for (int i = 0; i < mod->its_num_pages; i++) { +- void *page = mod->its_page_array[i]; +- execmem_restore_rox(page, PAGE_SIZE); +- } ++ if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) ++ its_pages_protect(&mod->arch.its_pages); + } + + void its_free_mod(struct module *mod) +@@ -206,37 +237,33 @@ void its_free_mod(struct module *mod) + if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) + return; + +- for (int i = 0; i < mod->its_num_pages; i++) { +- void *page = mod->its_page_array[i]; ++ for (int i = 0; i < mod->arch.its_pages.num; i++) { ++ void *page = mod->arch.its_pages.pages[i]; + execmem_free(page); + } +- kfree(mod->its_page_array); ++ kfree(mod->arch.its_pages.pages); + } + #endif /* CONFIG_MODULES */ + + static void *its_alloc(void) + { +- void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE); +- +- if (!page) +- return NULL; ++ struct its_array *pages = &its_pages; ++ void *page; + + #ifdef CONFIG_MODULES +- if (its_mod) { +- void *tmp = krealloc(its_mod->its_page_array, +- (its_mod->its_num_pages+1) * sizeof(void *), +- GFP_KERNEL); +- if (!tmp) +- return NULL; ++ if (its_mod) ++ pages = &its_mod->arch.its_pages; ++#endif + +- its_mod->its_page_array = tmp; +- its_mod->its_page_array[its_mod->its_num_pages++] = page; ++ page = __its_alloc(pages); ++ if (!page) ++ return NULL; + +- execmem_make_temp_rw(page, PAGE_SIZE); +- } +-#endif /* CONFIG_MODULES */ ++ execmem_make_temp_rw(page, PAGE_SIZE); ++ if (pages == &its_pages) ++ set_memory_x((unsigned long)page, 1); + +- return no_free_ptr(page); ++ return page; + } + + static void *its_allocate_thunk(int reg) +@@ -290,7 +317,9 @@ u8 *its_static_thunk(int reg) + return thunk; + } + +-#endif ++#else ++static inline void its_fini_core(void) {} ++#endif /* CONFIG_MITIGATION_ITS */ + + /* + * Nomenclature for variable names to simplify and clarify this code and ease +@@ -2367,6 +2396,8 @@ void __init alternative_instructions(void) + apply_retpolines(__retpoline_sites, __retpoline_sites_end); + apply_returns(__return_sites, __return_sites_end); + ++ its_fini_core(); ++ + /* + * Adjust all CALL instructions to point to func()-10, including + * those in .altinstr_replacement. +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index 4e06baab40bb3f..a59d6d8fc71f9f 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -29,7 +29,7 @@ + + #include "cpu.h" + +-u16 invlpgb_count_max __ro_after_init; ++u16 invlpgb_count_max __ro_after_init = 1; + + static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) + { +diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c +index 8ce352fc72ac3d..7c199773705a74 100644 +--- a/arch/x86/kernel/cpu/sgx/main.c ++++ b/arch/x86/kernel/cpu/sgx/main.c +@@ -719,6 +719,8 @@ int arch_memory_failure(unsigned long pfn, int flags) + goto out; + } + ++ sgx_unmark_page_reclaimable(page); ++ + /* + * TBD: Add additional plumbing to enable pre-emptive + * action for asynchronous poison notification. Until +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index a89c271a1951f4..b567ec94b7fa54 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -1488,7 +1488,7 @@ static void svm_clear_current_vmcb(struct vmcb *vmcb) + { + int i; + +- for_each_online_cpu(i) ++ for_each_possible_cpu(i) + cmpxchg(per_cpu_ptr(&svm_data.current_vmcb, i), vmcb, NULL); + } + +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index 5c5766467a61d4..0b66b856d673b2 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -769,8 +769,11 @@ void vmx_emergency_disable_virtualization_cpu(void) + return; + + list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), +- loaded_vmcss_on_cpu_link) ++ loaded_vmcss_on_cpu_link) { + vmcs_clear(v->vmcs); ++ if (v->shadow_vmcs) ++ vmcs_clear(v->shadow_vmcs); ++ } + + kvm_cpu_vmxoff(); + } +diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c +index bb8d99e717b9e7..148eba50265a59 100644 +--- a/arch/x86/mm/init_32.c ++++ b/arch/x86/mm/init_32.c +@@ -30,7 +30,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -756,8 +755,6 @@ void mark_rodata_ro(void) + pr_info("Write protecting kernel text and read-only data: %luk\n", + size >> 10); + +- execmem_cache_make_ro(); +- + kernel_set_to_readonly = 1; + + #ifdef CONFIG_CPA_DEBUG +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index 949a447f75ec7e..7c4f6f591f2b24 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -1392,8 +1391,6 @@ void mark_rodata_ro(void) + (end - start) >> 10); + set_memory_ro(start, (end - start) >> PAGE_SHIFT); + +- execmem_cache_make_ro(); +- + kernel_set_to_readonly = 1; + + /* +diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c +index def3d928425422..9292f835cf5a30 100644 +--- a/arch/x86/mm/pat/set_memory.c ++++ b/arch/x86/mm/pat/set_memory.c +@@ -1257,6 +1257,9 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr, + pgprot_t pgprot; + int i = 0; + ++ if (!cpu_feature_enabled(X86_FEATURE_PSE)) ++ return 0; ++ + addr &= PMD_MASK; + pte = pte_offset_kernel(pmd, addr); + first = *pte; +diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c +index 5f0d579932c688..ce2f5a6081bedd 100644 +--- a/arch/x86/mm/pti.c ++++ b/arch/x86/mm/pti.c +@@ -98,6 +98,11 @@ void __init pti_check_boottime_disable(void) + return; + + setup_force_cpu_cap(X86_FEATURE_PTI); ++ ++ if (cpu_feature_enabled(X86_FEATURE_INVLPGB)) { ++ pr_debug("PTI enabled, disabling INVLPGB\n"); ++ setup_clear_cpu_cap(X86_FEATURE_INVLPGB); ++ } + } + + static int __init pti_parse_cmdline(char *arg) +diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c +index 7fdb37387886ba..328a18164ac72e 100644 +--- a/arch/x86/virt/vmx/tdx/tdx.c ++++ b/arch/x86/virt/vmx/tdx/tdx.c +@@ -69,8 +69,9 @@ static inline void seamcall_err_ret(u64 fn, u64 err, + args->r9, args->r10, args->r11); + } + +-static inline int sc_retry_prerr(sc_func_t func, sc_err_func_t err_func, +- u64 fn, struct tdx_module_args *args) ++static __always_inline int sc_retry_prerr(sc_func_t func, ++ sc_err_func_t err_func, ++ u64 fn, struct tdx_module_args *args) + { + u64 sret = sc_retry(func, fn, args); + +diff --git a/block/blk-merge.c b/block/blk-merge.c +index fdd4efb54c6c70..daa010e93cb3a4 100644 +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -1127,20 +1127,20 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, + if (!plug || rq_list_empty(&plug->mq_list)) + return false; + +- rq_list_for_each(&plug->mq_list, rq) { +- if (rq->q == q) { +- if (blk_attempt_bio_merge(q, rq, bio, nr_segs, false) == +- BIO_MERGE_OK) +- return true; +- break; +- } ++ rq = plug->mq_list.tail; ++ if (rq->q == q) ++ return blk_attempt_bio_merge(q, rq, bio, nr_segs, false) == ++ BIO_MERGE_OK; ++ else if (!plug->multiple_queues) ++ return false; + +- /* +- * Only keep iterating plug list for merges if we have multiple +- * queues +- */ +- if (!plug->multiple_queues) +- break; ++ rq_list_for_each(&plug->mq_list, rq) { ++ if (rq->q != q) ++ continue; ++ if (blk_attempt_bio_merge(q, rq, bio, nr_segs, false) == ++ BIO_MERGE_OK) ++ return true; ++ break; + } + return false; + } +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index 45c91016cef38a..351d659280e116 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -1225,6 +1225,7 @@ void blk_zone_write_plug_bio_endio(struct bio *bio) + if (bio_flagged(bio, BIO_EMULATES_ZONE_APPEND)) { + bio->bi_opf &= ~REQ_OP_MASK; + bio->bi_opf |= REQ_OP_ZONE_APPEND; ++ bio_clear_flag(bio, BIO_EMULATES_ZONE_APPEND); + } + + /* +diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c +index ccaaf6c100c022..9db741695401e7 100644 +--- a/drivers/accel/ivpu/ivpu_fw.c ++++ b/drivers/accel/ivpu/ivpu_fw.c +@@ -55,18 +55,18 @@ static struct { + int gen; + const char *name; + } fw_names[] = { +- { IVPU_HW_IP_37XX, "vpu_37xx.bin" }, ++ { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v1.bin" }, + { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v0.0.bin" }, +- { IVPU_HW_IP_40XX, "vpu_40xx.bin" }, ++ { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v1.bin" }, + { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v0.0.bin" }, +- { IVPU_HW_IP_50XX, "vpu_50xx.bin" }, ++ { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v1.bin" }, + { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v0.0.bin" }, + }; + + /* Production fw_names from the table above */ +-MODULE_FIRMWARE("intel/vpu/vpu_37xx_v0.0.bin"); +-MODULE_FIRMWARE("intel/vpu/vpu_40xx_v0.0.bin"); +-MODULE_FIRMWARE("intel/vpu/vpu_50xx_v0.0.bin"); ++MODULE_FIRMWARE("intel/vpu/vpu_37xx_v1.bin"); ++MODULE_FIRMWARE("intel/vpu/vpu_40xx_v1.bin"); ++MODULE_FIRMWARE("intel/vpu/vpu_50xx_v1.bin"); + + static int ivpu_fw_request(struct ivpu_device *vdev) + { +diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c +index 8741c73b92ce0b..248bfebeaa22d2 100644 +--- a/drivers/accel/ivpu/ivpu_gem.c ++++ b/drivers/accel/ivpu/ivpu_gem.c +@@ -28,11 +28,21 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con + { + ivpu_dbg(vdev, BO, + "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", +- action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, ++ action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx_id, + (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, + (bool)bo->base.base.import_attach); + } + ++static inline int ivpu_bo_lock(struct ivpu_bo *bo) ++{ ++ return dma_resv_lock(bo->base.base.resv, NULL); ++} ++ ++static inline void ivpu_bo_unlock(struct ivpu_bo *bo) ++{ ++ dma_resv_unlock(bo->base.base.resv); ++} ++ + /* + * ivpu_bo_pin() - pin the backing physical pages and map them to VPU. + * +@@ -43,22 +53,22 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con + int __must_check ivpu_bo_pin(struct ivpu_bo *bo) + { + struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); ++ struct sg_table *sgt; + int ret = 0; + +- mutex_lock(&bo->lock); +- + ivpu_dbg_bo(vdev, bo, "pin"); +- drm_WARN_ON(&vdev->drm, !bo->ctx); + +- if (!bo->mmu_mapped) { +- struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); ++ sgt = drm_gem_shmem_get_pages_sgt(&bo->base); ++ if (IS_ERR(sgt)) { ++ ret = PTR_ERR(sgt); ++ ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); ++ return ret; ++ } + +- if (IS_ERR(sgt)) { +- ret = PTR_ERR(sgt); +- ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); +- goto unlock; +- } ++ ivpu_bo_lock(bo); + ++ if (!bo->mmu_mapped) { ++ drm_WARN_ON(&vdev->drm, !bo->ctx); + ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt, + ivpu_bo_is_snooped(bo)); + if (ret) { +@@ -69,7 +79,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) + } + + unlock: +- mutex_unlock(&bo->lock); ++ ivpu_bo_unlock(bo); + + return ret; + } +@@ -84,7 +94,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, + if (!drm_dev_enter(&vdev->drm, &idx)) + return -ENODEV; + +- mutex_lock(&bo->lock); ++ ivpu_bo_lock(bo); + + ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node); + if (!ret) { +@@ -94,9 +104,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, + ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); + } + +- ivpu_dbg_bo(vdev, bo, "alloc"); +- +- mutex_unlock(&bo->lock); ++ ivpu_bo_unlock(bo); + + drm_dev_exit(idx); + +@@ -107,7 +115,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) + { + struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); + +- lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount)); ++ lockdep_assert(dma_resv_held(bo->base.base.resv) || !kref_read(&bo->base.base.refcount)); + + if (bo->mmu_mapped) { + drm_WARN_ON(&vdev->drm, !bo->ctx); +@@ -125,14 +133,12 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) + if (bo->base.base.import_attach) + return; + +- dma_resv_lock(bo->base.base.resv, NULL); + if (bo->base.sgt) { + dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(bo->base.sgt); + kfree(bo->base.sgt); + bo->base.sgt = NULL; + } +- dma_resv_unlock(bo->base.base.resv); + } + + void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) +@@ -144,12 +150,12 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m + + mutex_lock(&vdev->bo_list_lock); + list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { +- mutex_lock(&bo->lock); ++ ivpu_bo_lock(bo); + if (bo->ctx == ctx) { + ivpu_dbg_bo(vdev, bo, "unbind"); + ivpu_bo_unbind_locked(bo); + } +- mutex_unlock(&bo->lock); ++ ivpu_bo_unlock(bo); + } + mutex_unlock(&vdev->bo_list_lock); + } +@@ -169,7 +175,6 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz + bo->base.pages_mark_dirty_on_put = true; /* VPU can dirty a BO anytime */ + + INIT_LIST_HEAD(&bo->bo_list_node); +- mutex_init(&bo->lock); + + return &bo->base.base; + } +@@ -215,7 +220,7 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, + return ERR_PTR(ret); + } + +-static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags) ++static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id) + { + struct drm_gem_shmem_object *shmem; + struct ivpu_bo *bo; +@@ -233,6 +238,7 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla + return ERR_CAST(shmem); + + bo = to_ivpu_bo(&shmem->base); ++ bo->ctx_id = ctx_id; + bo->base.map_wc = flags & DRM_IVPU_BO_WC; + bo->flags = flags; + +@@ -240,6 +246,8 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); + ++ ivpu_dbg_bo(vdev, bo, "alloc"); ++ + return bo; + } + +@@ -277,10 +285,14 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj) + list_del(&bo->bo_list_node); + mutex_unlock(&vdev->bo_list_lock); + +- drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); ++ drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base) && ++ !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); ++ drm_WARN_ON(&vdev->drm, ivpu_bo_size(bo) == 0); ++ drm_WARN_ON(&vdev->drm, bo->base.vaddr); + + ivpu_bo_unbind_locked(bo); +- mutex_destroy(&bo->lock); ++ drm_WARN_ON(&vdev->drm, bo->mmu_mapped); ++ drm_WARN_ON(&vdev->drm, bo->ctx); + + drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1); + drm_gem_shmem_free(&bo->base); +@@ -314,7 +326,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi + if (size == 0) + return -EINVAL; + +- bo = ivpu_bo_alloc(vdev, size, args->flags); ++ bo = ivpu_bo_alloc(vdev, size, args->flags, file_priv->ctx.id); + if (IS_ERR(bo)) { + ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)", + bo, file_priv->ctx.id, args->size, args->flags); +@@ -322,7 +334,10 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi + } + + ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); +- if (!ret) ++ if (ret) ++ ivpu_err(vdev, "Failed to create handle for BO: %pe (ctx %u size %llu flags 0x%x)", ++ bo, file_priv->ctx.id, args->size, args->flags); ++ else + args->vpu_addr = bo->vpu_addr; + + drm_gem_object_put(&bo->base.base); +@@ -345,7 +360,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, + drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(range->end)); + drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size)); + +- bo = ivpu_bo_alloc(vdev, size, flags); ++ bo = ivpu_bo_alloc(vdev, size, flags, IVPU_GLOBAL_CONTEXT_MMU_SSID); + if (IS_ERR(bo)) { + ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)", + bo, range->start, size, flags); +@@ -361,9 +376,9 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, + goto err_put; + + if (flags & DRM_IVPU_BO_MAPPABLE) { +- dma_resv_lock(bo->base.base.resv, NULL); ++ ivpu_bo_lock(bo); + ret = drm_gem_shmem_vmap(&bo->base, &map); +- dma_resv_unlock(bo->base.base.resv); ++ ivpu_bo_unlock(bo); + + if (ret) + goto err_put; +@@ -386,9 +401,9 @@ void ivpu_bo_free(struct ivpu_bo *bo) + struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); + + if (bo->flags & DRM_IVPU_BO_MAPPABLE) { +- dma_resv_lock(bo->base.base.resv, NULL); ++ ivpu_bo_lock(bo); + drm_gem_shmem_vunmap(&bo->base, &map); +- dma_resv_unlock(bo->base.base.resv); ++ ivpu_bo_unlock(bo); + } + + drm_gem_object_put(&bo->base.base); +@@ -407,12 +422,12 @@ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file + + bo = to_ivpu_bo(obj); + +- mutex_lock(&bo->lock); ++ ivpu_bo_lock(bo); + args->flags = bo->flags; + args->mmap_offset = drm_vma_node_offset_addr(&obj->vma_node); + args->vpu_addr = bo->vpu_addr; + args->size = obj->size; +- mutex_unlock(&bo->lock); ++ ivpu_bo_unlock(bo); + + drm_gem_object_put(obj); + return ret; +@@ -449,10 +464,10 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file + + static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) + { +- mutex_lock(&bo->lock); ++ ivpu_bo_lock(bo); + + drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", +- bo, bo->ctx ? bo->ctx->id : 0, bo->vpu_addr, bo->base.base.size, ++ bo, bo->ctx_id, bo->vpu_addr, bo->base.base.size, + bo->flags, kref_read(&bo->base.base.refcount)); + + if (bo->base.pages) +@@ -466,7 +481,7 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) + + drm_printf(p, "\n"); + +- mutex_unlock(&bo->lock); ++ ivpu_bo_unlock(bo); + } + + void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) +diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h +index a222a9ec9d6113..aa8ff14f7aae1a 100644 +--- a/drivers/accel/ivpu/ivpu_gem.h ++++ b/drivers/accel/ivpu/ivpu_gem.h +@@ -17,10 +17,10 @@ struct ivpu_bo { + struct list_head bo_list_node; + struct drm_mm_node mm_node; + +- struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ + u64 vpu_addr; + u32 flags; + u32 job_status; /* Valid only for command buffer */ ++ u32 ctx_id; + bool mmu_mapped; + }; + +diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c +index 1c8e283ad98542..fae8351aa33090 100644 +--- a/drivers/accel/ivpu/ivpu_job.c ++++ b/drivers/accel/ivpu/ivpu_job.c +@@ -986,7 +986,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work) + return; + + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) +- ivpu_jsm_reset_engine(vdev, 0); ++ if (ivpu_jsm_reset_engine(vdev, 0)) ++ return; + + mutex_lock(&vdev->context_list_lock); + xa_for_each(&vdev->context_xa, ctx_id, file_priv) { +@@ -1009,7 +1010,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work) + if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW) + goto runtime_put; + +- ivpu_jsm_hws_resume_engine(vdev, 0); ++ if (ivpu_jsm_hws_resume_engine(vdev, 0)) ++ return; + /* + * In hardware scheduling mode NPU already has stopped processing jobs + * and won't send us any further notifications, thus we have to free job related resources +diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c +index 219ab8afefabde..0256b2dfefc10c 100644 +--- a/drivers/accel/ivpu/ivpu_jsm_msg.c ++++ b/drivers/accel/ivpu/ivpu_jsm_msg.c +@@ -7,6 +7,7 @@ + #include "ivpu_hw.h" + #include "ivpu_ipc.h" + #include "ivpu_jsm_msg.h" ++#include "ivpu_pm.h" + #include "vpu_jsm_api.h" + + const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) +@@ -163,8 +164,10 @@ int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine) + + ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_ENGINE_RESET_DONE, &resp, + VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); +- if (ret) ++ if (ret) { + ivpu_err_ratelimited(vdev, "Failed to reset engine %d: %d\n", engine, ret); ++ ivpu_pm_trigger_recovery(vdev, "Engine reset failed"); ++ } + + return ret; + } +@@ -354,8 +357,10 @@ int ivpu_jsm_hws_resume_engine(struct ivpu_device *vdev, u32 engine) + + ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE, &resp, + VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); +- if (ret) ++ if (ret) { + ivpu_err_ratelimited(vdev, "Failed to resume engine %d: %d\n", engine, ret); ++ ivpu_pm_trigger_recovery(vdev, "Engine resume failed"); ++ } + + return ret; + } +diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h +index 4e88f9fc2a2894..b6588b7fa8986a 100644 +--- a/drivers/acpi/acpica/amlresrc.h ++++ b/drivers/acpi/acpica/amlresrc.h +@@ -504,10 +504,6 @@ struct aml_resource_pin_group_config { + + #define AML_RESOURCE_PIN_GROUP_CONFIG_REVISION 1 /* ACPI 6.2 */ + +-/* restore default alignment */ +- +-#pragma pack() +- + /* Union of all resource descriptors, so we can allocate the worst case */ + + union aml_resource { +@@ -562,6 +558,10 @@ union aml_resource { + u8 byte_item; + }; + ++/* restore default alignment */ ++ ++#pragma pack() ++ + /* Interfaces used by both the disassembler and compiler */ + + void +diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c +index fb9ed5e1da89dc..2bdae8a25e084d 100644 +--- a/drivers/acpi/acpica/dsutils.c ++++ b/drivers/acpi/acpica/dsutils.c +@@ -668,6 +668,8 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS]; + u32 arg_count = 0; + u32 index = walk_state->num_operands; ++ u32 prev_num_operands = walk_state->num_operands; ++ u32 new_num_operands; + u32 i; + + ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg); +@@ -696,6 +698,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, + + /* Create the interpreter arguments, in reverse order */ + ++ new_num_operands = index; + index--; + for (i = 0; i < arg_count; i++) { + arg = arguments[index]; +@@ -720,7 +723,11 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, + * pop everything off of the operand stack and delete those + * objects + */ +- acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state); ++ walk_state->num_operands = i; ++ acpi_ds_obj_stack_pop_and_delete(new_num_operands, walk_state); ++ ++ /* Restore operand count */ ++ walk_state->num_operands = prev_num_operands; + + ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index)); + return_ACPI_STATUS(status); +diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c +index 54471083ba545e..0bce1baaa62b32 100644 +--- a/drivers/acpi/acpica/psobject.c ++++ b/drivers/acpi/acpica/psobject.c +@@ -636,7 +636,8 @@ acpi_status + acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status) + { +- acpi_status status2; ++ acpi_status return_status = status; ++ u8 ascending = TRUE; + + ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); + +@@ -650,7 +651,7 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + op)); + do { + if (op) { +- if (walk_state->ascending_callback != NULL) { ++ if (ascending && walk_state->ascending_callback != NULL) { + walk_state->op = op; + walk_state->op_info = + acpi_ps_get_opcode_info(op->common. +@@ -672,49 +673,26 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + } + + if (status == AE_CTRL_TERMINATE) { +- status = AE_OK; +- +- /* Clean up */ +- do { +- if (op) { +- status2 = +- acpi_ps_complete_this_op +- (walk_state, op); +- if (ACPI_FAILURE +- (status2)) { +- return_ACPI_STATUS +- (status2); +- } +- } +- +- acpi_ps_pop_scope(& +- (walk_state-> +- parser_state), +- &op, +- &walk_state-> +- arg_types, +- &walk_state-> +- arg_count); +- +- } while (op); +- +- return_ACPI_STATUS(status); ++ ascending = FALSE; ++ return_status = AE_CTRL_TERMINATE; + } + + else if (ACPI_FAILURE(status)) { + + /* First error is most important */ + +- (void) +- acpi_ps_complete_this_op(walk_state, +- op); +- return_ACPI_STATUS(status); ++ ascending = FALSE; ++ return_status = status; + } + } + +- status2 = acpi_ps_complete_this_op(walk_state, op); +- if (ACPI_FAILURE(status2)) { +- return_ACPI_STATUS(status2); ++ status = acpi_ps_complete_this_op(walk_state, op); ++ if (ACPI_FAILURE(status)) { ++ ascending = FALSE; ++ if (ACPI_SUCCESS(return_status) || ++ return_status == AE_CTRL_TERMINATE) { ++ return_status = status; ++ } + } + } + +@@ -724,5 +702,5 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + + } while (op); + +- return_ACPI_STATUS(status); ++ return_ACPI_STATUS(return_status); + } +diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c +index 27384ee245f094..f92010e667cda7 100644 +--- a/drivers/acpi/acpica/rsaddr.c ++++ b/drivers/acpi/acpica/rsaddr.c +@@ -272,18 +272,13 @@ u8 + acpi_rs_get_address_common(struct acpi_resource *resource, + union aml_resource *aml) + { +- struct aml_resource_address address; +- + ACPI_FUNCTION_ENTRY(); + +- /* Avoid undefined behavior: member access within misaligned address */ +- +- memcpy(&address, aml, sizeof(address)); +- + /* Validate the Resource Type */ + +- if ((address.resource_type > 2) && +- (address.resource_type < 0xC0) && (address.resource_type != 0x0A)) { ++ if ((aml->address.resource_type > 2) && ++ (aml->address.resource_type < 0xC0) && ++ (aml->address.resource_type != 0x0A)) { + return (FALSE); + } + +@@ -304,7 +299,7 @@ acpi_rs_get_address_common(struct acpi_resource *resource, + /* Generic resource type, just grab the type_specific byte */ + + resource->data.address.info.type_specific = +- address.specific_flags; ++ aml->address.specific_flags; + } + + return (TRUE); +diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c +index 6e7a152d645953..242daf45e20eff 100644 +--- a/drivers/acpi/acpica/rscalc.c ++++ b/drivers/acpi/acpica/rscalc.c +@@ -608,18 +608,12 @@ acpi_rs_get_list_length(u8 *aml_buffer, + + case ACPI_RESOURCE_NAME_SERIAL_BUS:{ + +- /* Avoid undefined behavior: member access within misaligned address */ +- +- struct aml_resource_common_serialbus +- common_serial_bus; +- memcpy(&common_serial_bus, aml_resource, +- sizeof(common_serial_bus)); +- + minimum_aml_resource_length = + acpi_gbl_resource_aml_serial_bus_sizes +- [common_serial_bus.type]; ++ [aml_resource->common_serial_bus.type]; + extra_struct_bytes += +- common_serial_bus.resource_length - ++ aml_resource->common_serial_bus. ++ resource_length - + minimum_aml_resource_length; + break; + } +@@ -688,16 +682,10 @@ acpi_rs_get_list_length(u8 *aml_buffer, + */ + if (acpi_ut_get_resource_type(aml_buffer) == + ACPI_RESOURCE_NAME_SERIAL_BUS) { +- +- /* Avoid undefined behavior: member access within misaligned address */ +- +- struct aml_resource_common_serialbus common_serial_bus; +- memcpy(&common_serial_bus, aml_resource, +- sizeof(common_serial_bus)); +- + buffer_size = + acpi_gbl_resource_struct_serial_bus_sizes +- [common_serial_bus.type] + extra_struct_bytes; ++ [aml_resource->common_serial_bus.type] + ++ extra_struct_bytes; + } else { + buffer_size = + acpi_gbl_resource_struct_sizes[resource_index] + +diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c +index 164c96e063c6e8..e46efaa889cdd7 100644 +--- a/drivers/acpi/acpica/rslist.c ++++ b/drivers/acpi/acpica/rslist.c +@@ -55,21 +55,15 @@ acpi_rs_convert_aml_to_resources(u8 * aml, + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + + if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { +- +- /* Avoid undefined behavior: member access within misaligned address */ +- +- struct aml_resource_common_serialbus common_serial_bus; +- memcpy(&common_serial_bus, aml_resource, +- sizeof(common_serial_bus)); +- +- if (common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE) { ++ if (aml_resource->common_serial_bus.type > ++ AML_RESOURCE_MAX_SERIALBUSTYPE) { + conversion_table = NULL; + } else { + /* This is an I2C, SPI, UART, or CSI2 serial_bus descriptor */ + + conversion_table = + acpi_gbl_convert_resource_serial_bus_dispatch +- [common_serial_bus.type]; ++ [aml_resource->common_serial_bus.type]; + } + } else { + conversion_table = +diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c +index 42b30b9f93128e..7fad03c5252c35 100644 +--- a/drivers/acpi/acpica/utprint.c ++++ b/drivers/acpi/acpica/utprint.c +@@ -333,11 +333,8 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args) + + pos = string; + +- if (size != ACPI_UINT32_MAX) { +- end = string + size; +- } else { +- end = ACPI_CAST_PTR(char, ACPI_UINT32_MAX); +- } ++ size = ACPI_MIN(size, ACPI_PTR_DIFF(ACPI_MAX_PTR, string)); ++ end = string + size; + + for (; *format; ++format) { + if (*format != '%') { +diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c +index cff7901f7866ec..e1cc3d3487508c 100644 +--- a/drivers/acpi/acpica/utresrc.c ++++ b/drivers/acpi/acpica/utresrc.c +@@ -361,20 +361,16 @@ acpi_ut_validate_resource(struct acpi_walk_state *walk_state, + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) { + +- /* Avoid undefined behavior: member access within misaligned address */ +- +- struct aml_resource_common_serialbus common_serial_bus; +- memcpy(&common_serial_bus, aml_resource, +- sizeof(common_serial_bus)); +- + /* Validate the bus_type field */ + +- if ((common_serial_bus.type == 0) || +- (common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE)) { ++ if ((aml_resource->common_serial_bus.type == 0) || ++ (aml_resource->common_serial_bus.type > ++ AML_RESOURCE_MAX_SERIALBUSTYPE)) { + if (walk_state) { + ACPI_ERROR((AE_INFO, + "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", +- common_serial_bus.type)); ++ aml_resource->common_serial_bus. ++ type)); + } + return (AE_AML_INVALID_RESOURCE_TYPE); + } +diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c +index 6760330a8af55d..93bb1f7d909867 100644 +--- a/drivers/acpi/battery.c ++++ b/drivers/acpi/battery.c +@@ -243,10 +243,23 @@ static int acpi_battery_get_property(struct power_supply *psy, + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_POWER_NOW: +- if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN) ++ if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN) { + ret = -ENODEV; +- else +- val->intval = battery->rate_now * 1000; ++ break; ++ } ++ ++ val->intval = battery->rate_now * 1000; ++ /* ++ * When discharging, the current should be reported as a ++ * negative number as per the power supply class interface ++ * definition. ++ */ ++ if (psp == POWER_SUPPLY_PROP_CURRENT_NOW && ++ (battery->state & ACPI_BATTERY_STATE_DISCHARGING) && ++ acpi_battery_handle_discharging(battery) ++ == POWER_SUPPLY_STATUS_DISCHARGING) ++ val->intval = -val->intval; ++ + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: +diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c +index 058910af82bca6..c2ab2783303f21 100644 +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -1446,8 +1446,10 @@ static int __init acpi_init(void) + } + + acpi_kobj = kobject_create_and_add("acpi", firmware_kobj); +- if (!acpi_kobj) +- pr_debug("%s: kset create error\n", __func__); ++ if (!acpi_kobj) { ++ pr_err("Failed to register kobject\n"); ++ return -ENOMEM; ++ } + + init_prmt(); + acpi_init_pcc(); +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index 163ac909bd0689..3fc65df9ccb839 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -1410,8 +1410,15 @@ static bool ahci_broken_suspend(struct pci_dev *pdev) + + static bool ahci_broken_lpm(struct pci_dev *pdev) + { ++ /* ++ * Platforms with LPM problems. ++ * If driver_data is NULL, there is no existing BIOS version with ++ * functioning LPM. ++ * If driver_data is non-NULL, then driver_data contains the DMI BIOS ++ * build date of the first BIOS version with functioning LPM (i.e. older ++ * BIOS versions have broken LPM). ++ */ + static const struct dmi_system_id sysids[] = { +- /* Various Lenovo 50 series have LPM issues with older BIOSen */ + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +@@ -1446,6 +1453,29 @@ static bool ahci_broken_lpm(struct pci_dev *pdev) + */ + .driver_data = "20180310", /* 2.35 */ + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ASUSPRO D840MB_M840SA"), ++ }, ++ /* 320 is broken, there is no known good version. */ ++ }, ++ { ++ /* ++ * AMD 500 Series Chipset SATA Controller [1022:43eb] ++ * on this motherboard timeouts on ports 5 and 6 when ++ * LPM is enabled, at least with WDC WD20EFAX-68FB5N0 ++ * hard drives. LPM with the same drive works fine on ++ * all other ports on the same controller. ++ */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, ++ "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, ++ "ROG STRIX B550-F GAMING (WI-FI)"), ++ }, ++ /* 3621 is broken, there is no known good version. */ ++ }, + { } /* terminate list */ + }; + const struct dmi_system_id *dmi = dmi_first_match(sysids); +@@ -1455,6 +1485,9 @@ static bool ahci_broken_lpm(struct pci_dev *pdev) + if (!dmi) + return false; + ++ if (!dmi->driver_data) ++ return true; ++ + dmi_get_date(DMI_BIOS_DATE, &year, &month, &date); + snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date); + +diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c +index 696b99720dcbda..d82728a01832b5 100644 +--- a/drivers/ata/pata_via.c ++++ b/drivers/ata/pata_via.c +@@ -368,7 +368,8 @@ static unsigned int via_mode_filter(struct ata_device *dev, unsigned int mask) + } + + if (dev->class == ATA_DEV_ATAPI && +- dmi_check_system(no_atapi_dma_dmi_table)) { ++ (dmi_check_system(no_atapi_dma_dmi_table) || ++ config->id == PCI_DEVICE_ID_VIA_6415)) { + ata_dev_warn(dev, "controller locks up on ATAPI DMA, forcing PIO\n"); + mask &= ATA_MASK_PIO; + } +diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c +index d4aa0f353b6c80..eeae160c898d38 100644 +--- a/drivers/atm/atmtcp.c ++++ b/drivers/atm/atmtcp.c +@@ -288,7 +288,9 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) + struct sk_buff *new_skb; + int result = 0; + +- if (!skb->len) return 0; ++ if (skb->len < sizeof(struct atmtcp_hdr)) ++ goto done; ++ + dev = vcc->dev_data; + hdr = (struct atmtcp_hdr *) skb->data; + if (hdr->length == ATMTCP_HDR_MAGIC) { +diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c +index 0e60dd650b5e0d..70db08f3ac6fae 100644 +--- a/drivers/base/platform-msi.c ++++ b/drivers/base/platform-msi.c +@@ -95,5 +95,6 @@ EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs); + void platform_device_msi_free_irqs_all(struct device *dev) + { + msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); ++ msi_remove_device_irq_domain(dev, MSI_DEFAULT_DOMAIN); + } + EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all); +diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c +index 205a4f8828b0ac..c55a7c70bc1a88 100644 +--- a/drivers/base/power/runtime.c ++++ b/drivers/base/power/runtime.c +@@ -1011,7 +1011,7 @@ static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer) + * If 'expires' is after the current time, we've been called + * too early. + */ +- if (expires > 0 && expires < ktime_get_mono_fast_ns()) { ++ if (expires > 0 && expires <= ktime_get_mono_fast_ns()) { + dev->power.timer_expires = 0; + rpm_suspend(dev, dev->power.timer_autosuspends ? + (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC); +diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c +index 5c78fa6ae77257..deda7f35a05987 100644 +--- a/drivers/base/swnode.c ++++ b/drivers/base/swnode.c +@@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode, + if (prop->is_inline) + return -EINVAL; + +- if (index * sizeof(*ref) >= prop->length) ++ if ((index + 1) * sizeof(*ref) > prop->length) + return -ENOENT; + + ref_array = prop->pointer; +diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c +index 141b2a0e03f2cb..8c18034cb3d69e 100644 +--- a/drivers/block/aoe/aoedev.c ++++ b/drivers/block/aoe/aoedev.c +@@ -198,6 +198,7 @@ aoedev_downdev(struct aoedev *d) + { + struct aoetgt *t, **tt, **te; + struct list_head *head, *pos, *nx; ++ struct request *rq, *rqnext; + int i; + + d->flags &= ~DEVFL_UP; +@@ -223,6 +224,13 @@ aoedev_downdev(struct aoedev *d) + /* clean out the in-process request (if any) */ + aoe_failip(d); + ++ /* clean out any queued block requests */ ++ list_for_each_entry_safe(rq, rqnext, &d->rq_list, queuelist) { ++ list_del_init(&rq->queuelist); ++ blk_mq_start_request(rq); ++ blk_mq_end_request(rq, BLK_STS_IOERR); ++ } ++ + /* fast fail all pending I/O */ + if (d->blkq) { + /* UP is cleared, freeze+quiesce to insure all are errored */ +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index dc104c025cd568..8a482853a75ede 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2710,6 +2710,9 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) + if (copy_from_user(&info, argp, sizeof(info))) + return -EFAULT; + ++ if (info.queue_depth > UBLK_MAX_QUEUE_DEPTH || info.nr_hw_queues > UBLK_MAX_NR_QUEUES) ++ return -EINVAL; ++ + if (capable(CAP_SYS_ADMIN)) + info.flags &= ~UBLK_F_UNPRIVILEGED_DEV; + else if (!(info.flags & UBLK_F_UNPRIVILEGED_DEV)) +diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c +index 07cd308f7abf6d..93932a0d8625a5 100644 +--- a/drivers/bluetooth/btmrvl_sdio.c ++++ b/drivers/bluetooth/btmrvl_sdio.c +@@ -100,7 +100,9 @@ static int btmrvl_sdio_probe_of(struct device *dev, + } + + /* Configure wakeup (enabled by default) */ +- device_init_wakeup(dev, true); ++ ret = devm_device_init_wakeup(dev); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to init wakeup\n"); + } + } + +diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c +index 1d26207b2ba70a..c16a3518b8ffa4 100644 +--- a/drivers/bluetooth/btmtksdio.c ++++ b/drivers/bluetooth/btmtksdio.c +@@ -1414,7 +1414,7 @@ static int btmtksdio_probe(struct sdio_func *func, + */ + pm_runtime_put_noidle(bdev->dev); + +- err = device_init_wakeup(bdev->dev, true); ++ err = devm_device_init_wakeup(bdev->dev); + if (err) + bt_dev_err(hdev, "failed to initialize device wakeup"); + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 256b451bbe065f..ef9689f877691e 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -513,6 +513,7 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + + /* Realtek 8851BE Bluetooth devices */ ++ { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, + + /* Realtek 8852AE Bluetooth devices */ +@@ -678,6 +679,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x13d3, 0x3584), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3605), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3607), .driver_info = BTUSB_MEDIATEK | +@@ -718,6 +721,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + + /* Additional Realtek 8723AE Bluetooth devices */ + { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, +diff --git a/drivers/bus/fsl-mc/fsl-mc-uapi.c b/drivers/bus/fsl-mc/fsl-mc-uapi.c +index 9c4c1395fcdbf2..a376ec66165348 100644 +--- a/drivers/bus/fsl-mc/fsl-mc-uapi.c ++++ b/drivers/bus/fsl-mc/fsl-mc-uapi.c +@@ -275,13 +275,13 @@ static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = { + .size = 8, + }, + [DPSW_GET_TAILDROP] = { +- .cmdid_value = 0x0A80, ++ .cmdid_value = 0x0A90, + .cmdid_mask = 0xFFF0, + .token = true, + .size = 14, + }, + [DPSW_SET_TAILDROP] = { +- .cmdid_value = 0x0A90, ++ .cmdid_value = 0x0A80, + .cmdid_mask = 0xFFF0, + .token = true, + .size = 24, +diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c +index a0ad7866cbfcba..cd8754763f40a2 100644 +--- a/drivers/bus/fsl-mc/mc-io.c ++++ b/drivers/bus/fsl-mc/mc-io.c +@@ -214,12 +214,19 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, + if (error < 0) + goto error_cleanup_resource; + +- dpmcp_dev->consumer_link = device_link_add(&mc_dev->dev, +- &dpmcp_dev->dev, +- DL_FLAG_AUTOREMOVE_CONSUMER); +- if (!dpmcp_dev->consumer_link) { +- error = -EINVAL; +- goto error_cleanup_mc_io; ++ /* If the DPRC device itself tries to allocate a portal (usually for ++ * UAPI interaction), don't add a device link between them since the ++ * DPMCP device is an actual child device of the DPRC and a reverse ++ * dependency is not allowed. ++ */ ++ if (mc_dev != mc_bus_dev) { ++ dpmcp_dev->consumer_link = device_link_add(&mc_dev->dev, ++ &dpmcp_dev->dev, ++ DL_FLAG_AUTOREMOVE_CONSUMER); ++ if (!dpmcp_dev->consumer_link) { ++ error = -EINVAL; ++ goto error_cleanup_mc_io; ++ } + } + + *new_mc_io = mc_io; +diff --git a/drivers/bus/fsl-mc/mc-sys.c b/drivers/bus/fsl-mc/mc-sys.c +index f2052cd0a05178..b22c59d57c8f0a 100644 +--- a/drivers/bus/fsl-mc/mc-sys.c ++++ b/drivers/bus/fsl-mc/mc-sys.c +@@ -19,7 +19,7 @@ + /* + * Timeout in milliseconds to wait for the completion of an MC command + */ +-#define MC_CMD_COMPLETION_TIMEOUT_MS 500 ++#define MC_CMD_COMPLETION_TIMEOUT_MS 15000 + + /* + * usleep_range() min and max values used to throttle down polling +diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c +index aeb53b2c34a8cd..26357ee68dee98 100644 +--- a/drivers/bus/mhi/ep/ring.c ++++ b/drivers/bus/mhi/ep/ring.c +@@ -131,19 +131,23 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e + } + + old_offset = ring->rd_offset; +- mhi_ep_ring_inc_index(ring); + + dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset); ++ buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); ++ buf_info.dev_addr = el; ++ buf_info.size = sizeof(*el); ++ ++ ret = mhi_cntrl->write_sync(mhi_cntrl, &buf_info); ++ if (ret) ++ return ret; ++ ++ mhi_ep_ring_inc_index(ring); + + /* Update rp in ring context */ + rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase); + memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64)); + +- buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); +- buf_info.dev_addr = el; +- buf_info.size = sizeof(*el); +- +- return mhi_cntrl->write_sync(mhi_cntrl, &buf_info); ++ return ret; + } + + void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id) +diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c +index 2fb27e6f8f88eb..33d92bf2fc3ed4 100644 +--- a/drivers/bus/mhi/host/pm.c ++++ b/drivers/bus/mhi/host/pm.c +@@ -602,6 +602,7 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) + struct mhi_cmd *mhi_cmd; + struct mhi_event_ctxt *er_ctxt; + struct device *dev = &mhi_cntrl->mhi_dev->dev; ++ bool reset_device = false; + int ret, i; + + dev_dbg(dev, "Transitioning from PM state: %s to: %s\n", +@@ -630,8 +631,23 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) + /* Wake up threads waiting for state transition */ + wake_up_all(&mhi_cntrl->state_event); + +- /* Trigger MHI RESET so that the device will not access host memory */ + if (MHI_REG_ACCESS_VALID(prev_state)) { ++ /* ++ * If the device is in PBL or SBL, it will only respond to ++ * RESET if the device is in SYSERR state. SYSERR might ++ * already be cleared at this point. ++ */ ++ enum mhi_state cur_state = mhi_get_mhi_state(mhi_cntrl); ++ enum mhi_ee_type cur_ee = mhi_get_exec_env(mhi_cntrl); ++ ++ if (cur_state == MHI_STATE_SYS_ERR) ++ reset_device = true; ++ else if (cur_ee != MHI_EE_PBL && cur_ee != MHI_EE_SBL) ++ reset_device = true; ++ } ++ ++ /* Trigger MHI RESET so that the device will not access host memory */ ++ if (reset_device) { + u32 in_reset = -1; + unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms); + +diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c +index f67b927ae4caa8..e5c02e950f2c1b 100644 +--- a/drivers/bus/ti-sysc.c ++++ b/drivers/bus/ti-sysc.c +@@ -677,51 +677,6 @@ static int sysc_parse_and_check_child_range(struct sysc *ddata) + return 0; + } + +-/* Interconnect instances to probe before l4_per instances */ +-static struct resource early_bus_ranges[] = { +- /* am3/4 l4_wkup */ +- { .start = 0x44c00000, .end = 0x44c00000 + 0x300000, }, +- /* omap4/5 and dra7 l4_cfg */ +- { .start = 0x4a000000, .end = 0x4a000000 + 0x300000, }, +- /* omap4 l4_wkup */ +- { .start = 0x4a300000, .end = 0x4a300000 + 0x30000, }, +- /* omap5 and dra7 l4_wkup without dra7 dcan segment */ +- { .start = 0x4ae00000, .end = 0x4ae00000 + 0x30000, }, +-}; +- +-static atomic_t sysc_defer = ATOMIC_INIT(10); +- +-/** +- * sysc_defer_non_critical - defer non_critical interconnect probing +- * @ddata: device driver data +- * +- * We want to probe l4_cfg and l4_wkup interconnect instances before any +- * l4_per instances as l4_per instances depend on resources on l4_cfg and +- * l4_wkup interconnects. +- */ +-static int sysc_defer_non_critical(struct sysc *ddata) +-{ +- struct resource *res; +- int i; +- +- if (!atomic_read(&sysc_defer)) +- return 0; +- +- for (i = 0; i < ARRAY_SIZE(early_bus_ranges); i++) { +- res = &early_bus_ranges[i]; +- if (ddata->module_pa >= res->start && +- ddata->module_pa <= res->end) { +- atomic_set(&sysc_defer, 0); +- +- return 0; +- } +- } +- +- atomic_dec_if_positive(&sysc_defer); +- +- return -EPROBE_DEFER; +-} +- + static struct device_node *stdout_path; + + static void sysc_init_stdout_path(struct sysc *ddata) +@@ -947,10 +902,6 @@ static int sysc_map_and_check_registers(struct sysc *ddata) + if (error) + return error; + +- error = sysc_defer_non_critical(ddata); +- if (error) +- return error; +- + sysc_check_children(ddata); + + if (!of_property_present(np, "reg")) +diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c +index 0b45b07dec22cd..5bf038e620c75f 100644 +--- a/drivers/char/ipmi/ipmi_ssif.c ++++ b/drivers/char/ipmi/ipmi_ssif.c +@@ -481,8 +481,6 @@ static int ipmi_ssif_thread(void *data) + /* Wait for something to do */ + result = wait_for_completion_interruptible( + &ssif_info->wake_thread); +- if (ssif_info->stopping) +- break; + if (result == -ERESTARTSYS) + continue; + init_completion(&ssif_info->wake_thread); +@@ -1270,10 +1268,8 @@ static void shutdown_ssif(void *send_info) + ssif_info->stopping = true; + timer_delete_sync(&ssif_info->watch_timer); + timer_delete_sync(&ssif_info->retry_timer); +- if (ssif_info->thread) { +- complete(&ssif_info->wake_thread); ++ if (ssif_info->thread) + kthread_stop(ssif_info->thread); +- } + } + + static void ssif_remove(struct i2c_client *client) +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index ceabebb1863d6e..d9e546e006d7e0 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -4093,6 +4093,7 @@ static const struct clk_parent_data spicc_sclk_parent_data[] = { + { .hw = &g12a_clk81.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, ++ { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, + }; +diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c +index fa1672c4e7d814..24f98062b9dd50 100644 +--- a/drivers/clk/qcom/gcc-sm8650.c ++++ b/drivers/clk/qcom/gcc-sm8650.c +@@ -3817,7 +3817,9 @@ static int gcc_sm8650_probe(struct platform_device *pdev) + qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x32030); /* GCC_VIDEO_XO_CLK */ + ++ /* FORCE_MEM_CORE_ON for ufs phy ice core and gcc ufs phy axi clocks */ + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); ++ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_axi_clk, true); + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52150, 0x0); +diff --git a/drivers/clk/qcom/gcc-sm8750.c b/drivers/clk/qcom/gcc-sm8750.c +index b36d7097609583..8092dd6b37b56f 100644 +--- a/drivers/clk/qcom/gcc-sm8750.c ++++ b/drivers/clk/qcom/gcc-sm8750.c +@@ -3244,8 +3244,9 @@ static int gcc_sm8750_probe(struct platform_device *pdev) + regmap_update_bits(regmap, 0x52010, BIT(20), BIT(20)); + regmap_update_bits(regmap, 0x52010, BIT(21), BIT(21)); + +- /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ ++ /* FORCE_MEM_CORE_ON for ufs phy ice core and gcc ufs phy axi clocks */ + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); ++ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_axi_clk, true); + + return qcom_cc_really_probe(&pdev->dev, &gcc_sm8750_desc, regmap); + } +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index 009f39139b6440..3e44757e25d324 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -6753,6 +6753,10 @@ static int gcc_x1e80100_probe(struct platform_device *pdev) + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); + ++ /* FORCE_MEM_CORE_ON for ufs phy ice core and gcc ufs phy axi clocks */ ++ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); ++ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_axi_clk, true); ++ + return qcom_cc_really_probe(&pdev->dev, &gcc_x1e80100_desc, regmap); + } + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index d341ce0708aac3..e4af3a92863794 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -431,6 +431,7 @@ static const char *const rk3036_critical_clocks[] __initconst = { + "hclk_peri", + "pclk_peri", + "pclk_ddrupctl", ++ "ddrphy", + }; + + static void __init rk3036_clk_init(struct device_node *np) +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index 944e899eb1be13..ef078426bfd51a 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -393,6 +393,40 @@ static struct cpufreq_driver scmi_cpufreq_driver = { + .set_boost = cpufreq_boost_set_sw, + }; + ++static bool scmi_dev_used_by_cpus(struct device *scmi_dev) ++{ ++ struct device_node *scmi_np = dev_of_node(scmi_dev); ++ struct device_node *cpu_np, *np; ++ struct device *cpu_dev; ++ int cpu, idx; ++ ++ if (!scmi_np) ++ return false; ++ ++ for_each_possible_cpu(cpu) { ++ cpu_dev = get_cpu_device(cpu); ++ if (!cpu_dev) ++ continue; ++ ++ cpu_np = dev_of_node(cpu_dev); ++ ++ np = of_parse_phandle(cpu_np, "clocks", 0); ++ of_node_put(np); ++ ++ if (np == scmi_np) ++ return true; ++ ++ idx = of_property_match_string(cpu_np, "power-domain-names", "perf"); ++ np = of_parse_phandle(cpu_np, "power-domains", idx); ++ of_node_put(np); ++ ++ if (np == scmi_np) ++ return true; ++ } ++ ++ return false; ++} ++ + static int scmi_cpufreq_probe(struct scmi_device *sdev) + { + int ret; +@@ -401,7 +435,7 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev) + + handle = sdev->handle; + +- if (!handle) ++ if (!handle || !scmi_dev_used_by_cpus(dev)) + return -ENODEV; + + scmi_cpufreq_driver.driver_data = sdev; +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +index 8084aa0f7f4170..b4731f02deb8c4 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +@@ -186,11 +186,19 @@ static void adf_remove(struct pci_dev *pdev) + adf_cleanup_accel(accel_dev); + } + ++static void adf_shutdown(struct pci_dev *pdev) ++{ ++ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); ++ ++ adf_dev_down(accel_dev); ++} ++ + static struct pci_driver adf_driver = { + .id_table = adf_pci_tbl, + .name = ADF_420XX_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, ++ .shutdown = adf_shutdown, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, + }; +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +index 5537a9991e4efb..1ac415ef3c3154 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +@@ -188,11 +188,19 @@ static void adf_remove(struct pci_dev *pdev) + adf_cleanup_accel(accel_dev); + } + ++static void adf_shutdown(struct pci_dev *pdev) ++{ ++ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); ++ ++ adf_dev_down(accel_dev); ++} ++ + static struct pci_driver adf_driver = { + .id_table = adf_pci_tbl, + .name = ADF_4XXX_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, ++ .shutdown = adf_shutdown, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, + }; +diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +index b825b35ab4bfcf..566258e80371fc 100644 +--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +@@ -19,6 +19,13 @@ + #include + #include "adf_c3xxx_hw_data.h" + ++static void adf_shutdown(struct pci_dev *pdev) ++{ ++ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); ++ ++ adf_dev_down(accel_dev); ++} ++ + static const struct pci_device_id adf_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C3XXX), }, + { } +@@ -33,6 +40,7 @@ static struct pci_driver adf_driver = { + .name = ADF_C3XXX_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, ++ .shutdown = adf_shutdown, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, + }; +diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +index 8a7bdec358d61c..ce541a72195261 100644 +--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +@@ -19,6 +19,13 @@ + #include + #include "adf_c62x_hw_data.h" + ++static void adf_shutdown(struct pci_dev *pdev) ++{ ++ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); ++ ++ adf_dev_down(accel_dev); ++} ++ + static const struct pci_device_id adf_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C62X), }, + { } +@@ -33,6 +40,7 @@ static struct pci_driver adf_driver = { + .name = ADF_C62X_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, ++ .shutdown = adf_shutdown, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, + }; +diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +index 07e9d7e5286135..f36e625266ed34 100644 +--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +@@ -19,6 +19,13 @@ + #include + #include "adf_dh895xcc_hw_data.h" + ++static void adf_shutdown(struct pci_dev *pdev) ++{ ++ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); ++ ++ adf_dev_down(accel_dev); ++} ++ + static const struct pci_device_id adf_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_DH895XCC), }, + { } +@@ -33,6 +40,7 @@ static struct pci_driver adf_driver = { + .name = ADF_DH895XCC_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, ++ .shutdown = adf_shutdown, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, + }; +diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c +index fa08f10e6f3f2c..9c21f5d835d2b0 100644 +--- a/drivers/crypto/marvell/cesa/cesa.c ++++ b/drivers/crypto/marvell/cesa/cesa.c +@@ -94,7 +94,7 @@ static int mv_cesa_std_process(struct mv_cesa_engine *engine, u32 status) + + static int mv_cesa_int_process(struct mv_cesa_engine *engine, u32 status) + { +- if (engine->chain.first && engine->chain.last) ++ if (engine->chain_hw.first && engine->chain_hw.last) + return mv_cesa_tdma_process(engine, status); + + return mv_cesa_std_process(engine, status); +diff --git a/drivers/crypto/marvell/cesa/cesa.h b/drivers/crypto/marvell/cesa/cesa.h +index d215a6bed6bc7b..50ca1039fdaa7a 100644 +--- a/drivers/crypto/marvell/cesa/cesa.h ++++ b/drivers/crypto/marvell/cesa/cesa.h +@@ -440,8 +440,10 @@ struct mv_cesa_dev { + * SRAM + * @queue: fifo of the pending crypto requests + * @load: engine load counter, useful for load balancing +- * @chain: list of the current tdma descriptors being processed +- * by this engine. ++ * @chain_hw: list of the current tdma descriptors being processed ++ * by the hardware. ++ * @chain_sw: list of the current tdma descriptors that will be ++ * submitted to the hardware. + * @complete_queue: fifo of the processed requests by the engine + * + * Structure storing CESA engine information. +@@ -463,7 +465,8 @@ struct mv_cesa_engine { + struct gen_pool *pool; + struct crypto_queue queue; + atomic_t load; +- struct mv_cesa_tdma_chain chain; ++ struct mv_cesa_tdma_chain chain_hw; ++ struct mv_cesa_tdma_chain chain_sw; + struct list_head complete_queue; + int irq; + }; +diff --git a/drivers/crypto/marvell/cesa/tdma.c b/drivers/crypto/marvell/cesa/tdma.c +index 388a06e180d64a..243305354420c1 100644 +--- a/drivers/crypto/marvell/cesa/tdma.c ++++ b/drivers/crypto/marvell/cesa/tdma.c +@@ -38,6 +38,15 @@ void mv_cesa_dma_step(struct mv_cesa_req *dreq) + { + struct mv_cesa_engine *engine = dreq->engine; + ++ spin_lock_bh(&engine->lock); ++ if (engine->chain_sw.first == dreq->chain.first) { ++ engine->chain_sw.first = NULL; ++ engine->chain_sw.last = NULL; ++ } ++ engine->chain_hw.first = dreq->chain.first; ++ engine->chain_hw.last = dreq->chain.last; ++ spin_unlock_bh(&engine->lock); ++ + writel_relaxed(0, engine->regs + CESA_SA_CFG); + + mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE); +@@ -96,25 +105,27 @@ void mv_cesa_dma_prepare(struct mv_cesa_req *dreq, + void mv_cesa_tdma_chain(struct mv_cesa_engine *engine, + struct mv_cesa_req *dreq) + { +- if (engine->chain.first == NULL && engine->chain.last == NULL) { +- engine->chain.first = dreq->chain.first; +- engine->chain.last = dreq->chain.last; +- } else { +- struct mv_cesa_tdma_desc *last; ++ struct mv_cesa_tdma_desc *last = engine->chain_sw.last; + +- last = engine->chain.last; ++ /* ++ * Break the DMA chain if the request being queued needs the IV ++ * regs to be set before lauching the request. ++ */ ++ if (!last || dreq->chain.first->flags & CESA_TDMA_SET_STATE) ++ engine->chain_sw.first = dreq->chain.first; ++ else { + last->next = dreq->chain.first; +- engine->chain.last = dreq->chain.last; +- +- /* +- * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on +- * the last element of the current chain, or if the request +- * being queued needs the IV regs to be set before lauching +- * the request. +- */ +- if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && +- !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) +- last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma); ++ last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma); ++ } ++ last = dreq->chain.last; ++ engine->chain_sw.last = last; ++ /* ++ * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on ++ * the last element of the current chain. ++ */ ++ if (last->flags & CESA_TDMA_BREAK_CHAIN) { ++ engine->chain_sw.first = NULL; ++ engine->chain_sw.last = NULL; + } + } + +@@ -127,7 +138,7 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status) + + tdma_cur = readl(engine->regs + CESA_TDMA_CUR); + +- for (tdma = engine->chain.first; tdma; tdma = next) { ++ for (tdma = engine->chain_hw.first; tdma; tdma = next) { + spin_lock_bh(&engine->lock); + next = tdma->next; + spin_unlock_bh(&engine->lock); +@@ -149,12 +160,12 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status) + &backlog); + + /* Re-chaining to the next request */ +- engine->chain.first = tdma->next; ++ engine->chain_hw.first = tdma->next; + tdma->next = NULL; + + /* If this is the last request, clear the chain */ +- if (engine->chain.first == NULL) +- engine->chain.last = NULL; ++ if (engine->chain_hw.first == NULL) ++ engine->chain_hw.last = NULL; + spin_unlock_bh(&engine->lock); + + ctx = crypto_tfm_ctx(req->tfm); +diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c +index e74e36a8ecda21..421d44644bc02a 100644 +--- a/drivers/dma-buf/udmabuf.c ++++ b/drivers/dma-buf/udmabuf.c +@@ -264,8 +264,7 @@ static int begin_cpu_udmabuf(struct dma_buf *buf, + ubuf->sg = NULL; + } + } else { +- dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, +- direction); ++ dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction); + } + + return ret; +@@ -280,7 +279,7 @@ static int end_cpu_udmabuf(struct dma_buf *buf, + if (!ubuf->sg) + return -EINVAL; + +- dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); ++ dma_sync_sgtable_for_device(dev, ubuf->sg, direction); + return 0; + } + +diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c +index dcd7008fe06b05..c45c92f0537367 100644 +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1746,9 +1746,9 @@ altr_edac_a10_device_trig(struct file *file, const char __user *user_buf, + + local_irq_save(flags); + if (trig_type == ALTR_UE_TRIGGER_CHAR) +- writel(priv->ue_set_mask, set_addr); ++ writew(priv->ue_set_mask, set_addr); + else +- writel(priv->ce_set_mask, set_addr); ++ writew(priv->ce_set_mask, set_addr); + + /* Ensure the interrupt test bits are set */ + wmb(); +@@ -1778,7 +1778,7 @@ altr_edac_a10_device_trig2(struct file *file, const char __user *user_buf, + + local_irq_save(flags); + if (trig_type == ALTR_UE_TRIGGER_CHAR) { +- writel(priv->ue_set_mask, set_addr); ++ writew(priv->ue_set_mask, set_addr); + } else { + /* Setup read/write of 4 bytes */ + writel(ECC_WORD_WRITE, drvdata->base + ECC_BLK_DBYTECTRL_OFST); +diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c +index 90f0eb7cc5b9bd..390f5756b66ed0 100644 +--- a/drivers/edac/amd64_edac.c ++++ b/drivers/edac/amd64_edac.c +@@ -3879,6 +3879,7 @@ static int per_family_init(struct amd64_pvt *pvt) + break; + case 0x70 ... 0x7f: + pvt->ctl_name = "F19h_M70h"; ++ pvt->max_mcs = 4; + pvt->flags.zn_regs_v2 = 1; + break; + case 0x90 ... 0x9f: +diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c +index 5807517ee32dec..cc50313b3e905f 100644 +--- a/drivers/edac/igen6_edac.c ++++ b/drivers/edac/igen6_edac.c +@@ -125,8 +125,9 @@ + #define MEM_SLICE_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6) + #define MEM_SLICE_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26) + +-static const struct res_config { ++static struct res_config { + bool machine_check; ++ /* The number of present memory controllers. */ + int num_imc; + u32 imc_base; + u32 cmf_base; +@@ -472,7 +473,7 @@ static u64 rpl_p_err_addr(u64 ecclog) + return ECC_ERROR_LOG_ADDR45(ecclog); + } + +-static const struct res_config ehl_cfg = { ++static struct res_config ehl_cfg = { + .num_imc = 1, + .imc_base = 0x5000, + .ibecc_base = 0xdc00, +@@ -482,7 +483,7 @@ static const struct res_config ehl_cfg = { + .err_addr_to_imc_addr = ehl_err_addr_to_imc_addr, + }; + +-static const struct res_config icl_cfg = { ++static struct res_config icl_cfg = { + .num_imc = 1, + .imc_base = 0x5000, + .ibecc_base = 0xd800, +@@ -492,7 +493,7 @@ static const struct res_config icl_cfg = { + .err_addr_to_imc_addr = ehl_err_addr_to_imc_addr, + }; + +-static const struct res_config tgl_cfg = { ++static struct res_config tgl_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0x5000, +@@ -506,7 +507,7 @@ static const struct res_config tgl_cfg = { + .err_addr_to_imc_addr = tgl_err_addr_to_imc_addr, + }; + +-static const struct res_config adl_cfg = { ++static struct res_config adl_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, +@@ -517,7 +518,7 @@ static const struct res_config adl_cfg = { + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + }; + +-static const struct res_config adl_n_cfg = { ++static struct res_config adl_n_cfg = { + .machine_check = true, + .num_imc = 1, + .imc_base = 0xd800, +@@ -528,7 +529,7 @@ static const struct res_config adl_n_cfg = { + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + }; + +-static const struct res_config rpl_p_cfg = { ++static struct res_config rpl_p_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, +@@ -540,7 +541,7 @@ static const struct res_config rpl_p_cfg = { + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + }; + +-static const struct res_config mtl_ps_cfg = { ++static struct res_config mtl_ps_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, +@@ -551,7 +552,7 @@ static const struct res_config mtl_ps_cfg = { + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + }; + +-static const struct res_config mtl_p_cfg = { ++static struct res_config mtl_p_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, +@@ -562,7 +563,7 @@ static const struct res_config mtl_p_cfg = { + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + }; + +-static const struct pci_device_id igen6_pci_tbl[] = { ++static struct pci_device_id igen6_pci_tbl[] = { + { PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU7), (kernel_ulong_t)&ehl_cfg }, +@@ -1201,23 +1202,21 @@ static void igen6_check(struct mem_ctl_info *mci) + irq_work_queue(&ecclog_irq_work); + } + +-static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) ++/* Check whether the memory controller is absent. */ ++static bool igen6_imc_absent(void __iomem *window) ++{ ++ return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0; ++} ++ ++static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev) + { + struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci; + struct igen6_imc *imc; +- void __iomem *window; + int rc; + + edac_dbg(2, "\n"); + +- mchbar += mc * MCHBAR_SIZE; +- window = ioremap(mchbar, MCHBAR_SIZE); +- if (!window) { +- igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar); +- return -ENODEV; +- } +- + layers[0].type = EDAC_MC_LAYER_CHANNEL; + layers[0].size = NUM_CHANNELS; + layers[0].is_virt_csrow = false; +@@ -1283,7 +1282,6 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) + fail2: + edac_mc_free(mci); + fail: +- iounmap(window); + return rc; + } + +@@ -1309,6 +1307,58 @@ static void igen6_unregister_mcis(void) + } + } + ++static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar) ++{ ++ void __iomem *window; ++ int lmc, pmc, rc; ++ u64 base; ++ ++ for (lmc = 0, pmc = 0; pmc < NUM_IMC; pmc++) { ++ base = mchbar + pmc * MCHBAR_SIZE; ++ window = ioremap(base, MCHBAR_SIZE); ++ if (!window) { ++ igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx for mc%d\n", base, pmc); ++ rc = -ENOMEM; ++ goto out_unregister_mcis; ++ } ++ ++ if (igen6_imc_absent(window)) { ++ iounmap(window); ++ edac_dbg(2, "Skip absent mc%d\n", pmc); ++ continue; ++ } ++ ++ rc = igen6_register_mci(lmc, window, pdev); ++ if (rc) ++ goto out_iounmap; ++ ++ /* Done, if all present MCs are detected and registered. */ ++ if (++lmc >= res_cfg->num_imc) ++ break; ++ } ++ ++ if (!lmc) { ++ igen6_printk(KERN_ERR, "No mc found.\n"); ++ return -ENODEV; ++ } ++ ++ if (lmc < res_cfg->num_imc) { ++ igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.", ++ res_cfg->num_imc, lmc); ++ res_cfg->num_imc = lmc; ++ } ++ ++ return 0; ++ ++out_iounmap: ++ iounmap(window); ++ ++out_unregister_mcis: ++ igen6_unregister_mcis(); ++ ++ return rc; ++} ++ + static int igen6_mem_slice_setup(u64 mchbar) + { + struct igen6_imc *imc = &igen6_pvt->imc[0]; +@@ -1405,7 +1455,7 @@ static void opstate_set(const struct res_config *cfg, const struct pci_device_id + static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + u64 mchbar; +- int i, rc; ++ int rc; + + edac_dbg(2, "\n"); + +@@ -1421,11 +1471,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + opstate_set(res_cfg, ent); + +- for (i = 0; i < res_cfg->num_imc; i++) { +- rc = igen6_register_mci(i, mchbar, pdev); +- if (rc) +- goto fail2; +- } ++ rc = igen6_register_mcis(pdev, mchbar); ++ if (rc) ++ goto fail; + + if (res_cfg->num_imc > 1) { + rc = igen6_mem_slice_setup(mchbar); +diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c +index 0390d5ff195ec0..06944ac6985d91 100644 +--- a/drivers/firmware/arm_scmi/driver.c ++++ b/drivers/firmware/arm_scmi/driver.c +@@ -1737,6 +1737,39 @@ static int scmi_common_get_max_msg_size(const struct scmi_protocol_handle *ph) + return info->desc->max_msg_size; + } + ++/** ++ * scmi_protocol_msg_check - Check protocol message attributes ++ * ++ * @ph: A reference to the protocol handle. ++ * @message_id: The ID of the message to check. ++ * @attributes: A parameter to optionally return the retrieved message ++ * attributes, in case of Success. ++ * ++ * An helper to check protocol message attributes for a specific protocol ++ * and message pair. ++ * ++ * Return: 0 on SUCCESS ++ */ ++static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, ++ u32 message_id, u32 *attributes) ++{ ++ int ret; ++ struct scmi_xfer *t; ++ ++ ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, ++ sizeof(__le32), 0, &t); ++ if (ret) ++ return ret; ++ ++ put_unaligned_le32(message_id, t->tx.buf); ++ ret = do_xfer(ph, t); ++ if (!ret && attributes) ++ *attributes = get_unaligned_le32(t->rx.buf); ++ xfer_put(ph, t); ++ ++ return ret; ++} ++ + /** + * struct scmi_iterator - Iterator descriptor + * @msg: A reference to the message TX buffer; filled by @prepare_message with +@@ -1878,6 +1911,7 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph, + int ret; + u32 flags; + u64 phys_addr; ++ u32 attributes; + u8 size; + void __iomem *addr; + struct scmi_xfer *t; +@@ -1886,6 +1920,15 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph, + struct scmi_msg_resp_desc_fc *resp; + const struct scmi_protocol_instance *pi = ph_to_pi(ph); + ++ /* Check if the MSG_ID supports fastchannel */ ++ ret = scmi_protocol_msg_check(ph, message_id, &attributes); ++ if (ret || !MSG_SUPPORTS_FASTCHANNEL(attributes)) { ++ dev_dbg(ph->dev, ++ "Skip FC init for 0x%02X/%d domain:%d - ret:%d\n", ++ pi->proto->id, message_id, domain, ret); ++ return; ++ } ++ + if (!p_addr) { + ret = -EINVAL; + goto err_out; +@@ -2003,39 +2046,6 @@ static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db) + SCMI_PROTO_FC_RING_DB(64); + } + +-/** +- * scmi_protocol_msg_check - Check protocol message attributes +- * +- * @ph: A reference to the protocol handle. +- * @message_id: The ID of the message to check. +- * @attributes: A parameter to optionally return the retrieved message +- * attributes, in case of Success. +- * +- * An helper to check protocol message attributes for a specific protocol +- * and message pair. +- * +- * Return: 0 on SUCCESS +- */ +-static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, +- u32 message_id, u32 *attributes) +-{ +- int ret; +- struct scmi_xfer *t; +- +- ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, +- sizeof(__le32), 0, &t); +- if (ret) +- return ret; +- +- put_unaligned_le32(message_id, t->tx.buf); +- ret = do_xfer(ph, t); +- if (!ret && attributes) +- *attributes = get_unaligned_le32(t->rx.buf); +- xfer_put(ph, t); +- +- return ret; +-} +- + static const struct scmi_proto_helpers_ops helpers_ops = { + .extended_name_get = scmi_common_extended_name_get, + .get_max_msg_size = scmi_common_get_max_msg_size, +diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h +index aaee57cdcd5589..d62c4469d1fd9f 100644 +--- a/drivers/firmware/arm_scmi/protocols.h ++++ b/drivers/firmware/arm_scmi/protocols.h +@@ -31,6 +31,8 @@ + + #define SCMI_PROTOCOL_VENDOR_BASE 0x80 + ++#define MSG_SUPPORTS_FASTCHANNEL(x) ((x) & BIT(0)) ++ + enum scmi_common_cmd { + PROTOCOL_VERSION = 0x0, + PROTOCOL_ATTRIBUTES = 0x1, +diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c b/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c +index 49d84f7e59e6a9..a0601b23b1bd32 100644 +--- a/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c ++++ b/drivers/firmware/cirrus/test/cs_dsp_mock_bin.c +@@ -96,10 +96,11 @@ static void cs_dsp_mock_bin_add_name_or_info(struct cs_dsp_mock_bin_builder *bui + + if (info_len % 4) { + /* Create a padded string with length a multiple of 4 */ ++ size_t copy_len = info_len; + info_len = round_up(info_len, 4); + tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp); +- memcpy(tmp, info, info_len); ++ memcpy(tmp, info, copy_len); + info = tmp; + } + +diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c b/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c +index 5a3ac03ac37f07..4fa74550dafd18 100644 +--- a/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c ++++ b/drivers/firmware/cirrus/test/cs_dsp_mock_wmfw.c +@@ -133,10 +133,11 @@ void cs_dsp_mock_wmfw_add_info(struct cs_dsp_mock_wmfw_builder *builder, + + if (info_len % 4) { + /* Create a padded string with length a multiple of 4 */ ++ size_t copy_len = info_len; + info_len = round_up(info_len, 4); + tmp = kunit_kzalloc(builder->test_priv->test, info_len, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(builder->test_priv->test, tmp); +- memcpy(tmp, info, info_len); ++ memcpy(tmp, info, copy_len); + info = tmp; + } + +diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c +index 83386cc978e3f8..ebca3a4ab0f1ad 100644 +--- a/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c ++++ b/drivers/firmware/cirrus/test/cs_dsp_test_control_cache.c +@@ -776,7 +776,6 @@ static void cs_dsp_ctl_cache_init_multiple_offsets(struct kunit *test) + "dummyalg", NULL); + + /* Create controls identical except for offset */ +- def.length_bytes = 8; + def.offset_dsp_words = 0; + def.shortname = "CtlA"; + cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &def); +diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c +index 7c5c03f274b951..889e5b05c739ce 100644 +--- a/drivers/firmware/sysfb.c ++++ b/drivers/firmware/sysfb.c +@@ -143,6 +143,7 @@ static __init int sysfb_init(void) + { + struct screen_info *si = &screen_info; + struct device *parent; ++ unsigned int type; + struct simplefb_platform_data mode; + const char *name; + bool compatible; +@@ -170,17 +171,26 @@ static __init int sysfb_init(void) + goto put_device; + } + ++ type = screen_info_video_type(si); ++ + /* if the FB is incompatible, create a legacy framebuffer device */ +- if (si->orig_video_isVGA == VIDEO_TYPE_EFI) +- name = "efi-framebuffer"; +- else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB) +- name = "vesa-framebuffer"; +- else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC) +- name = "vga-framebuffer"; +- else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC) ++ switch (type) { ++ case VIDEO_TYPE_EGAC: + name = "ega-framebuffer"; +- else ++ break; ++ case VIDEO_TYPE_VGAC: ++ name = "vga-framebuffer"; ++ break; ++ case VIDEO_TYPE_VLFB: ++ name = "vesa-framebuffer"; ++ break; ++ case VIDEO_TYPE_EFI: ++ name = "efi-framebuffer"; ++ break; ++ default: + name = "platform-framebuffer"; ++ break; ++ } + + pd = platform_device_alloc(name, 0); + if (!pd) { +diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c +index 806a975fff22ae..ae5fd1936ad322 100644 +--- a/drivers/firmware/ti_sci.c ++++ b/drivers/firmware/ti_sci.c +@@ -2,7 +2,7 @@ + /* + * Texas Instruments System Control Interface Protocol Driver + * +- * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/ ++ * Copyright (C) 2015-2025 Texas Instruments Incorporated - https://www.ti.com/ + * Nishanth Menon + */ + +@@ -3670,6 +3670,7 @@ static int __maybe_unused ti_sci_suspend(struct device *dev) + struct ti_sci_info *info = dev_get_drvdata(dev); + struct device *cpu_dev, *cpu_dev_max = NULL; + s32 val, cpu_lat = 0; ++ u16 cpu_lat_ms; + int i, ret; + + if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) { +@@ -3682,9 +3683,16 @@ static int __maybe_unused ti_sci_suspend(struct device *dev) + } + } + if (cpu_dev_max) { +- dev_dbg(cpu_dev_max, "%s: sending max CPU latency=%u\n", __func__, cpu_lat); ++ /* ++ * PM QoS latency unit is usecs, device manager uses msecs. ++ * Convert to msecs and round down for device manager. ++ */ ++ cpu_lat_ms = cpu_lat / USEC_PER_MSEC; ++ dev_dbg(cpu_dev_max, "%s: sending max CPU latency=%u ms\n", __func__, ++ cpu_lat_ms); + ret = ti_sci_cmd_set_latency_constraint(&info->handle, +- cpu_lat, TISCI_MSG_CONSTRAINT_SET); ++ cpu_lat_ms, ++ TISCI_MSG_CONSTRAINT_SET); + if (ret) + return ret; + } +diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c +index a9a93036f08ff0..286a3876ed0c08 100644 +--- a/drivers/gpio/gpio-loongson-64bit.c ++++ b/drivers/gpio/gpio-loongson-64bit.c +@@ -266,7 +266,7 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { + /* LS7A2000 ACPI GPIO */ + static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { + .label = "ls7a2000_gpio", +- .mode = BYTE_CTRL_MODE, ++ .mode = BIT_CTRL_MODE, + .conf_offset = 0x4, + .in_offset = 0x8, + .out_offset = 0x0, +diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c +index 10ea71273c8915..9875e34bde72a4 100644 +--- a/drivers/gpio/gpio-mlxbf3.c ++++ b/drivers/gpio/gpio-mlxbf3.c +@@ -190,7 +190,9 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) + struct mlxbf3_gpio_context *gs; + struct gpio_irq_chip *girq; + struct gpio_chip *gc; ++ char *colon_ptr; + int ret, irq; ++ long num; + + gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); + if (!gs) +@@ -227,25 +229,39 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) + gc->owner = THIS_MODULE; + gc->add_pin_ranges = mlxbf3_gpio_add_pin_ranges; + +- irq = platform_get_irq(pdev, 0); +- if (irq >= 0) { +- girq = &gs->gc.irq; +- gpio_irq_chip_set_chip(girq, &gpio_mlxbf3_irqchip); +- girq->default_type = IRQ_TYPE_NONE; +- /* This will let us handle the parent IRQ in the driver */ +- girq->num_parents = 0; +- girq->parents = NULL; +- girq->parent_handler = NULL; +- girq->handler = handle_bad_irq; +- +- /* +- * Directly request the irq here instead of passing +- * a flow-handler because the irq is shared. +- */ +- ret = devm_request_irq(dev, irq, mlxbf3_gpio_irq_handler, +- IRQF_SHARED, dev_name(dev), gs); +- if (ret) +- return dev_err_probe(dev, ret, "failed to request IRQ"); ++ colon_ptr = strchr(dev_name(dev), ':'); ++ if (!colon_ptr) { ++ dev_err(dev, "invalid device name format\n"); ++ return -EINVAL; ++ } ++ ++ ret = kstrtol(++colon_ptr, 16, &num); ++ if (ret) { ++ dev_err(dev, "invalid device instance\n"); ++ return ret; ++ } ++ ++ if (!num) { ++ irq = platform_get_irq(pdev, 0); ++ if (irq >= 0) { ++ girq = &gs->gc.irq; ++ gpio_irq_chip_set_chip(girq, &gpio_mlxbf3_irqchip); ++ girq->default_type = IRQ_TYPE_NONE; ++ /* This will let us handle the parent IRQ in the driver */ ++ girq->num_parents = 0; ++ girq->parents = NULL; ++ girq->parent_handler = NULL; ++ girq->handler = handle_bad_irq; ++ ++ /* ++ * Directly request the irq here instead of passing ++ * a flow-handler because the irq is shared. ++ */ ++ ret = devm_request_irq(dev, irq, mlxbf3_gpio_irq_handler, ++ IRQF_SHARED, dev_name(dev), gs); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to request IRQ"); ++ } + } + + platform_set_drvdata(pdev, gs); +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index 13cc120cf11f14..02da81ff1c0f18 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -952,7 +952,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) + IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), + chip); + if (ret) +- return dev_err_probe(dev, client->irq, "failed to request irq\n"); ++ return dev_err_probe(dev, ret, "failed to request irq\n"); + + return 0; + } +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index 65f6a7177b78ef..17802d97492fa6 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -224,6 +224,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, + */ + { "lantiq,pci-xway", "gpio-reset", false }, + #endif ++#if IS_ENABLED(CONFIG_REGULATOR_S5M8767) ++ /* ++ * According to S5M8767, the DVS and DS pin are ++ * active-high signals. However, exynos5250-spring.dts use ++ * active-low setting. ++ */ ++ { "samsung,s5m8767-pmic", "s5m8767,pmic-buck-dvs-gpios", true }, ++ { "samsung,s5m8767-pmic", "s5m8767,pmic-buck-ds-gpios", true }, ++#endif + #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2005) + /* + * DTS for Nokia N900 incorrectly specified "active high" +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index f8b3e04d71eda1..95124a4a0a67cf 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -2689,6 +2689,13 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + break; + } + ++ /* Check for IP version 9.4.3 with A0 hardware */ ++ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) && ++ !amdgpu_device_get_rev_id(adev)) { ++ dev_err(adev->dev, "Unsupported A0 hardware\n"); ++ return -ENODEV; /* device unsupported - no device error */ ++ } ++ + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && +@@ -2701,7 +2708,6 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + adev->has_pr3 = parent ? pci_pr3_present(parent) : false; + } + +- + adev->pm.pp_feature = amdgpu_pp_feature_mask; + if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS) + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index cf2df7790077d4..1dc06e4ab49705 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -1351,6 +1351,10 @@ static ssize_t amdgpu_gfx_get_current_compute_partition(struct device *dev, + struct amdgpu_device *adev = drm_to_adev(ddev); + int mode; + ++ /* Only minimal precaution taken to reject requests while in reset.*/ ++ if (amdgpu_in_reset(adev)) ++ return -EPERM; ++ + mode = amdgpu_xcp_query_partition_mode(adev->xcp_mgr, + AMDGPU_XCP_FL_NONE); + +@@ -1394,8 +1398,14 @@ static ssize_t amdgpu_gfx_set_compute_partition(struct device *dev, + return -EINVAL; + } + ++ /* Don't allow a switch while under reset */ ++ if (!down_read_trylock(&adev->reset_domain->sem)) ++ return -EPERM; ++ + ret = amdgpu_xcp_switch_partition_mode(adev->xcp_mgr, mode); + ++ up_read(&adev->reset_domain->sem); ++ + if (ret) + return ret; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index ecb74ccf1d9081..6b0fbbb91e5795 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -1230,6 +1230,10 @@ static ssize_t current_memory_partition_show( + struct amdgpu_device *adev = drm_to_adev(ddev); + enum amdgpu_memory_partition mode; + ++ /* Only minimal precaution taken to reject requests while in reset */ ++ if (amdgpu_in_reset(adev)) ++ return -EPERM; ++ + mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); + if ((mode >= ARRAY_SIZE(nps_desc)) || + (BIT(mode) & AMDGPU_ALL_NPS_MASK) != BIT(mode)) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +index fb212f0a1136a4..5590ad5e8cd76c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +@@ -150,9 +150,6 @@ int amdgpu_mes_init(struct amdgpu_device *adev) + adev->mes.compute_hqd_mask[i] = 0xc; + } + +- for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) +- adev->mes.gfx_hqd_mask[i] = i ? 0 : 0xfffffffe; +- + for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) { + if (i >= adev->sdma.num_instances) + break; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +index da2c9a8cb3e011..52dd54a32fb477 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +@@ -111,8 +111,8 @@ struct amdgpu_mes { + + uint32_t vmid_mask_gfxhub; + uint32_t vmid_mask_mmhub; +- uint32_t compute_hqd_mask[AMDGPU_MES_MAX_COMPUTE_PIPES]; + uint32_t gfx_hqd_mask[AMDGPU_MES_MAX_GFX_PIPES]; ++ uint32_t compute_hqd_mask[AMDGPU_MES_MAX_COMPUTE_PIPES]; + uint32_t sdma_hqd_mask[AMDGPU_MES_MAX_SDMA_PIPES]; + uint32_t aggregated_doorbells[AMDGPU_MES_PRIORITY_NUM_LEVELS]; + uint32_t sch_ctx_offs[AMDGPU_MAX_MES_PIPES]; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +index 8d5acc415d386b..dcf5e8e0b9e3ea 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +@@ -107,6 +107,7 @@ enum psp_reg_prog_id { + PSP_REG_IH_RB_CNTL = 0, /* register IH_RB_CNTL */ + PSP_REG_IH_RB_CNTL_RING1 = 1, /* register IH_RB_CNTL_RING1 */ + PSP_REG_IH_RB_CNTL_RING2 = 2, /* register IH_RB_CNTL_RING2 */ ++ PSP_REG_MMHUB_L1_TLB_CNTL = 25, + PSP_REG_LAST + }; + +@@ -142,6 +143,8 @@ struct psp_funcs { + bool (*get_ras_capability)(struct psp_context *psp); + bool (*is_aux_sos_load_required)(struct psp_context *psp); + bool (*is_reload_needed)(struct psp_context *psp); ++ int (*reg_program_no_ring)(struct psp_context *psp, uint32_t val, ++ enum psp_reg_prog_id id); + }; + + struct ta_funcs { +@@ -475,6 +478,10 @@ struct amdgpu_psp_funcs { + #define psp_is_aux_sos_load_required(psp) \ + ((psp)->funcs->is_aux_sos_load_required ? (psp)->funcs->is_aux_sos_load_required((psp)) : 0) + ++#define psp_reg_program_no_ring(psp, val, id) \ ++ ((psp)->funcs->reg_program_no_ring ? \ ++ (psp)->funcs->reg_program_no_ring((psp), val, id) : -EINVAL) ++ + extern const struct amd_ip_funcs psp_ip_funcs; + + extern const struct amdgpu_ip_block_version psp_v3_1_ip_block; +@@ -569,5 +576,8 @@ bool amdgpu_psp_get_ras_capability(struct psp_context *psp); + int psp_config_sq_perfmon(struct psp_context *psp, uint32_t xcp_id, + bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable); + bool amdgpu_psp_tos_reload_needed(struct amdgpu_device *adev); ++int amdgpu_psp_reg_program_no_ring(struct psp_context *psp, uint32_t val, ++ enum psp_reg_prog_id id); ++ + + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +index 0ea7cfaf3587df..e979a6086178c7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -1392,17 +1392,33 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) + + __decode_table_header_from_buf(hdr, buf); + +- if (hdr->version >= RAS_TABLE_VER_V2_1) { ++ switch (hdr->version) { ++ case RAS_TABLE_VER_V2_1: ++ case RAS_TABLE_VER_V3: + control->ras_num_recs = RAS_NUM_RECS_V2_1(hdr); + control->ras_record_offset = RAS_RECORD_START_V2_1; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1; +- } else { ++ break; ++ case RAS_TABLE_VER_V1: + control->ras_num_recs = RAS_NUM_RECS(hdr); + control->ras_record_offset = RAS_RECORD_START; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT; ++ break; ++ default: ++ dev_err(adev->dev, ++ "RAS header invalid, unsupported version: %u", ++ hdr->version); ++ return -EINVAL; + } +- control->ras_fri = RAS_OFFSET_TO_INDEX(control, hdr->first_rec_offset); + ++ if (control->ras_num_recs > control->ras_max_record_count) { ++ dev_err(adev->dev, ++ "RAS header invalid, records in header: %u max allowed :%u", ++ control->ras_num_recs, control->ras_max_record_count); ++ return -EINVAL; ++ } ++ ++ control->ras_fri = RAS_OFFSET_TO_INDEX(control, hdr->first_rec_offset); + control->ras_num_mca_recs = 0; + control->ras_num_pa_recs = 0; + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +index df03dba67ab898..b6ec6b7969f0c9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +@@ -146,11 +146,13 @@ enum AMDGIM_FEATURE_FLAG { + + enum AMDGIM_REG_ACCESS_FLAG { + /* Use PSP to program IH_RB_CNTL */ +- AMDGIM_FEATURE_IH_REG_PSP_EN = (1 << 0), ++ AMDGIM_FEATURE_IH_REG_PSP_EN = (1 << 0), + /* Use RLC to program MMHUB regs */ +- AMDGIM_FEATURE_MMHUB_REG_RLC_EN = (1 << 1), ++ AMDGIM_FEATURE_MMHUB_REG_RLC_EN = (1 << 1), + /* Use RLC to program GC regs */ +- AMDGIM_FEATURE_GC_REG_RLC_EN = (1 << 2), ++ AMDGIM_FEATURE_GC_REG_RLC_EN = (1 << 2), ++ /* Use PSP to program L1_TLB_CNTL*/ ++ AMDGIM_FEATURE_L1_TLB_CNTL_PSP_EN = (1 << 3), + }; + + struct amdgim_pf2vf_info_v1 { +@@ -330,6 +332,10 @@ struct amdgpu_video_codec_info; + (amdgpu_sriov_vf((adev)) && \ + ((adev)->virt.reg_access & (AMDGIM_FEATURE_GC_REG_RLC_EN))) + ++#define amdgpu_sriov_reg_indirect_l1_tlb_cntl(adev) \ ++(amdgpu_sriov_vf((adev)) && \ ++ ((adev)->virt.reg_access & (AMDGIM_FEATURE_L1_TLB_CNTL_PSP_EN))) ++ + #define amdgpu_sriov_rlcg_error_report_enabled(adev) \ + (amdgpu_sriov_reg_indirect_mmhub(adev) || amdgpu_sriov_reg_indirect_gc(adev)) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +index d6ac2652f0ac29..bea724981309cd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +@@ -109,10 +109,11 @@ union amd_sriov_msg_feature_flags { + + union amd_sriov_reg_access_flags { + struct { +- uint32_t vf_reg_access_ih : 1; +- uint32_t vf_reg_access_mmhub : 1; +- uint32_t vf_reg_access_gc : 1; +- uint32_t reserved : 29; ++ uint32_t vf_reg_access_ih : 1; ++ uint32_t vf_reg_access_mmhub : 1; ++ uint32_t vf_reg_access_gc : 1; ++ uint32_t vf_reg_access_l1_tlb_cntl : 1; ++ uint32_t reserved : 28; + } flags; + uint32_t all; + }; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index c68c2e2f4d61aa..2144d124c91084 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -4322,8 +4322,6 @@ static void gfx_v10_0_get_csb_buffer(struct amdgpu_device *adev, + PACKET3_SET_CONTEXT_REG_START); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 2a5c2a1ae3c74f..914c18f48e8e1a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -859,8 +859,6 @@ static void gfx_v11_0_get_csb_buffer(struct amdgpu_device *adev, + PACKET3_SET_CONTEXT_REG_START); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 13fbee46417af8..cee2cf47112c91 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -2874,8 +2874,6 @@ static void gfx_v6_0_get_csb_buffer(struct amdgpu_device *adev, + buffer[count++] = cpu_to_le32(ext->reg_index - 0xa000); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +index 8181bd0e4f189c..0deeee542623a0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +@@ -3906,8 +3906,6 @@ static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev, + buffer[count++] = cpu_to_le32(ext->reg_index - PACKET3_SET_CONTEXT_REG_START); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index bfedd487efc536..fc73be4ab0685b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -1248,8 +1248,6 @@ static void gfx_v8_0_get_csb_buffer(struct amdgpu_device *adev, + PACKET3_SET_CONTEXT_REG_START); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index d7db4cb907ae55..d725e2e230a3dc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1649,8 +1649,6 @@ static void gfx_v9_0_get_csb_buffer(struct amdgpu_device *adev, + PACKET3_SET_CONTEXT_REG_START); + for (i = 0; i < ext->reg_count; i++) + buffer[count++] = cpu_to_le32(ext->extent[i]); +- } else { +- return; + } + } + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +index 5effe8327d29fb..53050176c244da 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +@@ -1213,10 +1213,7 @@ static void gmc_v9_0_get_coherence_flags(struct amdgpu_device *adev, + if (uncached) { + mtype = MTYPE_UC; + } else if (ext_coherent) { +- if (gc_ip_version == IP_VERSION(9, 5, 0) || adev->rev_id) +- mtype = is_local ? MTYPE_CC : MTYPE_UC; +- else +- mtype = MTYPE_UC; ++ mtype = is_local ? MTYPE_CC : MTYPE_UC; + } else if (adev->flags & AMD_IS_APU) { + mtype = is_local ? mtype_local : MTYPE_NC; + } else { +@@ -1336,7 +1333,7 @@ static void gmc_v9_0_override_vm_pte_flags(struct amdgpu_device *adev, + mtype_local = MTYPE_CC; + + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, mtype_local); +- } else if (adev->rev_id) { ++ } else { + /* MTYPE_UC case */ + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_CC); + } +@@ -2411,13 +2408,6 @@ static int gmc_v9_0_hw_init(struct amdgpu_ip_block *ip_block) + adev->gmc.flush_tlb_needs_extra_type_2 = + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 0) && + adev->gmc.xgmi.num_physical_nodes; +- /* +- * TODO: This workaround is badly documented and had a buggy +- * implementation. We should probably verify what we do here. +- */ +- adev->gmc.flush_tlb_needs_extra_type_0 = +- amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) && +- adev->rev_id == 0; + + /* The sequence of these two function calls matters.*/ + gmc_v9_0_init_golden_registers(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +index ef9538fbbf5371..821c9baf5baa6a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +@@ -480,7 +480,7 @@ static int mes_v11_0_reset_hw_queue(struct amdgpu_mes *mes, + + return mes_v11_0_submit_pkt_and_poll_completion(mes, + &mes_reset_queue_pkt, sizeof(mes_reset_queue_pkt), +- offsetof(union MESAPI__REMOVE_QUEUE, api_status)); ++ offsetof(union MESAPI__RESET, api_status)); + } + + static int mes_v11_0_map_legacy_queue(struct amdgpu_mes *mes, +@@ -669,6 +669,18 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes, + offsetof(union MESAPI__MISC, api_status)); + } + ++static void mes_v11_0_set_gfx_hqd_mask(union MESAPI_SET_HW_RESOURCES *pkt) ++{ ++ /* ++ * GFX pipe 0 queue 0 is being used by Kernel queue. ++ * Set GFX pipe 0 queue 1 for MES scheduling ++ * mask = 10b ++ * GFX pipe 1 can't be used for MES due to HW limitation. ++ */ ++ pkt->gfx_hqd_mask[0] = 0x2; ++ pkt->gfx_hqd_mask[1] = 0; ++} ++ + static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes) + { + int i; +@@ -693,8 +705,7 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes) + mes_set_hw_res_pkt.compute_hqd_mask[i] = + mes->compute_hqd_mask[i]; + +- for (i = 0; i < MAX_GFX_PIPES; i++) +- mes_set_hw_res_pkt.gfx_hqd_mask[i] = mes->gfx_hqd_mask[i]; ++ mes_v11_0_set_gfx_hqd_mask(&mes_set_hw_res_pkt); + + for (i = 0; i < MAX_SDMA_PIPES; i++) + mes_set_hw_res_pkt.sdma_hqd_mask[i] = mes->sdma_hqd_mask[i]; +diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +index e6ab617b9a4041..7984ebda5b8bf5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +@@ -500,7 +500,7 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes, + + return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe, + &mes_reset_queue_pkt, sizeof(mes_reset_queue_pkt), +- offsetof(union MESAPI__REMOVE_QUEUE, api_status)); ++ offsetof(union MESAPI__RESET, api_status)); + } + + static int mes_v12_0_map_legacy_queue(struct amdgpu_mes *mes, +@@ -694,6 +694,17 @@ static int mes_v12_0_set_hw_resources_1(struct amdgpu_mes *mes, int pipe) + offsetof(union MESAPI_SET_HW_RESOURCES_1, api_status)); + } + ++static void mes_v12_0_set_gfx_hqd_mask(union MESAPI_SET_HW_RESOURCES *pkt) ++{ ++ /* ++ * GFX V12 has only one GFX pipe, but 8 queues in it. ++ * GFX pipe 0 queue 0 is being used by Kernel queue. ++ * Set GFX pipe 0 queue 1-7 for MES scheduling ++ * mask = 1111 1110b ++ */ ++ pkt->gfx_hqd_mask[0] = 0xFE; ++} ++ + static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe) + { + int i; +@@ -716,9 +727,7 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe) + mes_set_hw_res_pkt.compute_hqd_mask[i] = + mes->compute_hqd_mask[i]; + +- for (i = 0; i < MAX_GFX_PIPES; i++) +- mes_set_hw_res_pkt.gfx_hqd_mask[i] = +- mes->gfx_hqd_mask[i]; ++ mes_v12_0_set_gfx_hqd_mask(&mes_set_hw_res_pkt); + + for (i = 0; i < MAX_SDMA_PIPES; i++) + mes_set_hw_res_pkt.sdma_hqd_mask[i] = +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +index 84cde1239ee458..4a43c9ab95a2b1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +@@ -30,6 +30,7 @@ + #include "soc15_common.h" + #include "soc15.h" + #include "amdgpu_ras.h" ++#include "amdgpu_psp.h" + + #define regVM_L2_CNTL3_DEFAULT 0x80100007 + #define regVM_L2_CNTL4_DEFAULT 0x000000c1 +@@ -192,10 +193,8 @@ static void mmhub_v1_8_init_tlb_regs(struct amdgpu_device *adev) + uint32_t tmp, inst_mask; + int i; + +- /* Setup TLB control */ +- inst_mask = adev->aid_mask; +- for_each_inst(i, inst_mask) { +- tmp = RREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL); ++ if (amdgpu_sriov_reg_indirect_l1_tlb_cntl(adev)) { ++ tmp = RREG32_SOC15(MMHUB, 0, regMC_VM_MX_L1_TLB_CNTL); + + tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, + 1); +@@ -209,7 +208,26 @@ static void mmhub_v1_8_init_tlb_regs(struct amdgpu_device *adev) + MTYPE, MTYPE_UC);/* XXX for emulation. */ + tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1); + +- WREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL, tmp); ++ psp_reg_program_no_ring(&adev->psp, tmp, PSP_REG_MMHUB_L1_TLB_CNTL); ++ } else { ++ inst_mask = adev->aid_mask; ++ for_each_inst(i, inst_mask) { ++ tmp = RREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL); ++ ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, ++ 1); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ SYSTEM_ACCESS_MODE, 3); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ ENABLE_ADVANCED_DRIVER_MODEL, 1); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ SYSTEM_APERTURE_UNMAPPED_ACCESS, 0); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ MTYPE, MTYPE_UC);/* XXX for emulation. */ ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1); ++ ++ WREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL, tmp); ++ } + } + } + +@@ -454,6 +472,30 @@ static int mmhub_v1_8_gart_enable(struct amdgpu_device *adev) + return 0; + } + ++static void mmhub_v1_8_disable_l1_tlb(struct amdgpu_device *adev) ++{ ++ u32 tmp; ++ u32 i, inst_mask; ++ ++ if (amdgpu_sriov_reg_indirect_l1_tlb_cntl(adev)) { ++ tmp = RREG32_SOC15(MMHUB, 0, regMC_VM_MX_L1_TLB_CNTL); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, 0); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ ENABLE_ADVANCED_DRIVER_MODEL, 0); ++ psp_reg_program_no_ring(&adev->psp, tmp, PSP_REG_MMHUB_L1_TLB_CNTL); ++ } else { ++ inst_mask = adev->aid_mask; ++ for_each_inst(i, inst_mask) { ++ tmp = RREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, ++ 0); ++ tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ++ ENABLE_ADVANCED_DRIVER_MODEL, 0); ++ WREG32_SOC15(MMHUB, i, regMC_VM_MX_L1_TLB_CNTL, tmp); ++ } ++ } ++} ++ + static void mmhub_v1_8_gart_disable(struct amdgpu_device *adev) + { + struct amdgpu_vmhub *hub; +@@ -467,15 +509,6 @@ static void mmhub_v1_8_gart_disable(struct amdgpu_device *adev) + for (i = 0; i < 16; i++) + WREG32_SOC15_OFFSET(MMHUB, j, regVM_CONTEXT0_CNTL, + i * hub->ctx_distance, 0); +- +- /* Setup TLB control */ +- tmp = RREG32_SOC15(MMHUB, j, regMC_VM_MX_L1_TLB_CNTL); +- tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, +- 0); +- tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, +- ENABLE_ADVANCED_DRIVER_MODEL, 0); +- WREG32_SOC15(MMHUB, j, regMC_VM_MX_L1_TLB_CNTL, tmp); +- + if (!amdgpu_sriov_vf(adev)) { + /* Setup L2 cache */ + tmp = RREG32_SOC15(MMHUB, j, regVM_L2_CNTL); +@@ -485,6 +518,8 @@ static void mmhub_v1_8_gart_disable(struct amdgpu_device *adev) + WREG32_SOC15(MMHUB, j, regVM_L2_CNTL3, 0); + } + } ++ ++ mmhub_v1_8_disable_l1_tlb(adev); + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +index afdf8ce3b4c59e..f5f616ab20e704 100644 +--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +@@ -858,6 +858,25 @@ static bool psp_v13_0_is_reload_needed(struct psp_context *psp) + return false; + } + ++static int psp_v13_0_reg_program_no_ring(struct psp_context *psp, uint32_t val, ++ enum psp_reg_prog_id id) ++{ ++ struct amdgpu_device *adev = psp->adev; ++ int ret = -EOPNOTSUPP; ++ ++ /* PSP will broadcast the value to all instances */ ++ if (amdgpu_sriov_vf(adev)) { ++ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_GBR_IH_SET); ++ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_102, id); ++ WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_103, val); ++ ++ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101), ++ 0x80000000, 0x80000000, false); ++ } ++ ++ return ret; ++} ++ + static const struct psp_funcs psp_v13_0_funcs = { + .init_microcode = psp_v13_0_init_microcode, + .wait_for_bootloader = psp_v13_0_wait_for_bootloader_steady_state, +@@ -884,6 +903,7 @@ static const struct psp_funcs psp_v13_0_funcs = { + .get_ras_capability = psp_v13_0_get_ras_capability, + .is_aux_sos_load_required = psp_v13_0_is_aux_sos_load_required, + .is_reload_needed = psp_v13_0_is_reload_needed, ++ .reg_program_no_ring = psp_v13_0_reg_program_no_ring, + }; + + void psp_v13_0_set_psp_funcs(struct psp_context *psp) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +index b9c82be6ce134f..bf0854bd55551b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -352,11 +352,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) + f2g = &aldebaran_kfd2kgd; + break; + case IP_VERSION(9, 4, 3): +- gfx_target_version = adev->rev_id >= 1 ? 90402 +- : adev->flags & AMD_IS_APU ? 90400 +- : 90401; +- f2g = &gc_9_4_3_kfd2kgd; +- break; + case IP_VERSION(9, 4, 4): + gfx_target_version = 90402; + f2g = &gc_9_4_3_kfd2kgd; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +index 80320a6c8854a5..97933d2a380323 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +@@ -495,6 +495,10 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, + m->sdma_engine_id = q->sdma_engine_id; + m->sdma_queue_id = q->sdma_queue_id; + m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; ++ /* Allow context switch so we don't cross-process starve with a massive ++ * command buffer of long-running SDMA commands ++ */ ++ m->sdmax_rlcx_ib_cntl |= SDMA0_GFX_IB_CNTL__SWITCH_INSIDE_IB_MASK; + + q->is_active = QUEUE_IS_ACTIVE(*q); + } +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +index 4afff7094cafcd..a65c67cf56ff37 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +@@ -402,7 +402,7 @@ static u32 kfd_get_vgpr_size_per_cu(u32 gfxv) + { + u32 vgpr_size = 0x40000; + +- if ((gfxv / 100 * 100) == 90400 || /* GFX_VERSION_AQUA_VANJARAM */ ++ if (gfxv == 90402 || /* GFX_VERSION_AQUA_VANJARAM */ + gfxv == 90010 || /* GFX_VERSION_ALDEBARAN */ + gfxv == 90008 || /* GFX_VERSION_ARCTURUS */ + gfxv == 90500) +@@ -462,7 +462,7 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev) + + if (gfxv == 80002) /* GFX_VERSION_TONGA */ + props->eop_buffer_size = 0x8000; +- else if ((gfxv / 100 * 100) == 90400) /* GFX_VERSION_AQUA_VANJARAM */ ++ else if (gfxv == 90402) /* GFX_VERSION_AQUA_VANJARAM */ + props->eop_buffer_size = 4096; + else if (gfxv >= 80000) + props->eop_buffer_size = 4096; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +index 100717a98ec113..72be6e152e881e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +@@ -1245,8 +1245,7 @@ svm_range_get_pte_flags(struct kfd_node *node, + case IP_VERSION(9, 4, 4): + case IP_VERSION(9, 5, 0): + if (ext_coherent) +- mtype_local = (gc_ip_version < IP_VERSION(9, 5, 0) && !node->adev->rev_id) ? +- AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_CC; ++ mtype_local = AMDGPU_VM_MTYPE_CC; + else + mtype_local = amdgpu_mtype_local == 1 ? AMDGPU_VM_MTYPE_NC : + amdgpu_mtype_local == 2 ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +index 9bbee484d57cc4..d6653e39e1477b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +@@ -510,6 +510,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, + dev->node_props.capability |= + HSA_CAP_AQL_QUEUE_DOUBLE_MAP; + ++ if (KFD_GC_VERSION(dev->gpu) < IP_VERSION(10, 0, 0) && ++ (dev->gpu->adev->sdma.supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE)) ++ dev->node_props.capability2 |= HSA_CAP2_PER_SDMA_QUEUE_RESET_SUPPORTED; ++ + sysfs_show_32bit_prop(buffer, offs, "max_engine_clk_fcompute", + dev->node_props.max_engine_clk_fcompute); + +@@ -2001,8 +2005,6 @@ static void kfd_topology_set_capabilities(struct kfd_topology_device *dev) + if (!amdgpu_sriov_vf(dev->gpu->adev)) + dev->node_props.capability |= HSA_CAP_PER_QUEUE_RESET_SUPPORTED; + +- if (dev->gpu->adev->sdma.supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE) +- dev->node_props.capability2 |= HSA_CAP2_PER_SDMA_QUEUE_RESET_SUPPORTED; + } else { + dev->node_props.debug_prop |= HSA_DBG_WATCH_ADDR_MASK_LO_BIT_GFX10 | + HSA_DBG_WATCH_ADDR_MASK_HI_BIT; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +index ab2a97e354da1f..7329b8cc2576ea 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +@@ -38,6 +38,7 @@ AMDGPUDM = \ + amdgpu_dm_pp_smu.o \ + amdgpu_dm_psr.o \ + amdgpu_dm_replay.o \ ++ amdgpu_dm_quirks.o \ + amdgpu_dm_wb.o + + ifdef CONFIG_DRM_AMD_DC_FP +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 0fe8bd19ecd13e..96118a0e1ffeb2 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -80,7 +80,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -1631,153 +1630,6 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev) + return false; + } + +-struct amdgpu_dm_quirks { +- bool aux_hpd_discon; +- bool support_edp0_on_dp1; +-}; +- +-static struct amdgpu_dm_quirks quirk_entries = { +- .aux_hpd_discon = false, +- .support_edp0_on_dp1 = false +-}; +- +-static int edp0_on_dp1_callback(const struct dmi_system_id *id) +-{ +- quirk_entries.support_edp0_on_dp1 = true; +- return 0; +-} +- +-static int aux_hpd_discon_callback(const struct dmi_system_id *id) +-{ +- quirk_entries.aux_hpd_discon = true; +- return 0; +-} +- +-static const struct dmi_system_id dmi_quirk_table[] = { +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower Plus 7010"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower 7010"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF Plus 7010"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF 7010"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro Plus 7010"), +- }, +- }, +- { +- .callback = aux_hpd_discon_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro 7010"), +- }, +- }, +- { +- .callback = edp0_on_dp1_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "HP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite mt645 G8 Mobile Thin Client"), +- }, +- }, +- { +- .callback = edp0_on_dp1_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "HP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 645 14 inch G11 Notebook PC"), +- }, +- }, +- { +- .callback = edp0_on_dp1_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "HP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 665 16 inch G11 Notebook PC"), +- }, +- }, +- { +- .callback = edp0_on_dp1_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "HP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 445 14 inch G11 Notebook PC"), +- }, +- }, +- { +- .callback = edp0_on_dp1_callback, +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "HP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 465 16 inch G11 Notebook PC"), +- }, +- }, +- {} +- /* TODO: refactor this from a fixed table to a dynamic option */ +-}; +- +-static void retrieve_dmi_info(struct amdgpu_display_manager *dm, struct dc_init_data *init_data) +-{ +- int dmi_id; +- struct drm_device *dev = dm->ddev; +- +- dm->aux_hpd_discon_quirk = false; +- init_data->flags.support_edp0_on_dp1 = false; +- +- dmi_id = dmi_check_system(dmi_quirk_table); +- +- if (!dmi_id) +- return; +- +- if (quirk_entries.aux_hpd_discon) { +- dm->aux_hpd_discon_quirk = true; +- drm_info(dev, "aux_hpd_discon_quirk attached\n"); +- } +- if (quirk_entries.support_edp0_on_dp1) { +- init_data->flags.support_edp0_on_dp1 = true; +- drm_info(dev, "support_edp0_on_dp1 attached\n"); +- } +-} + + void* + dm_allocate_gpu_mem( +@@ -2064,7 +1916,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) + init_data.num_virtual_links = 1; + +- retrieve_dmi_info(&adev->dm, &init_data); ++ retrieve_dmi_info(&adev->dm); ++ if (adev->dm.edp0_on_dp1_quirk) ++ init_data.flags.support_edp0_on_dp1 = true; + + if (adev->dm.bb_from_dmub) + init_data.bb_from_dmub = adev->dm.bb_from_dmub; +@@ -10510,16 +10364,20 @@ static int dm_force_atomic_commit(struct drm_connector *connector) + */ + conn_state = drm_atomic_get_connector_state(state, connector); + +- ret = PTR_ERR_OR_ZERO(conn_state); +- if (ret) ++ /* Check for error in getting connector state */ ++ if (IS_ERR(conn_state)) { ++ ret = PTR_ERR(conn_state); + goto out; ++ } + + /* Attach crtc to drm_atomic_state*/ + crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base); + +- ret = PTR_ERR_OR_ZERO(crtc_state); +- if (ret) ++ /* Check for error in getting crtc state */ ++ if (IS_ERR(crtc_state)) { ++ ret = PTR_ERR(crtc_state); + goto out; ++ } + + /* force a restore */ + crtc_state->mode_changed = true; +@@ -10527,9 +10385,11 @@ static int dm_force_atomic_commit(struct drm_connector *connector) + /* Attach plane to drm_atomic_state */ + plane_state = drm_atomic_get_plane_state(state, plane); + +- ret = PTR_ERR_OR_ZERO(plane_state); +- if (ret) ++ /* Check for error in getting plane state */ ++ if (IS_ERR(plane_state)) { ++ ret = PTR_ERR(plane_state); + goto out; ++ } + + /* Call commit internally with the state we just constructed */ + ret = drm_atomic_commit(state); +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 385faaca6e26a6..9e8c659c53c496 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -613,6 +613,13 @@ struct amdgpu_display_manager { + */ + bool aux_hpd_discon_quirk; + ++ /** ++ * @edp0_on_dp1_quirk: ++ * ++ * quirk for platforms that put edp0 on DP1. ++ */ ++ bool edp0_on_dp1_quirk; ++ + /** + * @dpia_aux_lock: + * +@@ -1045,4 +1052,6 @@ void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector); + void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector); + int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector); + ++void retrieve_dmi_info(struct amdgpu_display_manager *dm); ++ + #endif /* __AMDGPU_DM_H__ */ +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 5cdbc86ef8f5a9..25e8befbcc479a 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -1739,16 +1739,17 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream, + struct dc_dsc_bw_range *bw_range) + { + struct dc_dsc_policy dsc_policy = {0}; ++ bool is_dsc_possible; + + dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); +- dc_dsc_compute_bandwidth_range(stream->sink->ctx->dc->res_pool->dscs[0], +- stream->sink->ctx->dc->debug.dsc_min_slice_height_override, +- dsc_policy.min_target_bpp * 16, +- dsc_policy.max_target_bpp * 16, +- &stream->sink->dsc_caps.dsc_dec_caps, +- &stream->timing, dc_link_get_highest_encoding_format(stream->link), bw_range); +- +- return bw_range->max_target_bpp_x16 && bw_range->min_target_bpp_x16; ++ is_dsc_possible = dc_dsc_compute_bandwidth_range(stream->sink->ctx->dc->res_pool->dscs[0], ++ stream->sink->ctx->dc->debug.dsc_min_slice_height_override, ++ dsc_policy.min_target_bpp * 16, ++ dsc_policy.max_target_bpp * 16, ++ &stream->sink->dsc_caps.dsc_dec_caps, ++ &stream->timing, dc_link_get_highest_encoding_format(stream->link), bw_range); ++ ++ return is_dsc_possible; + } + #endif + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c +new file mode 100644 +index 00000000000000..1da07ebf9217c0 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c +@@ -0,0 +1,178 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright 2025 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include ++ ++#include "amdgpu.h" ++#include "amdgpu_dm.h" ++ ++struct amdgpu_dm_quirks { ++ bool aux_hpd_discon; ++ bool support_edp0_on_dp1; ++}; ++ ++static struct amdgpu_dm_quirks quirk_entries = { ++ .aux_hpd_discon = false, ++ .support_edp0_on_dp1 = false ++}; ++ ++static int edp0_on_dp1_callback(const struct dmi_system_id *id) ++{ ++ quirk_entries.support_edp0_on_dp1 = true; ++ return 0; ++} ++ ++static int aux_hpd_discon_callback(const struct dmi_system_id *id) ++{ ++ quirk_entries.aux_hpd_discon = true; ++ return 0; ++} ++ ++static const struct dmi_system_id dmi_quirk_table[] = { ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower Plus 7010"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Tower 7010"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF Plus 7010"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex SFF 7010"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro Plus 7010"), ++ }, ++ }, ++ { ++ .callback = aux_hpd_discon_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex Micro 7010"), ++ }, ++ }, ++ { ++ .callback = edp0_on_dp1_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite mt645 G8 Mobile Thin Client"), ++ }, ++ }, ++ { ++ .callback = edp0_on_dp1_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 645 14 inch G11 Notebook PC"), ++ }, ++ }, ++ { ++ .callback = edp0_on_dp1_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 665 16 inch G11 Notebook PC"), ++ }, ++ }, ++ { ++ .callback = edp0_on_dp1_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 445 14 inch G11 Notebook PC"), ++ }, ++ }, ++ { ++ .callback = edp0_on_dp1_callback, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 465 16 inch G11 Notebook PC"), ++ }, ++ }, ++ {} ++ /* TODO: refactor this from a fixed table to a dynamic option */ ++}; ++ ++void retrieve_dmi_info(struct amdgpu_display_manager *dm) ++{ ++ struct drm_device *dev = dm->ddev; ++ int dmi_id; ++ ++ dm->aux_hpd_discon_quirk = false; ++ dm->edp0_on_dp1_quirk = false; ++ ++ dmi_id = dmi_check_system(dmi_quirk_table); ++ ++ if (!dmi_id) ++ return; ++ ++ if (quirk_entries.aux_hpd_discon) { ++ dm->aux_hpd_discon_quirk = true; ++ drm_info(dev, "aux_hpd_discon_quirk attached\n"); ++ } ++ if (quirk_entries.support_edp0_on_dp1) { ++ dm->edp0_on_dp1_quirk = true; ++ drm_info(dev, "support_edp0_on_dp1 attached\n"); ++ } ++} +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn351_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn351_clk_mgr.c +index 6a6ae618650b6d..4607eff07253c2 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn351_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn351_clk_mgr.c +@@ -65,6 +65,7 @@ + #define mmCLK1_CLK5_ALLOW_DS 0x16EB1 + + #define mmCLK5_spll_field_8 0x1B04B ++#define mmCLK6_spll_field_8 0x1B24B + #define mmDENTIST_DISPCLK_CNTL 0x0124 + #define regDENTIST_DISPCLK_CNTL 0x0064 + #define regDENTIST_DISPCLK_CNTL_BASE_IDX 1 +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +index 142de8938d7c3d..bb1ac12a2b0955 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +@@ -90,6 +90,7 @@ + #define mmCLK1_CLK5_ALLOW_DS 0x16EB1 + + #define mmCLK5_spll_field_8 0x1B24B ++#define mmCLK6_spll_field_8 0x1B24B + #define mmDENTIST_DISPCLK_CNTL 0x0124 + #define regDENTIST_DISPCLK_CNTL 0x0064 + #define regDENTIST_DISPCLK_CNTL_BASE_IDX 1 +@@ -116,6 +117,7 @@ + #define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_WDIVIDER_MASK 0x7F000000L + + #define CLK5_spll_field_8__spll_ssc_en_MASK 0x00002000L ++#define CLK6_spll_field_8__spll_ssc_en_MASK 0x00002000L + + #define SMU_VER_THRESHOLD 0x5D4A00 //93.74.0 + #undef FN +@@ -596,7 +598,11 @@ static bool dcn35_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base) + + uint32_t ssc_enable; + +- ssc_enable = REG_READ(CLK5_spll_field_8) & CLK5_spll_field_8__spll_ssc_en_MASK; ++ if (clk_mgr_base->ctx->dce_version == DCN_VERSION_3_51) { ++ ssc_enable = REG_READ(CLK6_spll_field_8) & CLK6_spll_field_8__spll_ssc_en_MASK; ++ } else { ++ ssc_enable = REG_READ(CLK5_spll_field_8) & CLK5_spll_field_8__spll_ssc_en_MASK; ++ } + + return ssc_enable != 0; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c +index b363f5360818d8..ad910065f463fe 100644 +--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c ++++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c +@@ -391,6 +391,7 @@ static void dccg35_set_dppclk_rcg(struct dccg *dccg, + + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + ++ + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && enable) + return; + +@@ -411,6 +412,8 @@ static void dccg35_set_dppclk_rcg(struct dccg *dccg, + BREAK_TO_DEBUGGER(); + break; + } ++ //DC_LOG_DEBUG("%s: inst(%d) DPPCLK rcg_disable: %d\n", __func__, inst, enable ? 0 : 1); ++ + } + + static void dccg35_set_dpstreamclk_rcg( +@@ -1112,30 +1115,24 @@ static void dcn35_set_dppclk_enable(struct dccg *dccg, + { + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + ++ + switch (dpp_inst) { + case 0: + REG_UPDATE(DPPCLK_CTRL, DPPCLK0_EN, enable); +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) +- REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable); + break; + case 1: + REG_UPDATE(DPPCLK_CTRL, DPPCLK1_EN, enable); +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) +- REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable); + break; + case 2: + REG_UPDATE(DPPCLK_CTRL, DPPCLK2_EN, enable); +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) +- REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable); + break; + case 3: + REG_UPDATE(DPPCLK_CTRL, DPPCLK3_EN, enable); +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) +- REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable); + break; + default: + break; + } ++ //DC_LOG_DEBUG("%s: dpp_inst(%d) DPPCLK_EN = %d\n", __func__, dpp_inst, enable); + + } + +@@ -1163,14 +1160,18 @@ static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst, + ASSERT(false); + phase = 0xff; + } ++ dccg35_set_dppclk_rcg(dccg, dpp_inst, false); + + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, phase, + DPPCLK0_DTO_MODULO, modulo); + + dcn35_set_dppclk_enable(dccg, dpp_inst, true); +- } else ++ } else { + dcn35_set_dppclk_enable(dccg, dpp_inst, false); ++ /*we have this in hwss: disable_plane*/ ++ //dccg35_set_dppclk_rcg(dccg, dpp_inst, true); ++ } + dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk; + } + +@@ -1182,6 +1183,7 @@ static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg, + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) + return; + ++ + switch (dpp_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable); +@@ -1198,6 +1200,8 @@ static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg, + default: + break; + } ++ //DC_LOG_DEBUG("%s: dpp_inst(%d) rcg: %d\n", __func__, dpp_inst, enable); ++ + } + + static void dccg35_get_pixel_rate_div( +@@ -1521,28 +1525,30 @@ static void dccg35_set_physymclk_root_clock_gating( + switch (phy_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, +- PHYASYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0); ++ PHYASYMCLK_ROOT_GATE_DISABLE, enable ? 0 : 1); + break; + case 1: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, +- PHYBSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0); ++ PHYBSYMCLK_ROOT_GATE_DISABLE, enable ? 0 : 1); + break; + case 2: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, +- PHYCSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0); ++ PHYCSYMCLK_ROOT_GATE_DISABLE, enable ? 0 : 1); + break; + case 3: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, +- PHYDSYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0); ++ PHYDSYMCLK_ROOT_GATE_DISABLE, enable ? 0 : 1); + break; + case 4: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, +- PHYESYMCLK_ROOT_GATE_DISABLE, enable ? 1 : 0); ++ PHYESYMCLK_ROOT_GATE_DISABLE, enable ? 0 : 1); + break; + default: + BREAK_TO_DEBUGGER(); + return; + } ++ //DC_LOG_DEBUG("%s: dpp_inst(%d) PHYESYMCLK_ROOT_GATE_DISABLE:\n", __func__, phy_inst, enable ? 0 : 1); ++ + } + + static void dccg35_set_physymclk( +@@ -1643,6 +1649,8 @@ static void dccg35_dpp_root_clock_control( + return; + + if (clock_on) { ++ dccg35_set_dppclk_rcg(dccg, dpp_inst, false); ++ + /* turn off the DTO and leave phase/modulo at max */ + dcn35_set_dppclk_enable(dccg, dpp_inst, 1); + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, +@@ -1654,6 +1662,8 @@ static void dccg35_dpp_root_clock_control( + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, 0, + DPPCLK0_DTO_MODULO, 1); ++ /*we have this in hwss: disable_plane*/ ++ //dccg35_set_dppclk_rcg(dccg, dpp_inst, true); + } + + dccg->dpp_clock_gated[dpp_inst] = !clock_on; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +index f1fe49401bc0ac..8d24763938ea6d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +@@ -1002,6 +1002,7 @@ static bool CalculatePrefetchSchedule( + + dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime + - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal); ++ dst_y_prefetch_equ = dml_min(dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH + + Lsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC); + Tsw_oto = Lsw_oto * LineTime; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +index f567a9023682d1..ed59c77bc6f60a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +@@ -1105,6 +1105,7 @@ static bool CalculatePrefetchSchedule( + Tr0_oto_lines = dml_ceil(4.0 * Tr0_oto / LineTime, 1) / 4.0; + dst_y_prefetch_oto = Tvm_oto_lines + 2 * Tr0_oto_lines + Lsw_oto; + dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal); ++ dst_y_prefetch_equ = dml_min(dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH + dst_y_prefetch_equ = dml_floor(4.0 * (dst_y_prefetch_equ + 0.125), 1) / 4.0; + Tpre_rounded = dst_y_prefetch_equ * LineTime; + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +index 5865e8fa2d8e8f..9f3938a50240f3 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +@@ -1123,6 +1123,7 @@ static bool CalculatePrefetchSchedule( + Tr0_oto_lines = dml_ceil(4.0 * Tr0_oto / LineTime, 1) / 4.0; + dst_y_prefetch_oto = Tvm_oto_lines + 2 * Tr0_oto_lines + Lsw_oto; + dst_y_prefetch_equ = VStartup - (*TSetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal); ++ dst_y_prefetch_equ = dml_min(dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH + dst_y_prefetch_equ = dml_floor(4.0 * (dst_y_prefetch_equ + 0.125), 1) / 4.0; + Tpre_rounded = dst_y_prefetch_equ * LineTime; + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +index ab6baf2698012c..5de775fd8fceef 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +@@ -896,7 +896,7 @@ static void populate_dummy_dml_surface_cfg(struct dml_surface_cfg_st *out, unsig + out->SurfaceWidthC[location] = in->timing.h_addressable; + out->SurfaceHeightC[location] = in->timing.v_addressable; + out->PitchY[location] = ((out->SurfaceWidthY[location] + 127) / 128) * 128; +- out->PitchC[location] = 0; ++ out->PitchC[location] = 1; + out->DCCEnable[location] = false; + out->DCCMetaPitchY[location] = 0; + out->DCCMetaPitchC[location] = 0; +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c +index e89571874185ee..525b7d04bf84cd 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c +@@ -663,7 +663,10 @@ static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_s + dml2_copy_clocks_to_dc_state(&out_clks, context); + dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.a, &dml2->v20.dml_core_ctx); + dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx); +- memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c)); ++ if (context->streams[0]->sink->link->dc->caps.is_apu) ++ dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.dml_core_ctx); ++ else ++ memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c)); + dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx); + dml2_extract_writeback_wm(context, &dml2->v20.dml_core_ctx); + //copy for deciding zstate use +diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c +index 62b7012cda4304..f7a373a3d70a52 100644 +--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c ++++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c +@@ -138,7 +138,7 @@ bool dpp35_construct( + dpp->base.funcs = &dcn35_dpp_funcs; + + // w/a for cursor memory stuck in LS by programming DISPCLK_R_GATE_DISABLE, limit w/a to some ASIC revs +- if (dpp->base.ctx->asic_id.hw_internal_rev <= 0x10) ++ if (dpp->base.ctx->asic_id.hw_internal_rev < 0x40) + dpp->dispclk_r_gate_disable = true; + return ret; + } +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c +index be26c925fdfa1a..e68f21fd5f0fb4 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c +@@ -84,6 +84,20 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg = {0}; + enum optc_dsc_mode optc_dsc_mode; ++ struct dcn_dsc_state dsc_state = {0}; ++ ++ if (!dsc) { ++ DC_LOG_DSC("DSC is NULL for tg instance %d:", pipe_ctx->stream_res.tg->inst); ++ return; ++ } ++ ++ if (dsc->funcs->dsc_read_state) { ++ dsc->funcs->dsc_read_state(dsc, &dsc_state); ++ if (!dsc_state.dsc_fw_en) { ++ DC_LOG_DSC("DSC has been disabled for tg instance %d:", pipe_ctx->stream_res.tg->inst); ++ return; ++ } ++ } + + /* Enable DSC hw block */ + dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +index 922b8d71cf1aa5..63077c1fad859c 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +@@ -241,11 +241,6 @@ void dcn35_init_hw(struct dc *dc) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } +- if (res_pool->dccg->funcs->dccg_root_gate_disable_control) { +- for (i = 0; i < res_pool->pipe_count; i++) +- res_pool->dccg->funcs->dccg_root_gate_disable_control(res_pool->dccg, i, 0); +- } +- + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + +@@ -901,12 +896,18 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) + void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, + struct dc_state *context) + { ++ struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dccg *dccg = dc->res_pool->dccg; ++ ++ + /* enable DCFCLK current DCHUB */ + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + + /* initialize HUBP on power up */ + pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); +- ++ /*make sure DPPCLK is on*/ ++ dccg->funcs->dccg_root_gate_disable_control(dccg, dpp->inst, true); ++ dpp->funcs->dpp_dppclk_control(dpp, false, true); + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, +@@ -923,6 +924,7 @@ void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, + // Program system aperture settings + pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); + } ++ //DC_LOG_DEBUG("%s: dpp_inst(%d) =\n", __func__, dpp->inst); + + if (!pipe_ctx->top_pipe + && pipe_ctx->plane_state +@@ -938,6 +940,8 @@ void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) + { + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dccg *dccg = dc->res_pool->dccg; ++ + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + +@@ -955,7 +959,8 @@ void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) + hubp->funcs->hubp_clk_cntl(hubp, false); + + dpp->funcs->dpp_dppclk_control(dpp, false, false); +-/*to do, need to support both case*/ ++ dccg->funcs->dccg_root_gate_disable_control(dccg, dpp->inst, false); ++ + hubp->power_gated = true; + + hubp->funcs->hubp_reset(hubp); +@@ -967,6 +972,8 @@ void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->plane_state = NULL; ++ //DC_LOG_DEBUG("%s: dpp_inst(%d)=\n", __func__, dpp->inst); ++ + } + + void dcn35_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +index 221645c023b502..bac8febad69a54 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +@@ -199,6 +199,7 @@ enum dentist_divider_range { + CLK_SR_DCN35(CLK1_CLK4_ALLOW_DS), \ + CLK_SR_DCN35(CLK1_CLK5_ALLOW_DS), \ + CLK_SR_DCN35(CLK5_spll_field_8), \ ++ CLK_SR_DCN35(CLK6_spll_field_8), \ + SR(DENTIST_DISPCLK_CNTL), \ + + #define CLK_COMMON_MASK_SH_LIST_DCN32(mask_sh) \ +@@ -307,7 +308,7 @@ struct clk_mgr_registers { + uint32_t CLK1_CLK4_ALLOW_DS; + uint32_t CLK1_CLK5_ALLOW_DS; + uint32_t CLK5_spll_field_8; +- ++ uint32_t CLK6_spll_field_8; + }; + + struct clk_mgr_shift { +diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c +index f0ac0aeeac512c..f839afacd5a5c0 100644 +--- a/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c ++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn32/irq_service_dcn32.c +@@ -191,6 +191,16 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .ack = NULL + }; + ++static struct irq_source_info_funcs vline1_irq_info_funcs = { ++ .set = NULL, ++ .ack = NULL ++}; ++ ++static struct irq_source_info_funcs vline2_irq_info_funcs = { ++ .set = NULL, ++ .ack = NULL ++}; ++ + #undef BASE_INNER + #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +@@ -259,6 +269,13 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .funcs = &pflip_irq_info_funcs\ + } + ++#define vblank_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ ++ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ ++ .funcs = &vblank_irq_info_funcs\ ++ } + /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +@@ -270,14 +287,6 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .funcs = &vupdate_no_lock_irq_info_funcs\ + } + +-#define vblank_int_entry(reg_num)\ +- [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ +- IRQ_REG_ENTRY(OTG, reg_num,\ +- OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ +- OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ +- .funcs = &vblank_irq_info_funcs\ +-} +- + #define vline0_int_entry(reg_num)\ + [DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ +@@ -285,6 +294,20 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\ + .funcs = &vline0_irq_info_funcs\ + } ++#define vline1_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_DC1_VLINE1 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE,\ ++ OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_CLEAR),\ ++ .funcs = &vline1_irq_info_funcs\ ++ } ++#define vline2_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\ ++ OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\ ++ .funcs = &vline2_irq_info_funcs\ ++ } + #define dmub_outbox_int_entry()\ + [DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\ + IRQ_REG_ENTRY_DMUB(\ +@@ -387,21 +410,29 @@ irq_source_info_dcn32[DAL_IRQ_SOURCES_NUMBER] = { + dc_underflow_int_entry(6), + [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), + [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), +- vupdate_no_lock_int_entry(0), +- vupdate_no_lock_int_entry(1), +- vupdate_no_lock_int_entry(2), +- vupdate_no_lock_int_entry(3), + vblank_int_entry(0), + vblank_int_entry(1), + vblank_int_entry(2), + vblank_int_entry(3), ++ [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(), ++ [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(), ++ dmub_outbox_int_entry(), ++ vupdate_no_lock_int_entry(0), ++ vupdate_no_lock_int_entry(1), ++ vupdate_no_lock_int_entry(2), ++ vupdate_no_lock_int_entry(3), + vline0_int_entry(0), + vline0_int_entry(1), + vline0_int_entry(2), + vline0_int_entry(3), +- [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(), +- [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(), +- dmub_outbox_int_entry(), ++ vline1_int_entry(0), ++ vline1_int_entry(1), ++ vline1_int_entry(2), ++ vline1_int_entry(3), ++ vline2_int_entry(0), ++ vline2_int_entry(1), ++ vline2_int_entry(2), ++ vline2_int_entry(3) + }; + + static const struct irq_service_funcs irq_service_funcs_dcn32 = { +diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c +index b43c9524b0de1e..8499e505cf3ef7 100644 +--- a/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c ++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn401/irq_service_dcn401.c +@@ -171,6 +171,16 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .ack = NULL + }; + ++static struct irq_source_info_funcs vline1_irq_info_funcs = { ++ .set = NULL, ++ .ack = NULL ++}; ++ ++static struct irq_source_info_funcs vline2_irq_info_funcs = { ++ .set = NULL, ++ .ack = NULL ++}; ++ + #undef BASE_INNER + #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +@@ -239,6 +249,13 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .funcs = &pflip_irq_info_funcs\ + } + ++#define vblank_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ ++ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ ++ .funcs = &vblank_irq_info_funcs\ ++ } + /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +@@ -250,13 +267,6 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + .funcs = &vupdate_no_lock_irq_info_funcs\ + } + +-#define vblank_int_entry(reg_num)\ +- [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ +- IRQ_REG_ENTRY(OTG, reg_num,\ +- OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ +- OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ +- .funcs = &vblank_irq_info_funcs\ +- } + #define vline0_int_entry(reg_num)\ + [DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ +@@ -264,6 +274,20 @@ static struct irq_source_info_funcs vline0_irq_info_funcs = { + OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\ + .funcs = &vline0_irq_info_funcs\ + } ++#define vline1_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_DC1_VLINE1 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE,\ ++ OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_CLEAR),\ ++ .funcs = &vline1_irq_info_funcs\ ++ } ++#define vline2_int_entry(reg_num)\ ++ [DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\ ++ IRQ_REG_ENTRY(OTG, reg_num,\ ++ OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\ ++ OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\ ++ .funcs = &vline2_irq_info_funcs\ ++ } + #define dmub_outbox_int_entry()\ + [DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\ + IRQ_REG_ENTRY_DMUB(\ +@@ -364,21 +388,29 @@ irq_source_info_dcn401[DAL_IRQ_SOURCES_NUMBER] = { + dc_underflow_int_entry(6), + [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), + [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), +- vupdate_no_lock_int_entry(0), +- vupdate_no_lock_int_entry(1), +- vupdate_no_lock_int_entry(2), +- vupdate_no_lock_int_entry(3), + vblank_int_entry(0), + vblank_int_entry(1), + vblank_int_entry(2), + vblank_int_entry(3), ++ [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(), ++ [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(), ++ dmub_outbox_int_entry(), ++ vupdate_no_lock_int_entry(0), ++ vupdate_no_lock_int_entry(1), ++ vupdate_no_lock_int_entry(2), ++ vupdate_no_lock_int_entry(3), + vline0_int_entry(0), + vline0_int_entry(1), + vline0_int_entry(2), + vline0_int_entry(3), +- [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(), +- [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(), +- dmub_outbox_int_entry(), ++ vline1_int_entry(0), ++ vline1_int_entry(1), ++ vline1_int_entry(2), ++ vline1_int_entry(3), ++ vline2_int_entry(0), ++ vline2_int_entry(1), ++ vline2_int_entry(2), ++ vline2_int_entry(3), + }; + + static const struct irq_service_funcs irq_service_funcs_dcn401 = { +diff --git a/drivers/gpu/drm/amd/display/dc/irq_types.h b/drivers/gpu/drm/amd/display/dc/irq_types.h +index 110f656d43aee0..eadab0a2afebe7 100644 +--- a/drivers/gpu/drm/amd/display/dc/irq_types.h ++++ b/drivers/gpu/drm/amd/display/dc/irq_types.h +@@ -161,6 +161,13 @@ enum dc_irq_source { + DC_IRQ_SOURCE_DPCX_TX_PHYE, + DC_IRQ_SOURCE_DPCX_TX_PHYF, + ++ DC_IRQ_SOURCE_DC1_VLINE2, ++ DC_IRQ_SOURCE_DC2_VLINE2, ++ DC_IRQ_SOURCE_DC3_VLINE2, ++ DC_IRQ_SOURCE_DC4_VLINE2, ++ DC_IRQ_SOURCE_DC5_VLINE2, ++ DC_IRQ_SOURCE_DC6_VLINE2, ++ + DAL_IRQ_SOURCES_NUMBER + }; + +@@ -170,6 +177,8 @@ enum irq_type + IRQ_TYPE_VUPDATE = DC_IRQ_SOURCE_VUPDATE1, + IRQ_TYPE_VBLANK = DC_IRQ_SOURCE_VBLANK1, + IRQ_TYPE_VLINE0 = DC_IRQ_SOURCE_DC1_VLINE0, ++ IRQ_TYPE_VLINE1 = DC_IRQ_SOURCE_DC1_VLINE1, ++ IRQ_TYPE_VLINE2 = DC_IRQ_SOURCE_DC1_VLINE2, + IRQ_TYPE_DCUNDERFLOW = DC_IRQ_SOURCE_DC1UNDERFLOW, + }; + +diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c +index a0e9e9f0441a41..b4cea2b8cb2a8a 100644 +--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c ++++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c +@@ -370,275 +370,279 @@ void mpc32_program_shaper_luta_settings( + MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y); + + curve = params->arr_curve_points; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_0_1[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_2_3[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_4_5[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_6_7[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_8_9[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_10_11[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_12_13[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_14_15[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_16_17[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_18_19[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_20_21[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_22_23[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_24_25[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_26_27[mpcc_id], 0, ++ if (curve) { ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_0_1[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_28_29[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_30_31[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_32_33[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +-} +- +- +-void mpc32_program_shaper_lutb_settings( +- struct mpc *mpc, +- const struct pwl_params *params, +- uint32_t mpcc_id) +-{ +- const struct gamma_curve *curve; +- struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); +- +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_B[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_G[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_R[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); +- +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_B[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y); +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_G[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y); +- REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_R[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y); +- +- curve = params->arr_curve_points; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_0_1[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_2_3[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_2_3[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_4_5[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_4_5[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_6_7[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_6_7[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_8_9[mpcc_id], 0, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, +- MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_8_9[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_10_11[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_10_11[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_12_13[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_12_13[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_14_15[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_14_15[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_16_17[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_16_17[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_18_19[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_18_19[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_20_21[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_20_21[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_22_23[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_22_23[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_24_25[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_24_25[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_26_27[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_26_27[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_28_29[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_28_29[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_30_31[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_30_31[mpcc_id], 0, ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMA_REGION_32_33[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ } ++} ++ ++ ++void mpc32_program_shaper_lutb_settings( ++ struct mpc *mpc, ++ const struct pwl_params *params, ++ uint32_t mpcc_id) ++{ ++ const struct gamma_curve *curve; ++ struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); ++ ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_B[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_G[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_START_CNTL_R[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); + +- curve += 2; +- REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_32_33[mpcc_id], 0, ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_B[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y); ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_G[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y); ++ REG_SET_2(MPCC_MCM_SHAPER_RAMB_END_CNTL_R[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y); ++ ++ curve = params->arr_curve_points; ++ if (curve) { ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_0_1[mpcc_id], 0, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_2_3[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_4_5[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_6_7[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_8_9[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_10_11[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_12_13[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_14_15[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_16_17[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_18_19[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_20_21[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_22_23[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_24_25[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_26_27[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_28_29[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_30_31[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ ++ curve += 2; ++ REG_SET_4(MPCC_MCM_SHAPER_RAMB_REGION_32_33[mpcc_id], 0, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, ++ MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); ++ } + } + + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +index ffd2b816cd02c7..8948d44a7a80e3 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +@@ -1903,7 +1903,7 @@ static bool dcn35_resource_construct( + dc->caps.max_disp_clock_khz_at_vmin = 650000; + + /* Sequential ONO is based on ASIC. */ +- if (dc->ctx->asic_id.hw_internal_rev > 0x10) ++ if (dc->ctx->asic_id.hw_internal_rev >= 0x40) + dc->caps.sequential_ono = true; + + /* Use pipe context based otg sync logic */ +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +index b6468573dc33d7..7f19689e976a17 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +@@ -1876,7 +1876,7 @@ static bool dcn36_resource_construct( + dc->caps.max_disp_clock_khz_at_vmin = 650000; + + /* Sequential ONO is based on ASIC. */ +- if (dc->ctx->asic_id.hw_internal_rev > 0x10) ++ if (dc->ctx->asic_id.hw_internal_rev >= 0x40) + dc->caps.sequential_ono = true; + + /* Use pipe context based otg sync logic */ +diff --git a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c +index 28348734d900c1..124aaff890d211 100644 +--- a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c ++++ b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c +@@ -1297,7 +1297,7 @@ static void spl_set_easf_data(struct spl_scratch *spl_scratch, struct spl_out *s + if (enable_easf_v) { + dscl_prog_data->easf_v_en = true; + dscl_prog_data->easf_v_ring = 0; +- dscl_prog_data->easf_v_sharp_factor = 0; ++ dscl_prog_data->easf_v_sharp_factor = 1; + dscl_prog_data->easf_v_bf1_en = 1; // 1-bit, BF1 calculation enable, 0=disable, 1=enable + dscl_prog_data->easf_v_bf2_mode = 0xF; // 4-bit, BF2 calculation mode + /* 2-bit, BF3 chroma mode correction calculation mode */ +@@ -1461,7 +1461,7 @@ static void spl_set_easf_data(struct spl_scratch *spl_scratch, struct spl_out *s + if (enable_easf_h) { + dscl_prog_data->easf_h_en = true; + dscl_prog_data->easf_h_ring = 0; +- dscl_prog_data->easf_h_sharp_factor = 0; ++ dscl_prog_data->easf_h_sharp_factor = 1; + dscl_prog_data->easf_h_bf1_en = + 1; // 1-bit, BF1 calculation enable, 0=disable, 1=enable + dscl_prog_data->easf_h_bf2_mode = +diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +index cd03caffe31735..21589c4583e6b3 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h ++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +@@ -310,6 +310,7 @@ int smu_v13_0_get_boot_freq_by_index(struct smu_context *smu, + uint32_t *value); + + void smu_v13_0_interrupt_work(struct smu_context *smu); ++void smu_v13_0_reset_custom_level(struct smu_context *smu); + bool smu_v13_0_12_is_dpm_running(struct smu_context *smu); + int smu_v13_0_12_get_max_metrics_size(void); + int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu); +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +index 83163d7c7f0014..5cb3b9bb60898f 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +@@ -1270,6 +1270,7 @@ static int aldebaran_set_performance_level(struct smu_context *smu, + struct smu_13_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; ++ int r; + + /* Disable determinism if switching to another mode */ + if ((smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) && +@@ -1282,7 +1283,11 @@ static int aldebaran_set_performance_level(struct smu_context *smu, + + case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: + return 0; +- ++ case AMD_DPM_FORCED_LEVEL_AUTO: ++ r = smu_v13_0_set_performance_level(smu, level); ++ if (!r) ++ smu_v13_0_reset_custom_level(smu); ++ return r; + case AMD_DPM_FORCED_LEVEL_HIGH: + case AMD_DPM_FORCED_LEVEL_LOW: + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: +@@ -1423,7 +1428,11 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ + min_clk = dpm_context->dpm_tables.gfx_table.min; + max_clk = dpm_context->dpm_tables.gfx_table.max; + +- return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false); ++ ret = aldebaran_set_soft_freq_limited_range( ++ smu, SMU_GFXCLK, min_clk, max_clk, false); ++ if (ret) ++ return ret; ++ smu_v13_0_reset_custom_level(smu); + } + break; + case PP_OD_COMMIT_DPM_TABLE: +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +index ba5a9012dbd5e3..075f381ad311ba 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +@@ -2595,3 +2595,13 @@ int smu_v13_0_set_wbrf_exclusion_ranges(struct smu_context *smu, + + return ret; + } ++ ++void smu_v13_0_reset_custom_level(struct smu_context *smu) ++{ ++ struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; ++ ++ pstate_table->uclk_pstate.custom.min = 0; ++ pstate_table->uclk_pstate.custom.max = 0; ++ pstate_table->gfxclk_pstate.custom.min = 0; ++ pstate_table->gfxclk_pstate.custom.max = 0; ++} +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +index c478b3be37af1e..b8feabb019cf80 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +@@ -1927,7 +1927,7 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, + return ret; + pstate_table->uclk_pstate.curr.max = uclk_table->max; + } +- pstate_table->uclk_pstate.custom.max = 0; ++ smu_v13_0_reset_custom_level(smu); + + return 0; + case AMD_DPM_FORCED_LEVEL_MANUAL: +@@ -2140,7 +2140,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, + smu, SMU_UCLK, min_clk, max_clk, false); + if (ret) + return ret; +- pstate_table->uclk_pstate.custom.max = 0; ++ smu_v13_0_reset_custom_level(smu); + } + break; + case PP_OD_COMMIT_DPM_TABLE: +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 09a1be234f7173..b9e0ca85226a60 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -16,6 +16,7 @@ config DRM_AUX_BRIDGE + tristate + depends on DRM_BRIDGE && OF + select AUXILIARY_BUS ++ select DRM_KMS_HELPER + select DRM_PANEL_BRIDGE + help + Simple transparent bridge that is used by several non-DRM drivers to +diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +index 5222b1e9f533d0..f96952e9ff4ef3 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +@@ -1622,10 +1622,10 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) + * that we can get the current state of the GPIO. + */ + dp->irq = gpiod_to_irq(dp->hpd_gpiod); +- irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; ++ irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN; + } else { + dp->irq = platform_get_irq(pdev, 0); +- irq_flags = 0; ++ irq_flags = IRQF_NO_AUTOEN; + } + + if (dp->irq == -ENXIO) { +@@ -1641,7 +1641,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) + dev_err(&pdev->dev, "failed to request irq\n"); + return ERR_PTR(ret); + } +- disable_irq(dp->irq); + + dp->aux.name = "DP-AUX"; + dp->aux.transfer = analogix_dpaux_transfer; +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index 0b97b66de57742..95d5a4e265788a 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -1257,10 +1257,10 @@ static void anx7625_power_on(struct anx7625_data *ctx) + usleep_range(11000, 12000); + + /* Power on pin enable */ +- gpiod_set_value(ctx->pdata.gpio_p_on, 1); ++ gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 1); + usleep_range(10000, 11000); + /* Power reset pin enable */ +- gpiod_set_value(ctx->pdata.gpio_reset, 1); ++ gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 1); + usleep_range(10000, 11000); + + DRM_DEV_DEBUG_DRIVER(dev, "power on !\n"); +@@ -1280,9 +1280,9 @@ static void anx7625_power_standby(struct anx7625_data *ctx) + return; + } + +- gpiod_set_value(ctx->pdata.gpio_reset, 0); ++ gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 0); + usleep_range(1000, 1100); +- gpiod_set_value(ctx->pdata.gpio_p_on, 0); ++ gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 0); + usleep_range(1000, 1100); + + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->pdata.supplies), +@@ -2474,6 +2474,22 @@ static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge + return anx7625_edid_read(ctx); + } + ++static void anx7625_bridge_hpd_enable(struct drm_bridge *bridge) ++{ ++ struct anx7625_data *ctx = bridge_to_anx7625(bridge); ++ struct device *dev = ctx->dev; ++ ++ pm_runtime_get_sync(dev); ++} ++ ++static void anx7625_bridge_hpd_disable(struct drm_bridge *bridge) ++{ ++ struct anx7625_data *ctx = bridge_to_anx7625(bridge); ++ struct device *dev = ctx->dev; ++ ++ pm_runtime_put_sync(dev); ++} ++ + static const struct drm_bridge_funcs anx7625_bridge_funcs = { + .attach = anx7625_bridge_attach, + .detach = anx7625_bridge_detach, +@@ -2487,6 +2503,8 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { + .atomic_reset = drm_atomic_helper_bridge_reset, + .detect = anx7625_bridge_detect, + .edid_read = anx7625_bridge_edid_read, ++ .hpd_enable = anx7625_bridge_hpd_enable, ++ .hpd_disable = anx7625_bridge_hpd_disable, + }; + + static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, +diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c +index dbce1c3f49691f..753d7c3942a149 100644 +--- a/drivers/gpu/drm/display/drm_dp_helper.c ++++ b/drivers/gpu/drm/display/drm_dp_helper.c +@@ -2081,14 +2081,17 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + + for (i = 0; i < num; i++) { + msg.address = msgs[i].addr; +- drm_dp_i2c_msg_set_request(&msg, &msgs[i]); +- /* Send a bare address packet to start the transaction. +- * Zero sized messages specify an address only (bare +- * address) transaction. +- */ +- msg.buffer = NULL; +- msg.size = 0; +- err = drm_dp_i2c_do_msg(aux, &msg); ++ ++ if (!aux->no_zero_sized) { ++ drm_dp_i2c_msg_set_request(&msg, &msgs[i]); ++ /* Send a bare address packet to start the transaction. ++ * Zero sized messages specify an address only (bare ++ * address) transaction. ++ */ ++ msg.buffer = NULL; ++ msg.size = 0; ++ err = drm_dp_i2c_do_msg(aux, &msg); ++ } + + /* + * Reset msg.request in case in case it got +@@ -2107,6 +2110,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + msg.buffer = msgs[i].buf + j; + msg.size = min(transfer_size, msgs[i].len - j); + ++ if (j + msg.size == msgs[i].len && aux->no_zero_sized) ++ msg.request &= ~DP_AUX_I2C_MOT; + err = drm_dp_i2c_drain_msg(aux, &msg); + + /* +@@ -2124,15 +2129,17 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + } + if (err >= 0) + err = num; +- /* Send a bare address packet to close out the transaction. +- * Zero sized messages specify an address only (bare +- * address) transaction. +- */ +- msg.request &= ~DP_AUX_I2C_MOT; +- msg.buffer = NULL; +- msg.size = 0; +- (void)drm_dp_i2c_do_msg(aux, &msg); + ++ if (!aux->no_zero_sized) { ++ /* Send a bare address packet to close out the transaction. ++ * Zero sized messages specify an address only (bare ++ * address) transaction. ++ */ ++ msg.request &= ~DP_AUX_I2C_MOT; ++ msg.buffer = NULL; ++ msg.size = 0; ++ (void)drm_dp_i2c_do_msg(aux, &msg); ++ } + return err; + } + +diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c +index c554ad8f246b65..7ac0fd5391feaf 100644 +--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c ++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c +@@ -517,6 +517,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, ++ }, { /* ZOTAC Gaming Zone */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ZOTAC"), ++ DMI_EXACT_MATCH(DMI_BOARD_NAME, "G0A1W"), ++ }, ++ .driver_data = (void *)&lcd1080x1920_leftside_up, + }, { /* One Mix 2S (generic strings, also match on bios date) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"), +diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c +index e5a188ce318578..990bfaba3ce4e8 100644 +--- a/drivers/gpu/drm/i915/i915_pmu.c ++++ b/drivers/gpu/drm/i915/i915_pmu.c +@@ -112,7 +112,7 @@ static u32 config_mask(const u64 config) + { + unsigned int bit = config_bit(config); + +- if (__builtin_constant_p(config)) ++ if (__builtin_constant_p(bit)) + BUILD_BUG_ON(bit > + BITS_PER_TYPE(typeof_member(struct i915_pmu, + enable)) - 1); +@@ -121,7 +121,7 @@ static u32 config_mask(const u64 config) + BITS_PER_TYPE(typeof_member(struct i915_pmu, + enable)) - 1); + +- return BIT(config_bit(config)); ++ return BIT(bit); + } + + static bool is_engine_event(struct perf_event *event) +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 90991ba5a4ae10..742132feb19cc9 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -130,6 +130,20 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, + OUT_RING(ring, lower_32_bits(rbmemptr(ring, fence))); + OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence))); + OUT_RING(ring, submit->seqno - 1); ++ ++ OUT_PKT7(ring, CP_THREAD_CONTROL, 1); ++ OUT_RING(ring, CP_SET_THREAD_BOTH); ++ ++ /* Reset state used to synchronize BR and BV */ ++ OUT_PKT7(ring, CP_RESET_CONTEXT_STATE, 1); ++ OUT_RING(ring, ++ CP_RESET_CONTEXT_STATE_0_CLEAR_ON_CHIP_TS | ++ CP_RESET_CONTEXT_STATE_0_CLEAR_RESOURCE_TABLE | ++ CP_RESET_CONTEXT_STATE_0_CLEAR_BV_BR_COUNTER | ++ CP_RESET_CONTEXT_STATE_0_RESET_GLOBAL_LOCAL_TS); ++ ++ OUT_PKT7(ring, CP_THREAD_CONTROL, 1); ++ OUT_RING(ring, CP_SET_THREAD_BR); + } + + if (!sysprof) { +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 0989aee3dd2cf9..628c19789e9d37 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -109,7 +109,7 @@ static int a6xx_hfi_wait_for_ack(struct a6xx_gmu *gmu, u32 id, u32 seqnum, + + /* Wait for a response */ + ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_GMU2HOST_INTR_INFO, val, +- val & A6XX_GMU_GMU2HOST_INTR_INFO_MSGQ, 100, 5000); ++ val & A6XX_GMU_GMU2HOST_INTR_INFO_MSGQ, 100, 1000000); + + if (ret) { + DRM_DEV_ERROR(gmu->dev, +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +index abd6600046cb3a..c3c7a0d56c4103 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +@@ -94,17 +94,21 @@ static void drm_mode_to_intf_timing_params( + timing->vsync_polarity = 0; + } + +- /* for DP/EDP, Shift timings to align it to bottom right */ +- if (phys_enc->hw_intf->cap->type == INTF_DP) { ++ timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent); ++ timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent); ++ ++ /* ++ * For DP/EDP, Shift timings to align it to bottom right. ++ * wide_bus_en is set for everything excluding SDM845 & ++ * porch changes cause DisplayPort failure and HDMI tearing. ++ */ ++ if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) { + timing->h_back_porch += timing->h_front_porch; + timing->h_front_porch = 0; + timing->v_back_porch += timing->v_front_porch; + timing->v_front_porch = 0; + } + +- timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent); +- timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent); +- + /* + * for DP, divide the horizonal parameters by 2 when + * widebus is enabled +@@ -372,7 +376,8 @@ static void dpu_encoder_phys_vid_underrun_irq(void *arg) + static bool dpu_encoder_phys_vid_needs_single_flush( + struct dpu_encoder_phys *phys_enc) + { +- return phys_enc->split_role != ENC_ROLE_SOLO; ++ return !(phys_enc->hw_ctl->caps->features & BIT(DPU_CTL_ACTIVE_CFG)) && ++ phys_enc->split_role != ENC_ROLE_SOLO; + } + + static void dpu_encoder_phys_vid_atomic_mode_set( +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index ab8c1f19dcb42d..c7503a7a6123f5 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -127,6 +127,11 @@ static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { + {} + }; + ++static const struct msm_dp_desc msm_dp_desc_sdm845[] = { ++ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0 }, ++ {} ++}; ++ + static const struct msm_dp_desc msm_dp_desc_sc7180[] = { + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + {} +@@ -179,7 +184,7 @@ static const struct of_device_id msm_dp_dt_match[] = { + { .compatible = "qcom,sc8180x-edp", .data = &msm_dp_desc_sc8180x }, + { .compatible = "qcom,sc8280xp-dp", .data = &msm_dp_desc_sc8280xp }, + { .compatible = "qcom,sc8280xp-edp", .data = &msm_dp_desc_sc8280xp }, +- { .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sc7180 }, ++ { .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sdm845 }, + { .compatible = "qcom,sm8350-dp", .data = &msm_dp_desc_sc7180 }, + { .compatible = "qcom,sm8650-dp", .data = &msm_dp_desc_sm8650 }, + { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +index 9812b4d6919792..af2e30f3f842a0 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +@@ -704,6 +704,13 @@ static int dsi_pll_10nm_init(struct msm_dsi_phy *phy) + /* TODO: Remove this when we have proper display handover support */ + msm_dsi_phy_pll_save_state(phy); + ++ /* ++ * Store also proper vco_current_rate, because its value will be used in ++ * dsi_10nm_pll_restore_state(). ++ */ ++ if (!dsi_pll_10nm_vco_recalc_rate(&pll_10nm->clk_hw, VCO_REF_CLK_RATE)) ++ pll_10nm->vco_current_rate = pll_10nm->phy->cfg->min_pll_rate; ++ + return 0; + } + +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c +index 7aa500d24240ff..ebefea4fb40855 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c +@@ -107,11 +107,15 @@ static int msm_hdmi_i2c_xfer(struct i2c_adapter *i2c, + if (num == 0) + return num; + ++ ret = pm_runtime_resume_and_get(&hdmi->pdev->dev); ++ if (ret) ++ return ret; ++ + init_ddc(hdmi_i2c); + + ret = ddc_clear_irq(hdmi_i2c); + if (ret) +- return ret; ++ goto fail; + + for (i = 0; i < num; i++) { + struct i2c_msg *p = &msgs[i]; +@@ -169,7 +173,7 @@ static int msm_hdmi_i2c_xfer(struct i2c_adapter *i2c, + hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS), + hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS), + hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL)); +- return ret; ++ goto fail; + } + + ddc_status = hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS); +@@ -202,7 +206,13 @@ static int msm_hdmi_i2c_xfer(struct i2c_adapter *i2c, + } + } + ++ pm_runtime_put(&hdmi->pdev->dev); ++ + return i; ++ ++fail: ++ pm_runtime_put(&hdmi->pdev->dev); ++ return ret; + } + + static u32 msm_hdmi_i2c_func(struct i2c_adapter *adapter) +diff --git a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml +index 5a6ae9fc319451..46271340162280 100644 +--- a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml ++++ b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml +@@ -2255,7 +2255,8 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords) + + + +- ++ ++ + + + +diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild +index 7b863355c5c676..0759ba15954be8 100644 +--- a/drivers/gpu/drm/nouveau/Kbuild ++++ b/drivers/gpu/drm/nouveau/Kbuild +@@ -2,6 +2,7 @@ + ccflags-y += -I $(src)/include + ccflags-y += -I $(src)/include/nvkm + ccflags-y += -I $(src)/nvkm ++ccflags-y += -I $(src)/nvkm/subdev/gsp + ccflags-y += -I $(src) + + # NVKM - HW resource manager +diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +index 746e126c3ecf56..b543c31d3d3209 100644 +--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h ++++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +@@ -31,6 +31,29 @@ typedef int (*nvkm_gsp_msg_ntfy_func)(void *priv, u32 fn, void *repv, u32 repc); + struct nvkm_gsp_event; + typedef void (*nvkm_gsp_event_func)(struct nvkm_gsp_event *, void *repv, u32 repc); + ++/** ++ * DOC: GSP message handling policy ++ * ++ * When sending a GSP RPC command, there can be multiple cases of handling ++ * the GSP RPC messages, which are the reply of GSP RPC commands, according ++ * to the requirement of the callers and the nature of the GSP RPC commands. ++ * ++ * NVKM_GSP_RPC_REPLY_NOWAIT - If specified, immediately return to the ++ * caller after the GSP RPC command is issued. ++ * ++ * NVKM_GSP_RPC_REPLY_RECV - If specified, wait and receive the entire GSP ++ * RPC message after the GSP RPC command is issued. ++ * ++ * NVKM_GSP_RPC_REPLY_POLL - If specified, wait for the specific reply and ++ * discard the reply before returning to the caller. ++ * ++ */ ++enum nvkm_gsp_rpc_reply_policy { ++ NVKM_GSP_RPC_REPLY_NOWAIT = 0, ++ NVKM_GSP_RPC_REPLY_RECV, ++ NVKM_GSP_RPC_REPLY_POLL, ++}; ++ + struct nvkm_gsp { + const struct nvkm_gsp_func *func; + struct nvkm_subdev subdev; +@@ -187,9 +210,7 @@ struct nvkm_gsp { + } gr; + + const struct nvkm_gsp_rm { +- void *(*rpc_get)(struct nvkm_gsp *, u32 fn, u32 argc); +- void *(*rpc_push)(struct nvkm_gsp *, void *argv, bool wait, u32 repc); +- void (*rpc_done)(struct nvkm_gsp *gsp, void *repv); ++ const struct nvkm_rm_api *api; + + void *(*rm_ctrl_get)(struct nvkm_gsp_object *, u32 cmd, u32 argc); + int (*rm_ctrl_push)(struct nvkm_gsp_object *, void **argv, u32 repc); +@@ -248,16 +269,19 @@ nvkm_gsp_rm(struct nvkm_gsp *gsp) + return gsp && (gsp->fws.rm || gsp->fw.img); + } + ++#include ++ + static inline void * + nvkm_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 argc) + { +- return gsp->rm->rpc_get(gsp, fn, argc); ++ return gsp->rm->api->rpc->get(gsp, fn, argc); + } + + static inline void * +-nvkm_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv, bool wait, u32 repc) ++nvkm_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv, ++ enum nvkm_gsp_rpc_reply_policy policy, u32 repc) + { +- return gsp->rm->rpc_push(gsp, argv, wait, repc); ++ return gsp->rm->api->rpc->push(gsp, argv, policy, repc); + } + + static inline void * +@@ -268,13 +292,14 @@ nvkm_gsp_rpc_rd(struct nvkm_gsp *gsp, u32 fn, u32 argc) + if (IS_ERR_OR_NULL(argv)) + return argv; + +- return nvkm_gsp_rpc_push(gsp, argv, true, argc); ++ return nvkm_gsp_rpc_push(gsp, argv, NVKM_GSP_RPC_REPLY_RECV, argc); + } + + static inline int +-nvkm_gsp_rpc_wr(struct nvkm_gsp *gsp, void *argv, bool wait) ++nvkm_gsp_rpc_wr(struct nvkm_gsp *gsp, void *argv, ++ enum nvkm_gsp_rpc_reply_policy policy) + { +- void *repv = nvkm_gsp_rpc_push(gsp, argv, wait, 0); ++ void *repv = nvkm_gsp_rpc_push(gsp, argv, policy, 0); + + if (IS_ERR(repv)) + return PTR_ERR(repv); +@@ -285,7 +310,7 @@ nvkm_gsp_rpc_wr(struct nvkm_gsp *gsp, void *argv, bool wait) + static inline void + nvkm_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv) + { +- gsp->rm->rpc_done(gsp, repv); ++ gsp->rm->api->rpc->done(gsp, repv); + } + + static inline void * +diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c +index d47442125fa183..9aae26eb7d8fba 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c ++++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c +@@ -42,7 +42,7 @@ + #include "nouveau_acpi.h" + + static struct ida bl_ida; +-#define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0' ++#define BL_NAME_SIZE 24 // 12 for name + 11 for digits + 1 for '\0' + + static bool + nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index e154d08857c55b..c69139701056d7 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -1079,6 +1079,10 @@ nouveau_pmops_freeze(struct device *dev) + { + struct nouveau_drm *drm = dev_get_drvdata(dev); + ++ if (drm->dev->switch_power_state == DRM_SWITCH_POWER_OFF || ++ drm->dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) ++ return 0; ++ + return nouveau_do_suspend(drm, false); + } + +@@ -1087,6 +1091,10 @@ nouveau_pmops_thaw(struct device *dev) + { + struct nouveau_drm *drm = dev_get_drvdata(dev); + ++ if (drm->dev->switch_power_state == DRM_SWITCH_POWER_OFF || ++ drm->dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) ++ return 0; ++ + return nouveau_do_resume(drm, false); + } + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/r535.c +index 3a30bea30e366f..90186f98065c28 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/r535.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/r535.c +@@ -56,7 +56,7 @@ r535_bar_bar2_update_pde(struct nvkm_gsp *gsp, u64 addr) + rpc->info.entryValue = addr ? ((addr >> 4) | 2) : 0; /* PD3 entry format! */ + rpc->info.entryLevelShift = 47; //XXX: probably fetch this from mmu! + +- return nvkm_gsp_rpc_wr(gsp, rpc, true); ++ return nvkm_gsp_rpc_wr(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV); + } + + static void +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild +index 16bf2f1bb78014..af6e55603763d6 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild +@@ -10,3 +10,5 @@ nvkm-y += nvkm/subdev/gsp/ga102.o + nvkm-y += nvkm/subdev/gsp/ad102.o + + nvkm-y += nvkm/subdev/gsp/r535.o ++ ++include $(src)/nvkm/subdev/gsp/rm/Kbuild +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c +index db2602e880062b..53a4af00103926 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c +@@ -19,6 +19,7 @@ + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ ++#include + #include "priv.h" + + #include +@@ -60,562 +61,6 @@ + + extern struct dentry *nouveau_debugfs_root; + +-#define GSP_MSG_MIN_SIZE GSP_PAGE_SIZE +-#define GSP_MSG_MAX_SIZE (GSP_MSG_MIN_SIZE * 16) +- +-/** +- * DOC: GSP message queue element +- * +- * https://github.com/NVIDIA/open-gpu-kernel-modules/blob/535/src/nvidia/inc/kernel/gpu/gsp/message_queue_priv.h +- * +- * The GSP command queue and status queue are message queues for the +- * communication between software and GSP. The software submits the GSP +- * RPC via the GSP command queue, GSP writes the status of the submitted +- * RPC in the status queue. +- * +- * A GSP message queue element consists of three parts: +- * +- * - message element header (struct r535_gsp_msg), which mostly maintains +- * the metadata for queuing the element. +- * +- * - RPC message header (struct nvfw_gsp_rpc), which maintains the info +- * of the RPC. E.g., the RPC function number. +- * +- * - The payload, where the RPC message stays. E.g. the params of a +- * specific RPC function. Some RPC functions also have their headers +- * in the payload. E.g. rm_alloc, rm_control. +- * +- * The memory layout of a GSP message element can be illustrated below:: +- * +- * +------------------------+ +- * | Message Element Header | +- * | (r535_gsp_msg) | +- * | | +- * | (r535_gsp_msg.data) | +- * | | | +- * |----------V-------------| +- * | GSP RPC Header | +- * | (nvfw_gsp_rpc) | +- * | | +- * | (nvfw_gsp_rpc.data) | +- * | | | +- * |----------V-------------| +- * | Payload | +- * | | +- * | header(optional) | +- * | params | +- * +------------------------+ +- * +- * The max size of a message queue element is 16 pages (including the +- * headers). When a GSP message to be sent is larger than 16 pages, the +- * message should be split into multiple elements and sent accordingly. +- * +- * In the bunch of the split elements, the first element has the expected +- * function number, while the rest of the elements are sent with the +- * function number NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD. +- * +- * GSP consumes the elements from the cmdq and always writes the result +- * back to the msgq. The result is also formed as split elements. +- * +- * Terminology: +- * +- * - gsp_msg(msg): GSP message element (element header + GSP RPC header + +- * payload) +- * - gsp_rpc(rpc): GSP RPC (RPC header + payload) +- * - gsp_rpc_buf: buffer for (GSP RPC header + payload) +- * - gsp_rpc_len: size of (GSP RPC header + payload) +- * - params_size: size of params in the payload +- * - payload_size: size of (header if exists + params) in the payload +- */ +- +-struct r535_gsp_msg { +- u8 auth_tag_buffer[16]; +- u8 aad_buffer[16]; +- u32 checksum; +- u32 sequence; +- u32 elem_count; +- u32 pad; +- u8 data[]; +-}; +- +-struct nvfw_gsp_rpc { +- u32 header_version; +- u32 signature; +- u32 length; +- u32 function; +- u32 rpc_result; +- u32 rpc_result_private; +- u32 sequence; +- union { +- u32 spare; +- u32 cpuRmGfid; +- }; +- u8 data[]; +-}; +- +-#define GSP_MSG_HDR_SIZE offsetof(struct r535_gsp_msg, data) +- +-#define to_gsp_hdr(p, header) \ +- container_of((void *)p, typeof(*header), data) +- +-#define to_payload_hdr(p, header) \ +- container_of((void *)p, typeof(*header), params) +- +-static int +-r535_rpc_status_to_errno(uint32_t rpc_status) +-{ +- switch (rpc_status) { +- case 0x55: /* NV_ERR_NOT_READY */ +- case 0x66: /* NV_ERR_TIMEOUT_RETRY */ +- return -EBUSY; +- case 0x51: /* NV_ERR_NO_MEMORY */ +- return -ENOMEM; +- default: +- return -EINVAL; +- } +-} +- +-static int +-r535_gsp_msgq_wait(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *ptime) +-{ +- u32 size, rptr = *gsp->msgq.rptr; +- int used; +- +- size = DIV_ROUND_UP(GSP_MSG_HDR_SIZE + gsp_rpc_len, +- GSP_PAGE_SIZE); +- if (WARN_ON(!size || size >= gsp->msgq.cnt)) +- return -EINVAL; +- +- do { +- u32 wptr = *gsp->msgq.wptr; +- +- used = wptr + gsp->msgq.cnt - rptr; +- if (used >= gsp->msgq.cnt) +- used -= gsp->msgq.cnt; +- if (used >= size) +- break; +- +- usleep_range(1, 2); +- } while (--(*ptime)); +- +- if (WARN_ON(!*ptime)) +- return -ETIMEDOUT; +- +- return used; +-} +- +-static struct r535_gsp_msg * +-r535_gsp_msgq_get_entry(struct nvkm_gsp *gsp) +-{ +- u32 rptr = *gsp->msgq.rptr; +- +- /* Skip the first page, which is the message queue info */ +- return (void *)((u8 *)gsp->shm.msgq.ptr + GSP_PAGE_SIZE + +- rptr * GSP_PAGE_SIZE); +-} +- +-/** +- * DOC: Receive a GSP message queue element +- * +- * Receiving a GSP message queue element from the message queue consists of +- * the following steps: +- * +- * - Peek the element from the queue: r535_gsp_msgq_peek(). +- * Peek the first page of the element to determine the total size of the +- * message before allocating the proper memory. +- * +- * - Allocate memory for the message. +- * Once the total size of the message is determined from the GSP message +- * queue element, the caller of r535_gsp_msgq_recv() allocates the +- * required memory. +- * +- * - Receive the message: r535_gsp_msgq_recv(). +- * Copy the message into the allocated memory. Advance the read pointer. +- * If the message is a large GSP message, r535_gsp_msgq_recv() calls +- * r535_gsp_msgq_recv_one_elem() repeatedly to receive continuation parts +- * until the complete message is received. +- * r535_gsp_msgq_recv() assembles the payloads of cotinuation parts into +- * the return of the large GSP message. +- * +- * - Free the allocated memory: r535_gsp_msg_done(). +- * The user is responsible for freeing the memory allocated for the GSP +- * message pages after they have been processed. +- */ +-static void * +-r535_gsp_msgq_peek(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) +-{ +- struct r535_gsp_msg *mqe; +- int ret; +- +- ret = r535_gsp_msgq_wait(gsp, gsp_rpc_len, retries); +- if (ret < 0) +- return ERR_PTR(ret); +- +- mqe = r535_gsp_msgq_get_entry(gsp); +- +- return mqe->data; +-} +- +-struct r535_gsp_msg_info { +- int *retries; +- u32 gsp_rpc_len; +- void *gsp_rpc_buf; +- bool continuation; +-}; +- +-static void +-r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl); +- +-static void * +-r535_gsp_msgq_recv_one_elem(struct nvkm_gsp *gsp, +- struct r535_gsp_msg_info *info) +-{ +- u8 *buf = info->gsp_rpc_buf; +- u32 rptr = *gsp->msgq.rptr; +- struct r535_gsp_msg *mqe; +- u32 size, expected, len; +- int ret; +- +- expected = info->gsp_rpc_len; +- +- ret = r535_gsp_msgq_wait(gsp, expected, info->retries); +- if (ret < 0) +- return ERR_PTR(ret); +- +- mqe = r535_gsp_msgq_get_entry(gsp); +- +- if (info->continuation) { +- struct nvfw_gsp_rpc *rpc = (struct nvfw_gsp_rpc *)mqe->data; +- +- if (rpc->function != NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD) { +- nvkm_error(&gsp->subdev, +- "Not a continuation of a large RPC\n"); +- r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); +- return ERR_PTR(-EIO); +- } +- } +- +- size = ALIGN(expected + GSP_MSG_HDR_SIZE, GSP_PAGE_SIZE); +- +- len = ((gsp->msgq.cnt - rptr) * GSP_PAGE_SIZE) - sizeof(*mqe); +- len = min_t(u32, expected, len); +- +- if (info->continuation) +- memcpy(buf, mqe->data + sizeof(struct nvfw_gsp_rpc), +- len - sizeof(struct nvfw_gsp_rpc)); +- else +- memcpy(buf, mqe->data, len); +- +- expected -= len; +- +- if (expected) { +- mqe = (void *)((u8 *)gsp->shm.msgq.ptr + 0x1000 + 0 * 0x1000); +- memcpy(buf + len, mqe, expected); +- } +- +- rptr = (rptr + DIV_ROUND_UP(size, GSP_PAGE_SIZE)) % gsp->msgq.cnt; +- +- mb(); +- (*gsp->msgq.rptr) = rptr; +- return buf; +-} +- +-static void * +-r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) +-{ +- struct r535_gsp_msg *mqe; +- const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*mqe); +- struct nvfw_gsp_rpc *rpc; +- struct r535_gsp_msg_info info = {0}; +- u32 expected = gsp_rpc_len; +- void *buf; +- +- mqe = r535_gsp_msgq_get_entry(gsp); +- rpc = (struct nvfw_gsp_rpc *)mqe->data; +- +- if (WARN_ON(rpc->length > max_rpc_size)) +- return NULL; +- +- buf = kvmalloc(max_t(u32, rpc->length, expected), GFP_KERNEL); +- if (!buf) +- return ERR_PTR(-ENOMEM); +- +- info.gsp_rpc_buf = buf; +- info.retries = retries; +- info.gsp_rpc_len = rpc->length; +- +- buf = r535_gsp_msgq_recv_one_elem(gsp, &info); +- if (IS_ERR(buf)) { +- kvfree(info.gsp_rpc_buf); +- info.gsp_rpc_buf = NULL; +- return buf; +- } +- +- if (expected <= max_rpc_size) +- return buf; +- +- info.gsp_rpc_buf += info.gsp_rpc_len; +- expected -= info.gsp_rpc_len; +- +- while (expected) { +- u32 size; +- +- rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries); +- if (IS_ERR_OR_NULL(rpc)) { +- kfree(buf); +- return rpc; +- } +- +- info.gsp_rpc_len = rpc->length; +- info.continuation = true; +- +- rpc = r535_gsp_msgq_recv_one_elem(gsp, &info); +- if (IS_ERR_OR_NULL(rpc)) { +- kfree(buf); +- return rpc; +- } +- +- size = info.gsp_rpc_len - sizeof(*rpc); +- expected -= size; +- info.gsp_rpc_buf += size; +- } +- +- rpc = buf; +- rpc->length = gsp_rpc_len; +- return buf; +-} +- +-static int +-r535_gsp_cmdq_push(struct nvkm_gsp *gsp, void *rpc) +-{ +- struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg); +- struct r535_gsp_msg *cqe; +- u32 gsp_rpc_len = msg->checksum; +- u64 *ptr = (void *)msg; +- u64 *end; +- u64 csum = 0; +- int free, time = 1000000; +- u32 wptr, size, step, len; +- u32 off = 0; +- +- len = ALIGN(GSP_MSG_HDR_SIZE + gsp_rpc_len, GSP_PAGE_SIZE); +- +- end = (u64 *)((char *)ptr + len); +- msg->pad = 0; +- msg->checksum = 0; +- msg->sequence = gsp->cmdq.seq++; +- msg->elem_count = DIV_ROUND_UP(len, 0x1000); +- +- while (ptr < end) +- csum ^= *ptr++; +- +- msg->checksum = upper_32_bits(csum) ^ lower_32_bits(csum); +- +- wptr = *gsp->cmdq.wptr; +- do { +- do { +- free = *gsp->cmdq.rptr + gsp->cmdq.cnt - wptr - 1; +- if (free >= gsp->cmdq.cnt) +- free -= gsp->cmdq.cnt; +- if (free >= 1) +- break; +- +- usleep_range(1, 2); +- } while(--time); +- +- if (WARN_ON(!time)) { +- kvfree(msg); +- return -ETIMEDOUT; +- } +- +- cqe = (void *)((u8 *)gsp->shm.cmdq.ptr + 0x1000 + wptr * 0x1000); +- step = min_t(u32, free, (gsp->cmdq.cnt - wptr)); +- size = min_t(u32, len, step * GSP_PAGE_SIZE); +- +- memcpy(cqe, (u8 *)msg + off, size); +- +- wptr += DIV_ROUND_UP(size, 0x1000); +- if (wptr == gsp->cmdq.cnt) +- wptr = 0; +- +- off += size; +- len -= size; +- } while (len); +- +- nvkm_trace(&gsp->subdev, "cmdq: wptr %d\n", wptr); +- wmb(); +- (*gsp->cmdq.wptr) = wptr; +- mb(); +- +- nvkm_falcon_wr32(&gsp->falcon, 0xc00, 0x00000000); +- +- kvfree(msg); +- return 0; +-} +- +-static void * +-r535_gsp_cmdq_get(struct nvkm_gsp *gsp, u32 gsp_rpc_len) +-{ +- struct r535_gsp_msg *msg; +- u32 size = GSP_MSG_HDR_SIZE + gsp_rpc_len; +- +- size = ALIGN(size, GSP_MSG_MIN_SIZE); +- msg = kvzalloc(size, GFP_KERNEL); +- if (!msg) +- return ERR_PTR(-ENOMEM); +- +- msg->checksum = gsp_rpc_len; +- return msg->data; +-} +- +-static void +-r535_gsp_msg_done(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg) +-{ +- kvfree(msg); +-} +- +-static void +-r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl) +-{ +- if (gsp->subdev.debug >= lvl) { +- nvkm_printk__(&gsp->subdev, lvl, info, +- "msg fn:%d len:0x%x/0x%zx res:0x%x resp:0x%x\n", +- msg->function, msg->length, msg->length - sizeof(*msg), +- msg->rpc_result, msg->rpc_result_private); +- print_hex_dump(KERN_INFO, "msg: ", DUMP_PREFIX_OFFSET, 16, 1, +- msg->data, msg->length - sizeof(*msg), true); +- } +-} +- +-static struct nvfw_gsp_rpc * +-r535_gsp_msg_recv(struct nvkm_gsp *gsp, int fn, u32 gsp_rpc_len) +-{ +- struct nvkm_subdev *subdev = &gsp->subdev; +- struct nvfw_gsp_rpc *rpc; +- int retries = 4000000, i; +- +-retry: +- rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), &retries); +- if (IS_ERR_OR_NULL(rpc)) +- return rpc; +- +- rpc = r535_gsp_msgq_recv(gsp, gsp_rpc_len, &retries); +- if (IS_ERR_OR_NULL(rpc)) +- return rpc; +- +- if (rpc->rpc_result) { +- r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); +- r535_gsp_msg_done(gsp, rpc); +- return ERR_PTR(-EINVAL); +- } +- +- r535_gsp_msg_dump(gsp, rpc, NV_DBG_TRACE); +- +- if (fn && rpc->function == fn) { +- if (gsp_rpc_len) { +- if (rpc->length < gsp_rpc_len) { +- nvkm_error(subdev, "rpc len %d < %d\n", +- rpc->length, gsp_rpc_len); +- r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); +- r535_gsp_msg_done(gsp, rpc); +- return ERR_PTR(-EIO); +- } +- +- return rpc; +- } +- +- r535_gsp_msg_done(gsp, rpc); +- return NULL; +- } +- +- for (i = 0; i < gsp->msgq.ntfy_nr; i++) { +- struct nvkm_gsp_msgq_ntfy *ntfy = &gsp->msgq.ntfy[i]; +- +- if (ntfy->fn == rpc->function) { +- if (ntfy->func) +- ntfy->func(ntfy->priv, ntfy->fn, rpc->data, +- rpc->length - sizeof(*rpc)); +- break; +- } +- } +- +- if (i == gsp->msgq.ntfy_nr) +- r535_gsp_msg_dump(gsp, rpc, NV_DBG_WARN); +- +- r535_gsp_msg_done(gsp, rpc); +- if (fn) +- goto retry; +- +- if (*gsp->msgq.rptr != *gsp->msgq.wptr) +- goto retry; +- +- return NULL; +-} +- +-static int +-r535_gsp_msg_ntfy_add(struct nvkm_gsp *gsp, u32 fn, nvkm_gsp_msg_ntfy_func func, void *priv) +-{ +- int ret = 0; +- +- mutex_lock(&gsp->msgq.mutex); +- if (WARN_ON(gsp->msgq.ntfy_nr >= ARRAY_SIZE(gsp->msgq.ntfy))) { +- ret = -ENOSPC; +- } else { +- gsp->msgq.ntfy[gsp->msgq.ntfy_nr].fn = fn; +- gsp->msgq.ntfy[gsp->msgq.ntfy_nr].func = func; +- gsp->msgq.ntfy[gsp->msgq.ntfy_nr].priv = priv; +- gsp->msgq.ntfy_nr++; +- } +- mutex_unlock(&gsp->msgq.mutex); +- return ret; +-} +- +-static int +-r535_gsp_rpc_poll(struct nvkm_gsp *gsp, u32 fn) +-{ +- void *repv; +- +- mutex_lock(&gsp->cmdq.mutex); +- repv = r535_gsp_msg_recv(gsp, fn, 0); +- mutex_unlock(&gsp->cmdq.mutex); +- if (IS_ERR(repv)) +- return PTR_ERR(repv); +- +- return 0; +-} +- +-static void * +-r535_gsp_rpc_send(struct nvkm_gsp *gsp, void *payload, bool wait, +- u32 gsp_rpc_len) +-{ +- struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc); +- struct nvfw_gsp_rpc *msg; +- u32 fn = rpc->function; +- void *repv = NULL; +- int ret; +- +- if (gsp->subdev.debug >= NV_DBG_TRACE) { +- nvkm_trace(&gsp->subdev, "rpc fn:%d len:0x%x/0x%zx\n", rpc->function, +- rpc->length, rpc->length - sizeof(*rpc)); +- print_hex_dump(KERN_INFO, "rpc: ", DUMP_PREFIX_OFFSET, 16, 1, +- rpc->data, rpc->length - sizeof(*rpc), true); +- } +- +- ret = r535_gsp_cmdq_push(gsp, rpc); +- if (ret) +- return ERR_PTR(ret); +- +- if (wait) { +- msg = r535_gsp_msg_recv(gsp, fn, gsp_rpc_len); +- if (!IS_ERR_OR_NULL(msg)) +- repv = msg->data; +- else +- repv = msg; +- } +- +- return repv; +-} +- + static void + r535_gsp_event_dtor(struct nvkm_gsp_event *event) + { +@@ -797,7 +242,7 @@ r535_gsp_rpc_rm_free(struct nvkm_gsp_object *object) + rpc->params.hRoot = client->object.handle; + rpc->params.hObjectParent = 0; + rpc->params.hObjectOld = object->handle; +- return nvkm_gsp_rpc_wr(gsp, rpc, true); ++ return nvkm_gsp_rpc_wr(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV); + } + + static void +@@ -815,7 +260,7 @@ r535_gsp_rpc_rm_alloc_push(struct nvkm_gsp_object *object, void *params) + struct nvkm_gsp *gsp = object->client->gsp; + void *ret = NULL; + +- rpc = nvkm_gsp_rpc_push(gsp, rpc, true, sizeof(*rpc)); ++ rpc = nvkm_gsp_rpc_push(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV, sizeof(*rpc)); + if (IS_ERR_OR_NULL(rpc)) + return rpc; + +@@ -876,7 +321,7 @@ r535_gsp_rpc_rm_ctrl_push(struct nvkm_gsp_object *object, void **params, u32 rep + struct nvkm_gsp *gsp = object->client->gsp; + int ret = 0; + +- rpc = nvkm_gsp_rpc_push(gsp, rpc, true, repc); ++ rpc = nvkm_gsp_rpc_push(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV, repc); + if (IS_ERR_OR_NULL(rpc)) { + *params = NULL; + return PTR_ERR(rpc); +@@ -920,109 +365,9 @@ r535_gsp_rpc_rm_ctrl_get(struct nvkm_gsp_object *object, u32 cmd, u32 params_siz + return rpc->params; + } + +-static void +-r535_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv) +-{ +- struct nvfw_gsp_rpc *rpc = container_of(repv, typeof(*rpc), data); +- +- r535_gsp_msg_done(gsp, rpc); +-} +- +-static void * +-r535_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 payload_size) +-{ +- struct nvfw_gsp_rpc *rpc; +- +- rpc = r535_gsp_cmdq_get(gsp, ALIGN(sizeof(*rpc) + payload_size, +- sizeof(u64))); +- if (IS_ERR(rpc)) +- return ERR_CAST(rpc); +- +- rpc->header_version = 0x03000000; +- rpc->signature = ('C' << 24) | ('P' << 16) | ('R' << 8) | 'V'; +- rpc->function = fn; +- rpc->rpc_result = 0xffffffff; +- rpc->rpc_result_private = 0xffffffff; +- rpc->length = sizeof(*rpc) + payload_size; +- return rpc->data; +-} +- +-static void * +-r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload, bool wait, +- u32 gsp_rpc_len) +-{ +- struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc); +- struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg); +- const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*msg); +- const u32 max_payload_size = max_rpc_size - sizeof(*rpc); +- u32 payload_size = rpc->length - sizeof(*rpc); +- void *repv; +- +- mutex_lock(&gsp->cmdq.mutex); +- if (payload_size > max_payload_size) { +- const u32 fn = rpc->function; +- u32 remain_payload_size = payload_size; +- +- /* Adjust length, and send initial RPC. */ +- rpc->length = sizeof(*rpc) + max_payload_size; +- msg->checksum = rpc->length; +- +- repv = r535_gsp_rpc_send(gsp, payload, false, 0); +- if (IS_ERR(repv)) +- goto done; +- +- payload += max_payload_size; +- remain_payload_size -= max_payload_size; +- +- /* Remaining chunks sent as CONTINUATION_RECORD RPCs. */ +- while (remain_payload_size) { +- u32 size = min(remain_payload_size, +- max_payload_size); +- void *next; +- +- next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size); +- if (IS_ERR(next)) { +- repv = next; +- goto done; +- } +- +- memcpy(next, payload, size); +- +- repv = r535_gsp_rpc_send(gsp, next, false, 0); +- if (IS_ERR(repv)) +- goto done; +- +- payload += size; +- remain_payload_size -= size; +- } +- +- /* Wait for reply. */ +- rpc = r535_gsp_msg_recv(gsp, fn, payload_size + +- sizeof(*rpc)); +- if (!IS_ERR_OR_NULL(rpc)) { +- if (wait) { +- repv = rpc->data; +- } else { +- nvkm_gsp_rpc_done(gsp, rpc); +- repv = NULL; +- } +- } else { +- repv = wait ? rpc : NULL; +- } +- } else { +- repv = r535_gsp_rpc_send(gsp, payload, wait, gsp_rpc_len); +- } +- +-done: +- mutex_unlock(&gsp->cmdq.mutex); +- return repv; +-} +- + const struct nvkm_gsp_rm + r535_gsp_rm = { +- .rpc_get = r535_gsp_rpc_get, +- .rpc_push = r535_gsp_rpc_push, +- .rpc_done = r535_gsp_rpc_done, ++ .api = &r535_rm, + + .rm_ctrl_get = r535_gsp_rpc_rm_ctrl_get, + .rm_ctrl_push = r535_gsp_rpc_rm_ctrl_push, +@@ -1327,7 +672,7 @@ r535_gsp_rpc_unloading_guest_driver(struct nvkm_gsp *gsp, bool suspend) + rpc->newLevel = NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_0; + } + +- return nvkm_gsp_rpc_wr(gsp, rpc, true); ++ return nvkm_gsp_rpc_wr(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV); + } + + enum registry_type { +@@ -1684,7 +1029,7 @@ r535_gsp_rpc_set_registry(struct nvkm_gsp *gsp) + + build_registry(gsp, rpc); + +- return nvkm_gsp_rpc_wr(gsp, rpc, false); ++ return nvkm_gsp_rpc_wr(gsp, rpc, NVKM_GSP_RPC_REPLY_NOWAIT); + + fail: + clean_registry(gsp); +@@ -1893,7 +1238,7 @@ r535_gsp_rpc_set_system_info(struct nvkm_gsp *gsp) + info->pciConfigMirrorSize = 0x001000; + r535_gsp_acpi_info(gsp, &info->acpiMethodData); + +- return nvkm_gsp_rpc_wr(gsp, info, false); ++ return nvkm_gsp_rpc_wr(gsp, info, NVKM_GSP_RPC_REPLY_NOWAIT); + } + + static int +@@ -2838,7 +2183,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, bool suspend) + return ret; + + nvkm_msec(gsp->subdev.device, 2000, +- if (nvkm_falcon_rd32(&gsp->falcon, 0x040) & 0x80000000) ++ if (nvkm_falcon_rd32(&gsp->falcon, 0x040) == 0x80000000) + break; + ); + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild +new file mode 100644 +index 00000000000000..1c07740215ec5f +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: MIT ++# ++# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. ++ ++include $(src)/nvkm/subdev/gsp/rm/r535/Kbuild +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild +new file mode 100644 +index 00000000000000..21c818ec070160 +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: MIT ++# ++# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. ++ ++nvkm-y += nvkm/subdev/gsp/rm/r535/rm.o ++nvkm-y += nvkm/subdev/gsp/rm/r535/rpc.o +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c +new file mode 100644 +index 00000000000000..f28b781abc5c7d +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: MIT ++ * ++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. ++ */ ++#include ++ ++const struct nvkm_rm_api ++r535_rm = { ++ .rpc = &r535_rpc, ++}; +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c +new file mode 100644 +index 00000000000000..d558b0f62b010f +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c +@@ -0,0 +1,699 @@ ++/* ++ * Copyright 2023 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#include ++ ++#include ++#include ++ ++#define GSP_MSG_MIN_SIZE GSP_PAGE_SIZE ++#define GSP_MSG_MAX_SIZE (GSP_MSG_MIN_SIZE * 16) ++ ++/** ++ * DOC: GSP message queue element ++ * ++ * https://github.com/NVIDIA/open-gpu-kernel-modules/blob/535/src/nvidia/inc/kernel/gpu/gsp/message_queue_priv.h ++ * ++ * The GSP command queue and status queue are message queues for the ++ * communication between software and GSP. The software submits the GSP ++ * RPC via the GSP command queue, GSP writes the status of the submitted ++ * RPC in the status queue. ++ * ++ * A GSP message queue element consists of three parts: ++ * ++ * - message element header (struct r535_gsp_msg), which mostly maintains ++ * the metadata for queuing the element. ++ * ++ * - RPC message header (struct nvfw_gsp_rpc), which maintains the info ++ * of the RPC. E.g., the RPC function number. ++ * ++ * - The payload, where the RPC message stays. E.g. the params of a ++ * specific RPC function. Some RPC functions also have their headers ++ * in the payload. E.g. rm_alloc, rm_control. ++ * ++ * The memory layout of a GSP message element can be illustrated below:: ++ * ++ * +------------------------+ ++ * | Message Element Header | ++ * | (r535_gsp_msg) | ++ * | | ++ * | (r535_gsp_msg.data) | ++ * | | | ++ * |----------V-------------| ++ * | GSP RPC Header | ++ * | (nvfw_gsp_rpc) | ++ * | | ++ * | (nvfw_gsp_rpc.data) | ++ * | | | ++ * |----------V-------------| ++ * | Payload | ++ * | | ++ * | header(optional) | ++ * | params | ++ * +------------------------+ ++ * ++ * The max size of a message queue element is 16 pages (including the ++ * headers). When a GSP message to be sent is larger than 16 pages, the ++ * message should be split into multiple elements and sent accordingly. ++ * ++ * In the bunch of the split elements, the first element has the expected ++ * function number, while the rest of the elements are sent with the ++ * function number NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD. ++ * ++ * GSP consumes the elements from the cmdq and always writes the result ++ * back to the msgq. The result is also formed as split elements. ++ * ++ * Terminology: ++ * ++ * - gsp_msg(msg): GSP message element (element header + GSP RPC header + ++ * payload) ++ * - gsp_rpc(rpc): GSP RPC (RPC header + payload) ++ * - gsp_rpc_buf: buffer for (GSP RPC header + payload) ++ * - gsp_rpc_len: size of (GSP RPC header + payload) ++ * - params_size: size of params in the payload ++ * - payload_size: size of (header if exists + params) in the payload ++ */ ++ ++struct r535_gsp_msg { ++ u8 auth_tag_buffer[16]; ++ u8 aad_buffer[16]; ++ u32 checksum; ++ u32 sequence; ++ u32 elem_count; ++ u32 pad; ++ u8 data[]; ++}; ++ ++struct nvfw_gsp_rpc { ++ u32 header_version; ++ u32 signature; ++ u32 length; ++ u32 function; ++ u32 rpc_result; ++ u32 rpc_result_private; ++ u32 sequence; ++ union { ++ u32 spare; ++ u32 cpuRmGfid; ++ }; ++ u8 data[]; ++}; ++ ++#define GSP_MSG_HDR_SIZE offsetof(struct r535_gsp_msg, data) ++ ++#define to_gsp_hdr(p, header) \ ++ container_of((void *)p, typeof(*header), data) ++ ++#define to_payload_hdr(p, header) \ ++ container_of((void *)p, typeof(*header), params) ++ ++int ++r535_rpc_status_to_errno(uint32_t rpc_status) ++{ ++ switch (rpc_status) { ++ case 0x55: /* NV_ERR_NOT_READY */ ++ case 0x66: /* NV_ERR_TIMEOUT_RETRY */ ++ return -EBUSY; ++ case 0x51: /* NV_ERR_NO_MEMORY */ ++ return -ENOMEM; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ++r535_gsp_msgq_wait(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *ptime) ++{ ++ u32 size, rptr = *gsp->msgq.rptr; ++ int used; ++ ++ size = DIV_ROUND_UP(GSP_MSG_HDR_SIZE + gsp_rpc_len, ++ GSP_PAGE_SIZE); ++ if (WARN_ON(!size || size >= gsp->msgq.cnt)) ++ return -EINVAL; ++ ++ do { ++ u32 wptr = *gsp->msgq.wptr; ++ ++ used = wptr + gsp->msgq.cnt - rptr; ++ if (used >= gsp->msgq.cnt) ++ used -= gsp->msgq.cnt; ++ if (used >= size) ++ break; ++ ++ usleep_range(1, 2); ++ } while (--(*ptime)); ++ ++ if (WARN_ON(!*ptime)) ++ return -ETIMEDOUT; ++ ++ return used; ++} ++ ++static struct r535_gsp_msg * ++r535_gsp_msgq_get_entry(struct nvkm_gsp *gsp) ++{ ++ u32 rptr = *gsp->msgq.rptr; ++ ++ /* Skip the first page, which is the message queue info */ ++ return (void *)((u8 *)gsp->shm.msgq.ptr + GSP_PAGE_SIZE + ++ rptr * GSP_PAGE_SIZE); ++} ++ ++/** ++ * DOC: Receive a GSP message queue element ++ * ++ * Receiving a GSP message queue element from the message queue consists of ++ * the following steps: ++ * ++ * - Peek the element from the queue: r535_gsp_msgq_peek(). ++ * Peek the first page of the element to determine the total size of the ++ * message before allocating the proper memory. ++ * ++ * - Allocate memory for the message. ++ * Once the total size of the message is determined from the GSP message ++ * queue element, the caller of r535_gsp_msgq_recv() allocates the ++ * required memory. ++ * ++ * - Receive the message: r535_gsp_msgq_recv(). ++ * Copy the message into the allocated memory. Advance the read pointer. ++ * If the message is a large GSP message, r535_gsp_msgq_recv() calls ++ * r535_gsp_msgq_recv_one_elem() repeatedly to receive continuation parts ++ * until the complete message is received. ++ * r535_gsp_msgq_recv() assembles the payloads of cotinuation parts into ++ * the return of the large GSP message. ++ * ++ * - Free the allocated memory: r535_gsp_msg_done(). ++ * The user is responsible for freeing the memory allocated for the GSP ++ * message pages after they have been processed. ++ */ ++static void * ++r535_gsp_msgq_peek(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) ++{ ++ struct r535_gsp_msg *mqe; ++ int ret; ++ ++ ret = r535_gsp_msgq_wait(gsp, gsp_rpc_len, retries); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ mqe = r535_gsp_msgq_get_entry(gsp); ++ ++ return mqe->data; ++} ++ ++struct r535_gsp_msg_info { ++ int *retries; ++ u32 gsp_rpc_len; ++ void *gsp_rpc_buf; ++ bool continuation; ++}; ++ ++static void ++r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl); ++ ++static void * ++r535_gsp_msgq_recv_one_elem(struct nvkm_gsp *gsp, ++ struct r535_gsp_msg_info *info) ++{ ++ u8 *buf = info->gsp_rpc_buf; ++ u32 rptr = *gsp->msgq.rptr; ++ struct r535_gsp_msg *mqe; ++ u32 size, expected, len; ++ int ret; ++ ++ expected = info->gsp_rpc_len; ++ ++ ret = r535_gsp_msgq_wait(gsp, expected, info->retries); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ mqe = r535_gsp_msgq_get_entry(gsp); ++ ++ if (info->continuation) { ++ struct nvfw_gsp_rpc *rpc = (struct nvfw_gsp_rpc *)mqe->data; ++ ++ if (rpc->function != NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD) { ++ nvkm_error(&gsp->subdev, ++ "Not a continuation of a large RPC\n"); ++ r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); ++ return ERR_PTR(-EIO); ++ } ++ } ++ ++ size = ALIGN(expected + GSP_MSG_HDR_SIZE, GSP_PAGE_SIZE); ++ ++ len = ((gsp->msgq.cnt - rptr) * GSP_PAGE_SIZE) - sizeof(*mqe); ++ len = min_t(u32, expected, len); ++ ++ if (info->continuation) ++ memcpy(buf, mqe->data + sizeof(struct nvfw_gsp_rpc), ++ len - sizeof(struct nvfw_gsp_rpc)); ++ else ++ memcpy(buf, mqe->data, len); ++ ++ expected -= len; ++ ++ if (expected) { ++ mqe = (void *)((u8 *)gsp->shm.msgq.ptr + 0x1000 + 0 * 0x1000); ++ memcpy(buf + len, mqe, expected); ++ } ++ ++ rptr = (rptr + DIV_ROUND_UP(size, GSP_PAGE_SIZE)) % gsp->msgq.cnt; ++ ++ mb(); ++ (*gsp->msgq.rptr) = rptr; ++ return buf; ++} ++ ++static void * ++r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries) ++{ ++ struct r535_gsp_msg *mqe; ++ const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*mqe); ++ struct nvfw_gsp_rpc *rpc; ++ struct r535_gsp_msg_info info = {0}; ++ u32 expected = gsp_rpc_len; ++ void *buf; ++ ++ mqe = r535_gsp_msgq_get_entry(gsp); ++ rpc = (struct nvfw_gsp_rpc *)mqe->data; ++ ++ if (WARN_ON(rpc->length > max_rpc_size)) ++ return NULL; ++ ++ buf = kvmalloc(max_t(u32, rpc->length, expected), GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ info.gsp_rpc_buf = buf; ++ info.retries = retries; ++ info.gsp_rpc_len = rpc->length; ++ ++ buf = r535_gsp_msgq_recv_one_elem(gsp, &info); ++ if (IS_ERR(buf)) { ++ kvfree(info.gsp_rpc_buf); ++ info.gsp_rpc_buf = NULL; ++ return buf; ++ } ++ ++ if (expected <= max_rpc_size) ++ return buf; ++ ++ info.gsp_rpc_buf += info.gsp_rpc_len; ++ expected -= info.gsp_rpc_len; ++ ++ while (expected) { ++ u32 size; ++ ++ rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries); ++ if (IS_ERR_OR_NULL(rpc)) { ++ kfree(buf); ++ return rpc; ++ } ++ ++ info.gsp_rpc_len = rpc->length; ++ info.continuation = true; ++ ++ rpc = r535_gsp_msgq_recv_one_elem(gsp, &info); ++ if (IS_ERR_OR_NULL(rpc)) { ++ kfree(buf); ++ return rpc; ++ } ++ ++ size = info.gsp_rpc_len - sizeof(*rpc); ++ expected -= size; ++ info.gsp_rpc_buf += size; ++ } ++ ++ rpc = buf; ++ rpc->length = gsp_rpc_len; ++ return buf; ++} ++ ++static int ++r535_gsp_cmdq_push(struct nvkm_gsp *gsp, void *rpc) ++{ ++ struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg); ++ struct r535_gsp_msg *cqe; ++ u32 gsp_rpc_len = msg->checksum; ++ u64 *ptr = (void *)msg; ++ u64 *end; ++ u64 csum = 0; ++ int free, time = 1000000; ++ u32 wptr, size, step, len; ++ u32 off = 0; ++ ++ len = ALIGN(GSP_MSG_HDR_SIZE + gsp_rpc_len, GSP_PAGE_SIZE); ++ ++ end = (u64 *)((char *)ptr + len); ++ msg->pad = 0; ++ msg->checksum = 0; ++ msg->sequence = gsp->cmdq.seq++; ++ msg->elem_count = DIV_ROUND_UP(len, 0x1000); ++ ++ while (ptr < end) ++ csum ^= *ptr++; ++ ++ msg->checksum = upper_32_bits(csum) ^ lower_32_bits(csum); ++ ++ wptr = *gsp->cmdq.wptr; ++ do { ++ do { ++ free = *gsp->cmdq.rptr + gsp->cmdq.cnt - wptr - 1; ++ if (free >= gsp->cmdq.cnt) ++ free -= gsp->cmdq.cnt; ++ if (free >= 1) ++ break; ++ ++ usleep_range(1, 2); ++ } while(--time); ++ ++ if (WARN_ON(!time)) { ++ kvfree(msg); ++ return -ETIMEDOUT; ++ } ++ ++ cqe = (void *)((u8 *)gsp->shm.cmdq.ptr + 0x1000 + wptr * 0x1000); ++ step = min_t(u32, free, (gsp->cmdq.cnt - wptr)); ++ size = min_t(u32, len, step * GSP_PAGE_SIZE); ++ ++ memcpy(cqe, (u8 *)msg + off, size); ++ ++ wptr += DIV_ROUND_UP(size, 0x1000); ++ if (wptr == gsp->cmdq.cnt) ++ wptr = 0; ++ ++ off += size; ++ len -= size; ++ } while (len); ++ ++ nvkm_trace(&gsp->subdev, "cmdq: wptr %d\n", wptr); ++ wmb(); ++ (*gsp->cmdq.wptr) = wptr; ++ mb(); ++ ++ nvkm_falcon_wr32(&gsp->falcon, 0xc00, 0x00000000); ++ ++ kvfree(msg); ++ return 0; ++} ++ ++static void * ++r535_gsp_cmdq_get(struct nvkm_gsp *gsp, u32 gsp_rpc_len) ++{ ++ struct r535_gsp_msg *msg; ++ u32 size = GSP_MSG_HDR_SIZE + gsp_rpc_len; ++ ++ size = ALIGN(size, GSP_MSG_MIN_SIZE); ++ msg = kvzalloc(size, GFP_KERNEL); ++ if (!msg) ++ return ERR_PTR(-ENOMEM); ++ ++ msg->checksum = gsp_rpc_len; ++ return msg->data; ++} ++ ++static void ++r535_gsp_msg_done(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg) ++{ ++ kvfree(msg); ++} ++ ++static void ++r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl) ++{ ++ if (gsp->subdev.debug >= lvl) { ++ nvkm_printk__(&gsp->subdev, lvl, info, ++ "msg fn:%d len:0x%x/0x%zx res:0x%x resp:0x%x\n", ++ msg->function, msg->length, msg->length - sizeof(*msg), ++ msg->rpc_result, msg->rpc_result_private); ++ print_hex_dump(KERN_INFO, "msg: ", DUMP_PREFIX_OFFSET, 16, 1, ++ msg->data, msg->length - sizeof(*msg), true); ++ } ++} ++ ++struct nvfw_gsp_rpc * ++r535_gsp_msg_recv(struct nvkm_gsp *gsp, int fn, u32 gsp_rpc_len) ++{ ++ struct nvkm_subdev *subdev = &gsp->subdev; ++ struct nvfw_gsp_rpc *rpc; ++ int retries = 4000000, i; ++ ++retry: ++ rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), &retries); ++ if (IS_ERR_OR_NULL(rpc)) ++ return rpc; ++ ++ rpc = r535_gsp_msgq_recv(gsp, gsp_rpc_len, &retries); ++ if (IS_ERR_OR_NULL(rpc)) ++ return rpc; ++ ++ if (rpc->rpc_result) { ++ r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); ++ r535_gsp_msg_done(gsp, rpc); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ r535_gsp_msg_dump(gsp, rpc, NV_DBG_TRACE); ++ ++ if (fn && rpc->function == fn) { ++ if (gsp_rpc_len) { ++ if (rpc->length < gsp_rpc_len) { ++ nvkm_error(subdev, "rpc len %d < %d\n", ++ rpc->length, gsp_rpc_len); ++ r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR); ++ r535_gsp_msg_done(gsp, rpc); ++ return ERR_PTR(-EIO); ++ } ++ ++ return rpc; ++ } ++ ++ r535_gsp_msg_done(gsp, rpc); ++ return NULL; ++ } ++ ++ for (i = 0; i < gsp->msgq.ntfy_nr; i++) { ++ struct nvkm_gsp_msgq_ntfy *ntfy = &gsp->msgq.ntfy[i]; ++ ++ if (ntfy->fn == rpc->function) { ++ if (ntfy->func) ++ ntfy->func(ntfy->priv, ntfy->fn, rpc->data, ++ rpc->length - sizeof(*rpc)); ++ break; ++ } ++ } ++ ++ if (i == gsp->msgq.ntfy_nr) ++ r535_gsp_msg_dump(gsp, rpc, NV_DBG_WARN); ++ ++ r535_gsp_msg_done(gsp, rpc); ++ if (fn) ++ goto retry; ++ ++ if (*gsp->msgq.rptr != *gsp->msgq.wptr) ++ goto retry; ++ ++ return NULL; ++} ++ ++int ++r535_gsp_msg_ntfy_add(struct nvkm_gsp *gsp, u32 fn, nvkm_gsp_msg_ntfy_func func, void *priv) ++{ ++ int ret = 0; ++ ++ mutex_lock(&gsp->msgq.mutex); ++ if (WARN_ON(gsp->msgq.ntfy_nr >= ARRAY_SIZE(gsp->msgq.ntfy))) { ++ ret = -ENOSPC; ++ } else { ++ gsp->msgq.ntfy[gsp->msgq.ntfy_nr].fn = fn; ++ gsp->msgq.ntfy[gsp->msgq.ntfy_nr].func = func; ++ gsp->msgq.ntfy[gsp->msgq.ntfy_nr].priv = priv; ++ gsp->msgq.ntfy_nr++; ++ } ++ mutex_unlock(&gsp->msgq.mutex); ++ return ret; ++} ++ ++int ++r535_gsp_rpc_poll(struct nvkm_gsp *gsp, u32 fn) ++{ ++ void *repv; ++ ++ mutex_lock(&gsp->cmdq.mutex); ++ repv = r535_gsp_msg_recv(gsp, fn, 0); ++ mutex_unlock(&gsp->cmdq.mutex); ++ if (IS_ERR(repv)) ++ return PTR_ERR(repv); ++ ++ return 0; ++} ++ ++static void * ++r535_gsp_rpc_handle_reply(struct nvkm_gsp *gsp, u32 fn, ++ enum nvkm_gsp_rpc_reply_policy policy, ++ u32 gsp_rpc_len) ++{ ++ struct nvfw_gsp_rpc *reply; ++ void *repv = NULL; ++ ++ switch (policy) { ++ case NVKM_GSP_RPC_REPLY_NOWAIT: ++ break; ++ case NVKM_GSP_RPC_REPLY_RECV: ++ reply = r535_gsp_msg_recv(gsp, fn, gsp_rpc_len); ++ if (!IS_ERR_OR_NULL(reply)) ++ repv = reply->data; ++ else ++ repv = reply; ++ break; ++ case NVKM_GSP_RPC_REPLY_POLL: ++ repv = r535_gsp_msg_recv(gsp, fn, 0); ++ break; ++ } ++ ++ return repv; ++} ++ ++static void * ++r535_gsp_rpc_send(struct nvkm_gsp *gsp, void *payload, ++ enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len) ++{ ++ struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc); ++ u32 fn = rpc->function; ++ int ret; ++ ++ if (gsp->subdev.debug >= NV_DBG_TRACE) { ++ nvkm_trace(&gsp->subdev, "rpc fn:%d len:0x%x/0x%zx\n", rpc->function, ++ rpc->length, rpc->length - sizeof(*rpc)); ++ print_hex_dump(KERN_INFO, "rpc: ", DUMP_PREFIX_OFFSET, 16, 1, ++ rpc->data, rpc->length - sizeof(*rpc), true); ++ } ++ ++ ret = r535_gsp_cmdq_push(gsp, rpc); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return r535_gsp_rpc_handle_reply(gsp, fn, policy, gsp_rpc_len); ++} ++ ++static void ++r535_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv) ++{ ++ struct nvfw_gsp_rpc *rpc = container_of(repv, typeof(*rpc), data); ++ ++ r535_gsp_msg_done(gsp, rpc); ++} ++ ++static void * ++r535_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 payload_size) ++{ ++ struct nvfw_gsp_rpc *rpc; ++ ++ rpc = r535_gsp_cmdq_get(gsp, ALIGN(sizeof(*rpc) + payload_size, ++ sizeof(u64))); ++ if (IS_ERR(rpc)) ++ return ERR_CAST(rpc); ++ ++ rpc->header_version = 0x03000000; ++ rpc->signature = ('C' << 24) | ('P' << 16) | ('R' << 8) | 'V'; ++ rpc->function = fn; ++ rpc->rpc_result = 0xffffffff; ++ rpc->rpc_result_private = 0xffffffff; ++ rpc->length = sizeof(*rpc) + payload_size; ++ return rpc->data; ++} ++ ++static void * ++r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload, ++ enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len) ++{ ++ struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc); ++ struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg); ++ const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*msg); ++ const u32 max_payload_size = max_rpc_size - sizeof(*rpc); ++ u32 payload_size = rpc->length - sizeof(*rpc); ++ void *repv; ++ ++ mutex_lock(&gsp->cmdq.mutex); ++ if (payload_size > max_payload_size) { ++ const u32 fn = rpc->function; ++ u32 remain_payload_size = payload_size; ++ void *next; ++ ++ /* Send initial RPC. */ ++ next = r535_gsp_rpc_get(gsp, fn, max_payload_size); ++ if (IS_ERR(next)) { ++ repv = next; ++ goto done; ++ } ++ ++ memcpy(next, payload, max_payload_size); ++ ++ repv = r535_gsp_rpc_send(gsp, next, NVKM_GSP_RPC_REPLY_NOWAIT, 0); ++ if (IS_ERR(repv)) ++ goto done; ++ ++ payload += max_payload_size; ++ remain_payload_size -= max_payload_size; ++ ++ /* Remaining chunks sent as CONTINUATION_RECORD RPCs. */ ++ while (remain_payload_size) { ++ u32 size = min(remain_payload_size, ++ max_payload_size); ++ ++ next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size); ++ if (IS_ERR(next)) { ++ repv = next; ++ goto done; ++ } ++ ++ memcpy(next, payload, size); ++ ++ repv = r535_gsp_rpc_send(gsp, next, NVKM_GSP_RPC_REPLY_NOWAIT, 0); ++ if (IS_ERR(repv)) ++ goto done; ++ ++ payload += size; ++ remain_payload_size -= size; ++ } ++ ++ /* Wait for reply. */ ++ repv = r535_gsp_rpc_handle_reply(gsp, fn, policy, payload_size + ++ sizeof(*rpc)); ++ if (!IS_ERR(repv)) ++ kvfree(msg); ++ } else { ++ repv = r535_gsp_rpc_send(gsp, payload, policy, gsp_rpc_len); ++ } ++ ++done: ++ mutex_unlock(&gsp->cmdq.mutex); ++ return repv; ++} ++ ++const struct nvkm_rm_api_rpc ++r535_rpc = { ++ .get = r535_gsp_rpc_get, ++ .push = r535_gsp_rpc_push, ++ .done = r535_gsp_rpc_done, ++}; +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h +new file mode 100644 +index 00000000000000..7a0ece9791671f +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: MIT ++ * ++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. ++ */ ++#include ++#ifndef __NVKM_RM_H__ ++#define __NVKM_RM_H__ ++ ++struct nvkm_rm_api { ++ const struct nvkm_rm_api_rpc { ++ void *(*get)(struct nvkm_gsp *, u32 fn, u32 argc); ++ void *(*push)(struct nvkm_gsp *gsp, void *argv, ++ enum nvkm_gsp_rpc_reply_policy policy, u32 repc); ++ void (*done)(struct nvkm_gsp *gsp, void *repv); ++ } *rpc; ++}; ++ ++extern const struct nvkm_rm_api r535_rm; ++extern const struct nvkm_rm_api_rpc r535_rpc; ++#endif +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h +new file mode 100644 +index 00000000000000..4431e33b33049f +--- /dev/null ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: MIT ++ * ++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. ++ */ ++#ifndef __NVKM_RM_RPC_H__ ++#define __NVKM_RM_RPC_H__ ++#include "rm.h" ++ ++#define to_payload_hdr(p, header) \ ++ container_of((void *)p, typeof(*header), params) ++ ++int r535_gsp_rpc_poll(struct nvkm_gsp *, u32 fn); ++ ++struct nvfw_gsp_rpc *r535_gsp_msg_recv(struct nvkm_gsp *, int fn, u32 gsp_rpc_len); ++int r535_gsp_msg_ntfy_add(struct nvkm_gsp *, u32 fn, nvkm_gsp_msg_ntfy_func, void *priv); ++ ++int r535_rpc_status_to_errno(uint32_t rpc_status); ++#endif +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/r535.c +index 5f3c9c02a4c04b..35ba1798ee6e49 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/r535.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/r535.c +@@ -105,7 +105,7 @@ fbsr_memlist(struct nvkm_gsp_device *device, u32 handle, enum nvkm_memory_target + rpc->pteDesc.pte_pde[i].pte = (phys >> 12) + i; + } + +- ret = nvkm_gsp_rpc_wr(gsp, rpc, true); ++ ret = nvkm_gsp_rpc_wr(gsp, rpc, NVKM_GSP_RPC_REPLY_POLL); + if (ret) + return ret; + +diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +index 729cbb0d8403ff..36abfa2e65e962 100644 +--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c ++++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +@@ -36,60 +36,49 @@ static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel) + static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt) + { + struct mipi_dsi_device *dsi = sharp_nt->dsi; +- int ret; ++ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + +- ret = mipi_dsi_dcs_exit_sleep_mode(dsi); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + +- msleep(120); ++ mipi_dsi_msleep(&dsi_ctx, 120); + + /* Novatek two-lane operation */ +- ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xae, 0x03); + + /* Set both MCU and RGB I/F to 24bpp */ +- ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT | +- (MIPI_DCS_PIXEL_FMT_24BIT << 4)); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, ++ MIPI_DCS_PIXEL_FMT_24BIT | ++ (MIPI_DCS_PIXEL_FMT_24BIT << 4)); + +- return 0; ++ return dsi_ctx.accum_err; + } + + static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt) + { + struct mipi_dsi_device *dsi = sharp_nt->dsi; +- int ret; ++ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + +- ret = mipi_dsi_dcs_set_display_on(dsi); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + +- return 0; ++ return dsi_ctx.accum_err; + } + + static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt) + { + struct mipi_dsi_device *dsi = sharp_nt->dsi; +- int ret; ++ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + +- ret = mipi_dsi_dcs_set_display_off(dsi); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + +- ret = mipi_dsi_dcs_enter_sleep_mode(dsi); +- if (ret < 0) +- return ret; ++ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + +- return 0; ++ return dsi_ctx.accum_err; + } + + static int sharp_nt_panel_unprepare(struct drm_panel *panel) +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 3aaac96c0bfbf5..53211b5eaa09b9 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -3798,6 +3798,32 @@ static const struct panel_desc pda_91_00156_a0 = { + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + }; + ++static const struct drm_display_mode powertip_ph128800t004_zza01_mode = { ++ .clock = 71150, ++ .hdisplay = 1280, ++ .hsync_start = 1280 + 48, ++ .hsync_end = 1280 + 48 + 32, ++ .htotal = 1280 + 48 + 32 + 80, ++ .vdisplay = 800, ++ .vsync_start = 800 + 9, ++ .vsync_end = 800 + 9 + 8, ++ .vtotal = 800 + 9 + 8 + 6, ++ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, ++}; ++ ++static const struct panel_desc powertip_ph128800t004_zza01 = { ++ .modes = &powertip_ph128800t004_zza01_mode, ++ .num_modes = 1, ++ .bpc = 8, ++ .size = { ++ .width = 216, ++ .height = 135, ++ }, ++ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, ++ .connector_type = DRM_MODE_CONNECTOR_LVDS, ++}; ++ + static const struct drm_display_mode powertip_ph128800t006_zhc01_mode = { + .clock = 66500, + .hdisplay = 1280, +@@ -5155,6 +5181,9 @@ static const struct of_device_id platform_of_match[] = { + }, { + .compatible = "pda,91-00156-a0", + .data = &pda_91_00156_a0, ++ }, { ++ .compatible = "powertip,ph128800t004-zza01", ++ .data = &powertip_ph128800t004_zza01, + }, { + .compatible = "powertip,ph128800t006-zhc01", + .data = &powertip_ph128800t006_zhc01, +diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c +index 7cca97d298ea10..cc838bfc82e00e 100644 +--- a/drivers/gpu/drm/panthor/panthor_mmu.c ++++ b/drivers/gpu/drm/panthor/panthor_mmu.c +@@ -1714,7 +1714,6 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) + * re-enabled. + */ + ptdev->mmu->irq.mask = new_int_mask; +- gpu_write(ptdev, MMU_INT_MASK, new_int_mask); + + if (ptdev->mmu->as.slots[as].vm) + ptdev->mmu->as.slots[as].vm->unhandled_fault = true; +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index 483ecfeaebb08f..87dfd300015832 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -10,10 +10,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #include + #include +@@ -29,8 +31,19 @@ + + #include "inno_hdmi.h" + ++#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) ++ + #define INNO_HDMI_MIN_TMDS_CLOCK 25000000U + ++#define RK3036_GRF_SOC_CON2 0x148 ++#define RK3036_HDMI_PHSYNC BIT(4) ++#define RK3036_HDMI_PVSYNC BIT(5) ++ ++enum inno_hdmi_dev_type { ++ RK3036_HDMI, ++ RK3128_HDMI, ++}; ++ + struct inno_hdmi_phy_config { + unsigned long pixelclock; + u8 pre_emphasis; +@@ -38,6 +51,7 @@ struct inno_hdmi_phy_config { + }; + + struct inno_hdmi_variant { ++ enum inno_hdmi_dev_type dev_type; + struct inno_hdmi_phy_config *phy_configs; + struct inno_hdmi_phy_config *default_phy_config; + }; +@@ -58,6 +72,7 @@ struct inno_hdmi { + struct clk *pclk; + struct clk *refclk; + void __iomem *regs; ++ struct regmap *grf; + + struct drm_connector connector; + struct rockchip_encoder encoder; +@@ -374,7 +389,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) + static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + struct drm_display_mode *mode) + { +- int value; ++ int value, psync; ++ ++ if (hdmi->variant->dev_type == RK3036_HDMI) { ++ psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? RK3036_HDMI_PHSYNC : 0; ++ value = HIWORD_UPDATE(psync, RK3036_HDMI_PHSYNC); ++ psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? RK3036_HDMI_PVSYNC : 0; ++ value |= HIWORD_UPDATE(psync, RK3036_HDMI_PVSYNC); ++ regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value); ++ } + + /* Set detail external video timing polarity and interlace mode */ + value = v_EXTERANL_VIDEO(1); +@@ -911,6 +934,15 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + goto err_disable_pclk; + } + ++ if (hdmi->variant->dev_type == RK3036_HDMI) { ++ hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); ++ if (IS_ERR(hdmi->grf)) { ++ ret = dev_err_probe(dev, PTR_ERR(hdmi->grf), ++ "Unable to get rockchip,grf\n"); ++ goto err_disable_clk; ++ } ++ } ++ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; +@@ -995,11 +1027,13 @@ static void inno_hdmi_remove(struct platform_device *pdev) + } + + static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { ++ .dev_type = RK3036_HDMI, + .phy_configs = rk3036_hdmi_phy_configs, + .default_phy_config = &rk3036_hdmi_phy_configs[1], + }; + + static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { ++ .dev_type = RK3128_HDMI, + .phy_configs = rk3128_hdmi_phy_configs, + .default_phy_config = &rk3128_hdmi_phy_configs[1], + }; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +index 680bedbb770e6f..fc3ecb9fcd9576 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +@@ -710,6 +710,7 @@ enum dst_factor_mode { + + #define VOP2_COLOR_KEY_MASK BIT(31) + ++#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL GENMASK(31, 30) + #define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28) + #define RK3568_OVL_CTRL__YUV_MODE(vp) BIT(vp) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +index 0a2840cbe8e22d..32c4ed6857395a 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +@@ -2070,7 +2070,10 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); + + ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); +- ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; ++ ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; ++ ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL; ++ ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id); ++ + if (vcstate->yuv_overlay) + ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); + else +diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c +index dd2006d51c7a2f..eec43d1a55951b 100644 +--- a/drivers/gpu/drm/solomon/ssd130x.c ++++ b/drivers/gpu/drm/solomon/ssd130x.c +@@ -974,7 +974,7 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) + + static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) + { +- unsigned int columns = DIV_ROUND_UP(ssd130x->height, SSD132X_SEGMENT_WIDTH); ++ unsigned int columns = DIV_ROUND_UP(ssd130x->width, SSD132X_SEGMENT_WIDTH); + unsigned int height = ssd130x->height; + + memset(data_array, 0, columns * height); +diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig +index 54c84c9801c192..cbdd2096b17a0b 100644 +--- a/drivers/gpu/drm/tiny/Kconfig ++++ b/drivers/gpu/drm/tiny/Kconfig +@@ -3,6 +3,7 @@ + config DRM_APPLETBDRM + tristate "DRM support for Apple Touch Bars" + depends on DRM && USB && MMU ++ depends on X86 || COMPILE_TEST + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help +diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c +index f8f20d2f61740f..e08e5a138420e3 100644 +--- a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c ++++ b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c +@@ -340,7 +340,7 @@ static void ttm_bo_unreserve_bulk(struct kunit *test) + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + resv = kunit_kzalloc(test, sizeof(*resv), GFP_KERNEL); +- KUNIT_ASSERT_NOT_NULL(test, ttm_dev); ++ KUNIT_ASSERT_NOT_NULL(test, resv); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); +diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c +index 35f131a46d0701..42df9d3567e79e 100644 +--- a/drivers/gpu/drm/v3d/v3d_sched.c ++++ b/drivers/gpu/drm/v3d/v3d_sched.c +@@ -199,7 +199,6 @@ v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue) + struct v3d_dev *v3d = job->v3d; + struct v3d_file_priv *file = job->file->driver_priv; + struct v3d_stats *global_stats = &v3d->queue[queue].stats; +- struct v3d_stats *local_stats = &file->stats[queue]; + u64 now = local_clock(); + unsigned long flags; + +@@ -209,7 +208,12 @@ v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue) + else + preempt_disable(); + +- v3d_stats_update(local_stats, now); ++ /* Don't update the local stats if the file context has already closed */ ++ if (file) ++ v3d_stats_update(&file->stats[queue], now); ++ else ++ drm_dbg(&v3d->drm, "The file descriptor was closed before job completion\n"); ++ + v3d_stats_update(global_stats, now); + + if (IS_ENABLED(CONFIG_LOCKDEP)) +diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c +index 5922302c3e00cc..2c9d57cf8d5334 100644 +--- a/drivers/gpu/drm/xe/xe_bo.c ++++ b/drivers/gpu/drm/xe/xe_bo.c +@@ -2408,7 +2408,7 @@ static int gem_create_user_ext_set_property(struct xe_device *xe, + int err; + u32 idx; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +@@ -2445,7 +2445,7 @@ static int gem_create_user_extensions(struct xe_device *xe, struct xe_bo *bo, + if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c +index e2bb156c71fb08..96732613b4b7df 100644 +--- a/drivers/gpu/drm/xe/xe_eu_stall.c ++++ b/drivers/gpu/drm/xe/xe_eu_stall.c +@@ -283,7 +283,7 @@ static int xe_eu_stall_user_ext_set_property(struct xe_device *xe, u64 extension + int err; + u32 idx; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +@@ -313,7 +313,7 @@ static int xe_eu_stall_user_extensions(struct xe_device *xe, u64 extension, + if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c +index b75adfc99fb7cd..44364c042ad72d 100644 +--- a/drivers/gpu/drm/xe/xe_exec.c ++++ b/drivers/gpu/drm/xe/xe_exec.c +@@ -176,8 +176,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) + } + + if (xe_exec_queue_is_parallel(q)) { +- err = __copy_from_user(addresses, addresses_user, sizeof(u64) * +- q->width); ++ err = copy_from_user(addresses, addresses_user, sizeof(u64) * ++ q->width); + if (err) { + err = -EFAULT; + goto err_syncs; +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index cd9b1c32f30f80..ce78cee5dec684 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -479,7 +479,7 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe, + int err; + u32 idx; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +@@ -518,7 +518,7 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue + if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +@@ -618,9 +618,8 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + if (XE_IOCTL_DBG(xe, !len || len > XE_HW_ENGINE_MAX_INSTANCE)) + return -EINVAL; + +- err = __copy_from_user(eci, user_eci, +- sizeof(struct drm_xe_engine_class_instance) * +- len); ++ err = copy_from_user(eci, user_eci, ++ sizeof(struct drm_xe_engine_class_instance) * len); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + +diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c +index 66198cf2662c57..4bad8894fa12c3 100644 +--- a/drivers/gpu/drm/xe/xe_gt.c ++++ b/drivers/gpu/drm/xe/xe_gt.c +@@ -116,7 +116,7 @@ static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) + xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg); + } + +- xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0x3); ++ xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0xF); + xe_force_wake_put(gt_to_fw(gt), fw_ref); + } + +diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c +index 552ac92496a408..60d9354e7dbf4b 100644 +--- a/drivers/gpu/drm/xe/xe_gt_freq.c ++++ b/drivers/gpu/drm/xe/xe_gt_freq.c +@@ -61,9 +61,10 @@ dev_to_xe(struct device *dev) + return gt_to_xe(kobj_to_gt(dev->kobj.parent)); + } + +-static ssize_t act_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t act_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + +@@ -73,11 +74,12 @@ static ssize_t act_freq_show(struct device *dev, + + return sysfs_emit(buf, "%d\n", freq); + } +-static DEVICE_ATTR_RO(act_freq); ++static struct kobj_attribute attr_act_freq = __ATTR_RO(act_freq); + +-static ssize_t cur_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t cur_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + ssize_t ret; +@@ -90,11 +92,12 @@ static ssize_t cur_freq_show(struct device *dev, + + return sysfs_emit(buf, "%d\n", freq); + } +-static DEVICE_ATTR_RO(cur_freq); ++static struct kobj_attribute attr_cur_freq = __ATTR_RO(cur_freq); + +-static ssize_t rp0_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t rp0_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + +@@ -104,11 +107,12 @@ static ssize_t rp0_freq_show(struct device *dev, + + return sysfs_emit(buf, "%d\n", freq); + } +-static DEVICE_ATTR_RO(rp0_freq); ++static struct kobj_attribute attr_rp0_freq = __ATTR_RO(rp0_freq); + +-static ssize_t rpe_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t rpe_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + +@@ -118,11 +122,12 @@ static ssize_t rpe_freq_show(struct device *dev, + + return sysfs_emit(buf, "%d\n", freq); + } +-static DEVICE_ATTR_RO(rpe_freq); ++static struct kobj_attribute attr_rpe_freq = __ATTR_RO(rpe_freq); + +-static ssize_t rpa_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t rpa_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + +@@ -132,20 +137,22 @@ static ssize_t rpa_freq_show(struct device *dev, + + return sysfs_emit(buf, "%d\n", freq); + } +-static DEVICE_ATTR_RO(rpa_freq); ++static struct kobj_attribute attr_rpa_freq = __ATTR_RO(rpa_freq); + +-static ssize_t rpn_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t rpn_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + + return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpn_freq(pc)); + } +-static DEVICE_ATTR_RO(rpn_freq); ++static struct kobj_attribute attr_rpn_freq = __ATTR_RO(rpn_freq); + +-static ssize_t min_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t min_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + ssize_t ret; +@@ -159,9 +166,10 @@ static ssize_t min_freq_show(struct device *dev, + return sysfs_emit(buf, "%d\n", freq); + } + +-static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, +- const char *buff, size_t count) ++static ssize_t min_freq_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buff, size_t count) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + ssize_t ret; +@@ -178,11 +186,12 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, + + return count; + } +-static DEVICE_ATTR_RW(min_freq); ++static struct kobj_attribute attr_min_freq = __ATTR_RW(min_freq); + +-static ssize_t max_freq_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t max_freq_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + ssize_t ret; +@@ -196,9 +205,10 @@ static ssize_t max_freq_show(struct device *dev, + return sysfs_emit(buf, "%d\n", freq); + } + +-static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, +- const char *buff, size_t count) ++static ssize_t max_freq_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buff, size_t count) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_guc_pc *pc = dev_to_pc(dev); + u32 freq; + ssize_t ret; +@@ -215,17 +225,17 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, + + return count; + } +-static DEVICE_ATTR_RW(max_freq); ++static struct kobj_attribute attr_max_freq = __ATTR_RW(max_freq); + + static const struct attribute *freq_attrs[] = { +- &dev_attr_act_freq.attr, +- &dev_attr_cur_freq.attr, +- &dev_attr_rp0_freq.attr, +- &dev_attr_rpa_freq.attr, +- &dev_attr_rpe_freq.attr, +- &dev_attr_rpn_freq.attr, +- &dev_attr_min_freq.attr, +- &dev_attr_max_freq.attr, ++ &attr_act_freq.attr, ++ &attr_cur_freq.attr, ++ &attr_rp0_freq.attr, ++ &attr_rpa_freq.attr, ++ &attr_rpe_freq.attr, ++ &attr_rpn_freq.attr, ++ &attr_min_freq.attr, ++ &attr_max_freq.attr, + NULL + }; + +diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c +index fbbace7b0b12a9..c11206410a4d4e 100644 +--- a/drivers/gpu/drm/xe/xe_gt_idle.c ++++ b/drivers/gpu/drm/xe/xe_gt_idle.c +@@ -249,9 +249,10 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p) + return 0; + } + +-static ssize_t name_show(struct device *dev, +- struct device_attribute *attr, char *buff) ++static ssize_t name_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt_idle *gtidle = dev_to_gtidle(dev); + struct xe_guc_pc *pc = gtidle_to_pc(gtidle); + ssize_t ret; +@@ -262,11 +263,12 @@ static ssize_t name_show(struct device *dev, + + return ret; + } +-static DEVICE_ATTR_RO(name); ++static struct kobj_attribute name_attr = __ATTR_RO(name); + +-static ssize_t idle_status_show(struct device *dev, +- struct device_attribute *attr, char *buff) ++static ssize_t idle_status_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt_idle *gtidle = dev_to_gtidle(dev); + struct xe_guc_pc *pc = gtidle_to_pc(gtidle); + enum xe_gt_idle_state state; +@@ -277,6 +279,7 @@ static ssize_t idle_status_show(struct device *dev, + + return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state)); + } ++static struct kobj_attribute idle_status_attr = __ATTR_RO(idle_status); + + u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle) + { +@@ -291,10 +294,11 @@ u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle) + return residency; + } + +-static DEVICE_ATTR_RO(idle_status); +-static ssize_t idle_residency_ms_show(struct device *dev, +- struct device_attribute *attr, char *buff) ++ ++static ssize_t idle_residency_ms_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt_idle *gtidle = dev_to_gtidle(dev); + struct xe_guc_pc *pc = gtidle_to_pc(gtidle); + u64 residency; +@@ -305,12 +309,12 @@ static ssize_t idle_residency_ms_show(struct device *dev, + + return sysfs_emit(buff, "%llu\n", residency); + } +-static DEVICE_ATTR_RO(idle_residency_ms); ++static struct kobj_attribute idle_residency_attr = __ATTR_RO(idle_residency_ms); + + static const struct attribute *gt_idle_attrs[] = { +- &dev_attr_name.attr, +- &dev_attr_idle_status.attr, +- &dev_attr_idle_residency_ms.attr, ++ &name_attr.attr, ++ &idle_status_attr.attr, ++ &idle_residency_attr.attr, + NULL, + }; + +diff --git a/drivers/gpu/drm/xe/xe_gt_throttle.c b/drivers/gpu/drm/xe/xe_gt_throttle.c +index 8db78d616b6f29..aa962c783cdf7a 100644 +--- a/drivers/gpu/drm/xe/xe_gt_throttle.c ++++ b/drivers/gpu/drm/xe/xe_gt_throttle.c +@@ -114,115 +114,115 @@ static u32 read_reason_vr_tdc(struct xe_gt *gt) + return tdc; + } + +-static ssize_t status_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t status_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool status = !!read_status(gt); + + return sysfs_emit(buff, "%u\n", status); + } +-static DEVICE_ATTR_RO(status); ++static struct kobj_attribute attr_status = __ATTR_RO(status); + +-static ssize_t reason_pl1_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_pl1_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool pl1 = !!read_reason_pl1(gt); + + return sysfs_emit(buff, "%u\n", pl1); + } +-static DEVICE_ATTR_RO(reason_pl1); ++static struct kobj_attribute attr_reason_pl1 = __ATTR_RO(reason_pl1); + +-static ssize_t reason_pl2_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_pl2_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool pl2 = !!read_reason_pl2(gt); + + return sysfs_emit(buff, "%u\n", pl2); + } +-static DEVICE_ATTR_RO(reason_pl2); ++static struct kobj_attribute attr_reason_pl2 = __ATTR_RO(reason_pl2); + +-static ssize_t reason_pl4_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_pl4_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool pl4 = !!read_reason_pl4(gt); + + return sysfs_emit(buff, "%u\n", pl4); + } +-static DEVICE_ATTR_RO(reason_pl4); ++static struct kobj_attribute attr_reason_pl4 = __ATTR_RO(reason_pl4); + +-static ssize_t reason_thermal_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_thermal_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool thermal = !!read_reason_thermal(gt); + + return sysfs_emit(buff, "%u\n", thermal); + } +-static DEVICE_ATTR_RO(reason_thermal); ++static struct kobj_attribute attr_reason_thermal = __ATTR_RO(reason_thermal); + +-static ssize_t reason_prochot_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_prochot_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool prochot = !!read_reason_prochot(gt); + + return sysfs_emit(buff, "%u\n", prochot); + } +-static DEVICE_ATTR_RO(reason_prochot); ++static struct kobj_attribute attr_reason_prochot = __ATTR_RO(reason_prochot); + +-static ssize_t reason_ratl_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_ratl_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool ratl = !!read_reason_ratl(gt); + + return sysfs_emit(buff, "%u\n", ratl); + } +-static DEVICE_ATTR_RO(reason_ratl); ++static struct kobj_attribute attr_reason_ratl = __ATTR_RO(reason_ratl); + +-static ssize_t reason_vr_thermalert_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_vr_thermalert_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool thermalert = !!read_reason_vr_thermalert(gt); + + return sysfs_emit(buff, "%u\n", thermalert); + } +-static DEVICE_ATTR_RO(reason_vr_thermalert); ++static struct kobj_attribute attr_reason_vr_thermalert = __ATTR_RO(reason_vr_thermalert); + +-static ssize_t reason_vr_tdc_show(struct device *dev, +- struct device_attribute *attr, +- char *buff) ++static ssize_t reason_vr_tdc_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buff) + { ++ struct device *dev = kobj_to_dev(kobj); + struct xe_gt *gt = dev_to_gt(dev); + bool tdc = !!read_reason_vr_tdc(gt); + + return sysfs_emit(buff, "%u\n", tdc); + } +-static DEVICE_ATTR_RO(reason_vr_tdc); ++static struct kobj_attribute attr_reason_vr_tdc = __ATTR_RO(reason_vr_tdc); + + static struct attribute *throttle_attrs[] = { +- &dev_attr_status.attr, +- &dev_attr_reason_pl1.attr, +- &dev_attr_reason_pl2.attr, +- &dev_attr_reason_pl4.attr, +- &dev_attr_reason_thermal.attr, +- &dev_attr_reason_prochot.attr, +- &dev_attr_reason_ratl.attr, +- &dev_attr_reason_vr_thermalert.attr, +- &dev_attr_reason_vr_tdc.attr, ++ &attr_status.attr, ++ &attr_reason_pl1.attr, ++ &attr_reason_pl2.attr, ++ &attr_reason_pl4.attr, ++ &attr_reason_thermal.attr, ++ &attr_reason_prochot.attr, ++ &attr_reason_ratl.attr, ++ &attr_reason_vr_thermalert.attr, ++ &attr_reason_vr_tdc.attr, + NULL + }; + +diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c +index bc5714a5b36b24..f082be4af4cffe 100644 +--- a/drivers/gpu/drm/xe/xe_guc.c ++++ b/drivers/gpu/drm/xe/xe_guc.c +@@ -1508,30 +1508,32 @@ void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p) + + xe_uc_fw_print(&guc->fw, p); + +- fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); +- if (!fw_ref) +- return; ++ if (!IS_SRIOV_VF(gt_to_xe(gt))) { ++ fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); ++ if (!fw_ref) ++ return; ++ ++ status = xe_mmio_read32(>->mmio, GUC_STATUS); ++ ++ drm_printf(p, "\nGuC status 0x%08x:\n", status); ++ drm_printf(p, "\tBootrom status = 0x%x\n", ++ REG_FIELD_GET(GS_BOOTROM_MASK, status)); ++ drm_printf(p, "\tuKernel status = 0x%x\n", ++ REG_FIELD_GET(GS_UKERNEL_MASK, status)); ++ drm_printf(p, "\tMIA Core status = 0x%x\n", ++ REG_FIELD_GET(GS_MIA_MASK, status)); ++ drm_printf(p, "\tLog level = %d\n", ++ xe_guc_log_get_level(&guc->log)); ++ ++ drm_puts(p, "\nScratch registers:\n"); ++ for (i = 0; i < SOFT_SCRATCH_COUNT; i++) { ++ drm_printf(p, "\t%2d: \t0x%x\n", ++ i, xe_mmio_read32(>->mmio, SOFT_SCRATCH(i))); ++ } + +- status = xe_mmio_read32(>->mmio, GUC_STATUS); +- +- drm_printf(p, "\nGuC status 0x%08x:\n", status); +- drm_printf(p, "\tBootrom status = 0x%x\n", +- REG_FIELD_GET(GS_BOOTROM_MASK, status)); +- drm_printf(p, "\tuKernel status = 0x%x\n", +- REG_FIELD_GET(GS_UKERNEL_MASK, status)); +- drm_printf(p, "\tMIA Core status = 0x%x\n", +- REG_FIELD_GET(GS_MIA_MASK, status)); +- drm_printf(p, "\tLog level = %d\n", +- xe_guc_log_get_level(&guc->log)); +- +- drm_puts(p, "\nScratch registers:\n"); +- for (i = 0; i < SOFT_SCRATCH_COUNT; i++) { +- drm_printf(p, "\t%2d: \t0x%x\n", +- i, xe_mmio_read32(>->mmio, SOFT_SCRATCH(i))); ++ xe_force_wake_put(gt_to_fw(gt), fw_ref); + } + +- xe_force_wake_put(gt_to_fw(gt), fw_ref); +- + drm_puts(p, "\n"); + xe_guc_ct_print(&guc->ct, p, false); + +diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c +index 7ffc98f67e6963..777ec6613abda0 100644 +--- a/drivers/gpu/drm/xe/xe_oa.c ++++ b/drivers/gpu/drm/xe/xe_oa.c +@@ -1301,7 +1301,7 @@ static int xe_oa_user_ext_set_property(struct xe_oa *oa, enum xe_oa_user_extn_fr + int err; + u32 idx; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(oa->xe, err)) + return -EFAULT; + +@@ -1338,7 +1338,7 @@ static int xe_oa_user_extensions(struct xe_oa *oa, enum xe_oa_user_extn_from fro + if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + +- err = __copy_from_user(&ext, address, sizeof(ext)); ++ err = copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(oa->xe, err)) + return -EFAULT; + +@@ -2280,7 +2280,7 @@ int xe_oa_add_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *fi + return -EACCES; + } + +- err = __copy_from_user(¶m, u64_to_user_ptr(data), sizeof(param)); ++ err = copy_from_user(¶m, u64_to_user_ptr(data), sizeof(param)); + if (XE_IOCTL_DBG(oa->xe, err)) + return -EFAULT; + +diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c +index 975094c1a58279..496ca4494beee6 100644 +--- a/drivers/gpu/drm/xe/xe_svm.c ++++ b/drivers/gpu/drm/xe/xe_svm.c +@@ -750,7 +750,7 @@ static bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, + return false; + } + +- if (range_size <= SZ_64K && !supports_4K_migration(vm->xe)) { ++ if (range_size < SZ_64K && !supports_4K_migration(vm->xe)) { + drm_dbg(&vm->xe->drm, "Platform doesn't support SZ_4K range migration\n"); + return false; + } +diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c +index fb0eda3d568290..b553079ae3d647 100644 +--- a/drivers/gpu/drm/xe/xe_uc_fw.c ++++ b/drivers/gpu/drm/xe/xe_uc_fw.c +@@ -222,8 +222,8 @@ uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) + [XE_UC_FW_TYPE_HUC] = { entries_huc, ARRAY_SIZE(entries_huc) }, + [XE_UC_FW_TYPE_GSC] = { entries_gsc, ARRAY_SIZE(entries_gsc) }, + }; +- static const struct uc_fw_entry *entries; + enum xe_platform p = xe->info.platform; ++ const struct uc_fw_entry *entries; + u32 count; + int i; + +diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c +index 737172013a8f9e..cc1ae8ba9bb750 100644 +--- a/drivers/gpu/drm/xe/xe_vm.c ++++ b/drivers/gpu/drm/xe/xe_vm.c +@@ -3087,9 +3087,9 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, + if (!*bind_ops) + return args->num_binds > 1 ? -ENOBUFS : -ENOMEM; + +- err = __copy_from_user(*bind_ops, bind_user, +- sizeof(struct drm_xe_vm_bind_op) * +- args->num_binds); ++ err = copy_from_user(*bind_ops, bind_user, ++ sizeof(struct drm_xe_vm_bind_op) * ++ args->num_binds); + if (XE_IOCTL_DBG(xe, err)) { + err = -EFAULT; + goto free_bind_ops; +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 46e3e42f9eb5fb..599c836507ff88 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); + #define FEATURE_KBD_LED_REPORT_ID1 0x5d + #define FEATURE_KBD_LED_REPORT_ID2 0x5e + ++#define ROG_ALLY_REPORT_SIZE 64 ++#define ROG_ALLY_X_MIN_MCU 313 ++#define ROG_ALLY_MIN_MCU 319 ++ + #define SUPPORT_KBD_BACKLIGHT BIT(0) + + #define MAX_TOUCH_MAJOR 8 +@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); + #define QUIRK_MEDION_E1239T BIT(10) + #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) + #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) ++#define QUIRK_ROG_ALLY_XPAD BIT(13) + + #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ + QUIRK_NO_INIT_REPORTS | \ +@@ -534,9 +539,99 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) + return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT); + } + ++/* ++ * We don't care about any other part of the string except the version section. ++ * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 ++ * The bytes "5a 05 03 31 00 1a 13" and possibly more come before the version ++ * string, and there may be additional bytes after the version string such as ++ * "75 00 74 00 65 00" or a postfix such as "_T01" ++ */ ++static int mcu_parse_version_string(const u8 *response, size_t response_size) ++{ ++ const u8 *end = response + response_size; ++ const u8 *p = response; ++ int dots, err, version; ++ char buf[4]; ++ ++ dots = 0; ++ while (p < end && dots < 2) { ++ if (*p++ == '.') ++ dots++; ++ } ++ ++ if (dots != 2 || p >= end || (p + 3) >= end) ++ return -EINVAL; ++ ++ memcpy(buf, p, 3); ++ buf[3] = '\0'; ++ ++ err = kstrtoint(buf, 10, &version); ++ if (err || version < 0) ++ return -EINVAL; ++ ++ return version; ++} ++ ++static int mcu_request_version(struct hid_device *hdev) ++{ ++ u8 *response __free(kfree) = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; ++ int ret; ++ ++ if (!response) ++ return -ENOMEM; ++ ++ ret = asus_kbd_set_report(hdev, request, sizeof(request)); ++ if (ret < 0) ++ return ret; ++ ++ ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response, ++ ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT, ++ HID_REQ_GET_REPORT); ++ if (ret < 0) ++ return ret; ++ ++ ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) { ++ pr_err("Failed to parse MCU version: %d\n", ret); ++ print_hex_dump(KERN_ERR, "MCU: ", DUMP_PREFIX_NONE, ++ 16, 1, response, ROG_ALLY_REPORT_SIZE, false); ++ } ++ ++ return ret; ++} ++ ++static void validate_mcu_fw_version(struct hid_device *hdev, int idProduct) ++{ ++ int min_version, version; ++ ++ version = mcu_request_version(hdev); ++ if (version < 0) ++ return; ++ ++ switch (idProduct) { ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: ++ min_version = ROG_ALLY_MIN_MCU; ++ break; ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: ++ min_version = ROG_ALLY_X_MIN_MCU; ++ break; ++ default: ++ min_version = 0; ++ } ++ ++ if (version < min_version) { ++ hid_warn(hdev, ++ "The MCU firmware version must be %d or greater to avoid issues with suspend.\n", ++ min_version); ++ } ++} ++ + static int asus_kbd_register_leds(struct hid_device *hdev) + { + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); ++ struct usb_interface *intf; ++ struct usb_device *udev; + unsigned char kbd_func; + int ret; + +@@ -560,6 +655,14 @@ static int asus_kbd_register_leds(struct hid_device *hdev) + if (ret < 0) + return ret; + } ++ ++ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { ++ intf = to_usb_interface(hdev->dev.parent); ++ udev = interface_to_usbdev(intf); ++ validate_mcu_fw_version(hdev, ++ le16_to_cpu(udev->descriptor.idProduct)); ++ } ++ + } else { + /* Initialize keyboard */ + ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); +@@ -1280,10 +1383,10 @@ static const struct hid_device_id asus_devices[] = { + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), +- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, ++ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD}, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), +- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, ++ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), + QUIRK_ROG_CLAYMORE_II_KEYBOARD }, +diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c +index 8351360bba1617..be490c59878524 100644 +--- a/drivers/hv/connection.c ++++ b/drivers/hv/connection.c +@@ -206,11 +206,20 @@ int vmbus_connect(void) + INIT_LIST_HEAD(&vmbus_connection.chn_list); + mutex_init(&vmbus_connection.channel_mutex); + ++ /* ++ * The following Hyper-V interrupt and monitor pages can be used by ++ * UIO for mapping to user-space, so they should always be allocated on ++ * system page boundaries. The system page size must be >= the Hyper-V ++ * page size. ++ */ ++ BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); ++ + /* + * Setup the vmbus event connection for channel interrupt + * abstraction stuff + */ +- vmbus_connection.int_page = hv_alloc_hyperv_zeroed_page(); ++ vmbus_connection.int_page = ++ (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (vmbus_connection.int_page == NULL) { + ret = -ENOMEM; + goto cleanup; +@@ -225,8 +234,8 @@ int vmbus_connect(void) + * Setup the monitor notification facility. The 1st page for + * parent->child and the 2nd page for child->parent + */ +- vmbus_connection.monitor_pages[0] = hv_alloc_hyperv_page(); +- vmbus_connection.monitor_pages[1] = hv_alloc_hyperv_page(); ++ vmbus_connection.monitor_pages[0] = (void *)__get_free_page(GFP_KERNEL); ++ vmbus_connection.monitor_pages[1] = (void *)__get_free_page(GFP_KERNEL); + if ((vmbus_connection.monitor_pages[0] == NULL) || + (vmbus_connection.monitor_pages[1] == NULL)) { + ret = -ENOMEM; +@@ -342,21 +351,23 @@ void vmbus_disconnect(void) + destroy_workqueue(vmbus_connection.work_queue); + + if (vmbus_connection.int_page) { +- hv_free_hyperv_page(vmbus_connection.int_page); ++ free_page((unsigned long)vmbus_connection.int_page); + vmbus_connection.int_page = NULL; + } + + if (vmbus_connection.monitor_pages[0]) { + if (!set_memory_encrypted( + (unsigned long)vmbus_connection.monitor_pages[0], 1)) +- hv_free_hyperv_page(vmbus_connection.monitor_pages[0]); ++ free_page((unsigned long) ++ vmbus_connection.monitor_pages[0]); + vmbus_connection.monitor_pages[0] = NULL; + } + + if (vmbus_connection.monitor_pages[1]) { + if (!set_memory_encrypted( + (unsigned long)vmbus_connection.monitor_pages[1], 1)) +- hv_free_hyperv_page(vmbus_connection.monitor_pages[1]); ++ free_page((unsigned long) ++ vmbus_connection.monitor_pages[1]); + vmbus_connection.monitor_pages[1] = NULL; + } + } +diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c +index a3a07662e49175..8aeec16a7a9054 100644 +--- a/drivers/hwmon/ftsteutates.c ++++ b/drivers/hwmon/ftsteutates.c +@@ -423,13 +423,16 @@ static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + break; + case hwmon_pwm: + switch (attr) { +- case hwmon_pwm_auto_channels_temp: +- if (data->fan_source[channel] == FTS_FAN_SOURCE_INVALID) ++ case hwmon_pwm_auto_channels_temp: { ++ u8 fan_source = data->fan_source[channel]; ++ ++ if (fan_source == FTS_FAN_SOURCE_INVALID || fan_source >= BITS_PER_LONG) + *val = 0; + else +- *val = BIT(data->fan_source[channel]); ++ *val = BIT(fan_source); + + return 0; ++ } + default: + break; + } +diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c +index 7f38d269623965..f607fe8f793702 100644 +--- a/drivers/hwmon/ltc4282.c ++++ b/drivers/hwmon/ltc4282.c +@@ -1511,13 +1511,6 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev) + return ret; + } + +- if (device_property_read_bool(dev, "adi,fault-log-enable")) { +- ret = regmap_set_bits(st->map, LTC4282_ADC_CTRL, +- LTC4282_FAULT_LOG_EN_MASK); +- if (ret) +- return ret; +- } +- + if (device_property_read_bool(dev, "adi,fault-log-enable")) { + ret = regmap_set_bits(st->map, LTC4282_ADC_CTRL, LTC4282_FAULT_LOG_EN_MASK); + if (ret) +diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c +index 9486db249c64fb..b3694a4209b975 100644 +--- a/drivers/hwmon/occ/common.c ++++ b/drivers/hwmon/occ/common.c +@@ -459,12 +459,10 @@ static ssize_t occ_show_power_1(struct device *dev, + return sysfs_emit(buf, "%llu\n", val); + } + +-static u64 occ_get_powr_avg(u64 *accum, u32 *samples) ++static u64 occ_get_powr_avg(u64 accum, u32 samples) + { +- u64 divisor = get_unaligned_be32(samples); +- +- return (divisor == 0) ? 0 : +- div64_u64(get_unaligned_be64(accum) * 1000000ULL, divisor); ++ return (samples == 0) ? 0 : ++ mul_u64_u32_div(accum, 1000000UL, samples); + } + + static ssize_t occ_show_power_2(struct device *dev, +@@ -489,8 +487,8 @@ static ssize_t occ_show_power_2(struct device *dev, + get_unaligned_be32(&power->sensor_id), + power->function_id, power->apss_channel); + case 1: +- val = occ_get_powr_avg(&power->accumulator, +- &power->update_tag); ++ val = occ_get_powr_avg(get_unaligned_be64(&power->accumulator), ++ get_unaligned_be32(&power->update_tag)); + break; + case 2: + val = (u64)get_unaligned_be32(&power->update_tag) * +@@ -527,8 +525,8 @@ static ssize_t occ_show_power_a0(struct device *dev, + return sysfs_emit(buf, "%u_system\n", + get_unaligned_be32(&power->sensor_id)); + case 1: +- val = occ_get_powr_avg(&power->system.accumulator, +- &power->system.update_tag); ++ val = occ_get_powr_avg(get_unaligned_be64(&power->system.accumulator), ++ get_unaligned_be32(&power->system.update_tag)); + break; + case 2: + val = (u64)get_unaligned_be32(&power->system.update_tag) * +@@ -541,8 +539,8 @@ static ssize_t occ_show_power_a0(struct device *dev, + return sysfs_emit(buf, "%u_proc\n", + get_unaligned_be32(&power->sensor_id)); + case 5: +- val = occ_get_powr_avg(&power->proc.accumulator, +- &power->proc.update_tag); ++ val = occ_get_powr_avg(get_unaligned_be64(&power->proc.accumulator), ++ get_unaligned_be32(&power->proc.update_tag)); + break; + case 6: + val = (u64)get_unaligned_be32(&power->proc.update_tag) * +@@ -555,8 +553,8 @@ static ssize_t occ_show_power_a0(struct device *dev, + return sysfs_emit(buf, "%u_vdd\n", + get_unaligned_be32(&power->sensor_id)); + case 9: +- val = occ_get_powr_avg(&power->vdd.accumulator, +- &power->vdd.update_tag); ++ val = occ_get_powr_avg(get_unaligned_be64(&power->vdd.accumulator), ++ get_unaligned_be32(&power->vdd.update_tag)); + break; + case 10: + val = (u64)get_unaligned_be32(&power->vdd.update_tag) * +@@ -569,8 +567,8 @@ static ssize_t occ_show_power_a0(struct device *dev, + return sysfs_emit(buf, "%u_vdn\n", + get_unaligned_be32(&power->sensor_id)); + case 13: +- val = occ_get_powr_avg(&power->vdn.accumulator, +- &power->vdn.update_tag); ++ val = occ_get_powr_avg(get_unaligned_be64(&power->vdn.accumulator), ++ get_unaligned_be32(&power->vdn.update_tag)); + break; + case 14: + val = (u64)get_unaligned_be32(&power->vdn.update_tag) * +@@ -747,29 +745,30 @@ static ssize_t occ_show_extended(struct device *dev, + } + + /* +- * Some helper macros to make it easier to define an occ_attribute. Since these +- * are dynamically allocated, we shouldn't use the existing kernel macros which ++ * A helper to make it easier to define an occ_attribute. Since these ++ * are dynamically allocated, we cannot use the existing kernel macros which + * stringify the name argument. + */ +-#define ATTR_OCC(_name, _mode, _show, _store) { \ +- .attr = { \ +- .name = _name, \ +- .mode = VERIFY_OCTAL_PERMISSIONS(_mode), \ +- }, \ +- .show = _show, \ +- .store = _store, \ +-} +- +-#define SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index) { \ +- .dev_attr = ATTR_OCC(_name, _mode, _show, _store), \ +- .index = _index, \ +- .nr = _nr, \ ++static void occ_init_attribute(struct occ_attribute *attr, int mode, ++ ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf), ++ ssize_t (*store)(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count), ++ int nr, int index, const char *fmt, ...) ++{ ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(attr->name, sizeof(attr->name), fmt, args); ++ va_end(args); ++ ++ attr->sensor.dev_attr.attr.name = attr->name; ++ attr->sensor.dev_attr.attr.mode = mode; ++ attr->sensor.dev_attr.show = show; ++ attr->sensor.dev_attr.store = store; ++ attr->sensor.index = index; ++ attr->sensor.nr = nr; + } + +-#define OCC_INIT_ATTR(_name, _mode, _show, _store, _nr, _index) \ +- ((struct sensor_device_attribute_2) \ +- SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index)) +- + /* + * Allocate and instatiate sensor_device_attribute_2s. It's most efficient to + * use our own instead of the built-in hwmon attribute types. +@@ -855,14 +854,15 @@ static int occ_setup_sensor_attrs(struct occ *occ) + sensors->extended.num_sensors = 0; + } + +- occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * num_attrs, ++ occ->attrs = devm_kcalloc(dev, num_attrs, sizeof(*occ->attrs), + GFP_KERNEL); + if (!occ->attrs) + return -ENOMEM; + + /* null-terminated list */ +- occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) * +- num_attrs + 1, GFP_KERNEL); ++ occ->group.attrs = devm_kcalloc(dev, num_attrs + 1, ++ sizeof(*occ->group.attrs), ++ GFP_KERNEL); + if (!occ->group.attrs) + return -ENOMEM; + +@@ -872,43 +872,33 @@ static int occ_setup_sensor_attrs(struct occ *occ) + s = i + 1; + temp = ((struct temp_sensor_2 *)sensors->temp.data) + i; + +- snprintf(attr->name, sizeof(attr->name), "temp%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL, +- 0, i); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 0, i, "temp%d_label", s); + attr++; + + if (sensors->temp.version == 2 && + temp->fru_type == OCC_FRU_TYPE_VRM) { +- snprintf(attr->name, sizeof(attr->name), +- "temp%d_alarm", s); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 1, i, "temp%d_alarm", s); + } else { +- snprintf(attr->name, sizeof(attr->name), +- "temp%d_input", s); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 1, i, "temp%d_input", s); + } + +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL, +- 1, i); + attr++; + + if (sensors->temp.version > 1) { +- snprintf(attr->name, sizeof(attr->name), +- "temp%d_fru_type", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_temp, NULL, 2, i); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 2, i, "temp%d_fru_type", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "temp%d_fault", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_temp, NULL, 3, i); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 3, i, "temp%d_fault", s); + attr++; + + if (sensors->temp.version == 0x10) { +- snprintf(attr->name, sizeof(attr->name), +- "temp%d_max", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_temp, NULL, +- 4, i); ++ occ_init_attribute(attr, 0444, show_temp, NULL, ++ 4, i, "temp%d_max", s); + attr++; + } + } +@@ -917,14 +907,12 @@ static int occ_setup_sensor_attrs(struct occ *occ) + for (i = 0; i < sensors->freq.num_sensors; ++i) { + s = i + 1; + +- snprintf(attr->name, sizeof(attr->name), "freq%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL, +- 0, i); ++ occ_init_attribute(attr, 0444, show_freq, NULL, ++ 0, i, "freq%d_label", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "freq%d_input", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL, +- 1, i); ++ occ_init_attribute(attr, 0444, show_freq, NULL, ++ 1, i, "freq%d_input", s); + attr++; + } + +@@ -940,32 +928,24 @@ static int occ_setup_sensor_attrs(struct occ *occ) + s = (i * 4) + 1; + + for (j = 0; j < 4; ++j) { +- snprintf(attr->name, sizeof(attr->name), +- "power%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, +- nr++, i); ++ occ_init_attribute(attr, 0444, show_power, ++ NULL, nr++, i, ++ "power%d_label", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_average", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, +- nr++, i); ++ occ_init_attribute(attr, 0444, show_power, ++ NULL, nr++, i, ++ "power%d_average", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_average_interval", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, +- nr++, i); ++ occ_init_attribute(attr, 0444, show_power, ++ NULL, nr++, i, ++ "power%d_average_interval", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_input", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, +- nr++, i); ++ occ_init_attribute(attr, 0444, show_power, ++ NULL, nr++, i, ++ "power%d_input", s); + attr++; + + s++; +@@ -977,28 +957,20 @@ static int occ_setup_sensor_attrs(struct occ *occ) + for (i = 0; i < sensors->power.num_sensors; ++i) { + s = i + 1; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, 0, i); ++ occ_init_attribute(attr, 0444, show_power, NULL, ++ 0, i, "power%d_label", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_average", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, 1, i); ++ occ_init_attribute(attr, 0444, show_power, NULL, ++ 1, i, "power%d_average", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_average_interval", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, 2, i); ++ occ_init_attribute(attr, 0444, show_power, NULL, ++ 2, i, "power%d_average_interval", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_input", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_power, NULL, 3, i); ++ occ_init_attribute(attr, 0444, show_power, NULL, ++ 3, i, "power%d_input", s); + attr++; + } + +@@ -1006,56 +978,43 @@ static int occ_setup_sensor_attrs(struct occ *occ) + } + + if (sensors->caps.num_sensors >= 1) { +- snprintf(attr->name, sizeof(attr->name), "power%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 0, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 0, 0, "power%d_label", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "power%d_cap", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 1, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 1, 0, "power%d_cap", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "power%d_input", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 2, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 2, 0, "power%d_input", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), +- "power%d_cap_not_redundant", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 3, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 3, 0, "power%d_cap_not_redundant", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "power%d_cap_max", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 4, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 4, 0, "power%d_cap_max", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "power%d_cap_min", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL, +- 5, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 5, 0, "power%d_cap_min", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "power%d_cap_user", +- s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0644, show_caps, +- occ_store_caps_user, 6, 0); ++ occ_init_attribute(attr, 0644, show_caps, occ_store_caps_user, ++ 6, 0, "power%d_cap_user", s); + attr++; + + if (sensors->caps.version > 1) { +- snprintf(attr->name, sizeof(attr->name), +- "power%d_cap_user_source", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_caps, NULL, 7, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 7, 0, "power%d_cap_user_source", s); + attr++; + + if (sensors->caps.version > 2) { +- snprintf(attr->name, sizeof(attr->name), +- "power%d_cap_min_soft", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- show_caps, NULL, +- 8, 0); ++ occ_init_attribute(attr, 0444, show_caps, NULL, ++ 8, 0, ++ "power%d_cap_min_soft", s); + attr++; + } + } +@@ -1064,19 +1023,16 @@ static int occ_setup_sensor_attrs(struct occ *occ) + for (i = 0; i < sensors->extended.num_sensors; ++i) { + s = i + 1; + +- snprintf(attr->name, sizeof(attr->name), "extn%d_label", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- occ_show_extended, NULL, 0, i); ++ occ_init_attribute(attr, 0444, occ_show_extended, NULL, ++ 0, i, "extn%d_label", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "extn%d_flags", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- occ_show_extended, NULL, 1, i); ++ occ_init_attribute(attr, 0444, occ_show_extended, NULL, ++ 1, i, "extn%d_flags", s); + attr++; + +- snprintf(attr->name, sizeof(attr->name), "extn%d_input", s); +- attr->sensor = OCC_INIT_ATTR(attr->name, 0444, +- occ_show_extended, NULL, 2, i); ++ occ_init_attribute(attr, 0444, occ_show_extended, NULL, ++ 2, i, "extn%d_input", s); + attr++; + } + +diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c +index 5cd4a5f7a472e4..b936a240db0a93 100644 +--- a/drivers/i2c/busses/i2c-designware-slave.c ++++ b/drivers/i2c/busses/i2c-designware-slave.c +@@ -96,7 +96,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) + i2c_dw_disable(dev); + synchronize_irq(dev->irq); + dev->slave = NULL; +- pm_runtime_put(dev->dev); ++ pm_runtime_put_sync_suspend(dev->dev); + + return 0; + } +diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c +index 5965b4cf6220e4..b68a21fff0b56b 100644 +--- a/drivers/i2c/busses/i2c-k1.c ++++ b/drivers/i2c/busses/i2c-k1.c +@@ -477,7 +477,7 @@ static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, in + + ret = spacemit_i2c_wait_bus_idle(i2c); + if (!ret) +- spacemit_i2c_xfer_msg(i2c); ++ ret = spacemit_i2c_xfer_msg(i2c); + else if (ret < 0) + dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret); + else +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index de713b5747fe5c..05a140ec2b64d8 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -2178,10 +2178,14 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, + + /* Check HW is OK: SDA and SCL should be high at this point. */ + if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) { +- dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num); +- dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap), +- npcm_i2c_get_SCL(&bus->adap)); +- return -ENXIO; ++ dev_warn(bus->dev, " I2C%d SDA=%d SCL=%d, attempting to recover\n", bus->num, ++ npcm_i2c_get_SDA(&bus->adap), npcm_i2c_get_SCL(&bus->adap)); ++ if (npcm_i2c_recovery_tgclk(&bus->adap)) { ++ dev_err(bus->dev, "I2C%d init fail: SDA=%d SCL=%d\n", ++ bus->num, npcm_i2c_get_SDA(&bus->adap), ++ npcm_i2c_get_SCL(&bus->adap)); ++ return -ENXIO; ++ } + } + + npcm_i2c_int_enable(bus, true); +diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c +index bd128ab2e2ebb6..27ab09854c9275 100644 +--- a/drivers/i2c/busses/i2c-pasemi-core.c ++++ b/drivers/i2c/busses/i2c-pasemi-core.c +@@ -71,7 +71,7 @@ static inline int reg_read(struct pasemi_smbus *smbus, int reg) + + static void pasemi_reset(struct pasemi_smbus *smbus) + { +- u32 val = (CTL_MTR | CTL_MRR | (smbus->clk_div & CTL_CLK_M)); ++ u32 val = (CTL_MTR | CTL_MRR | CTL_UJM | (smbus->clk_div & CTL_CLK_M)); + + if (smbus->hw_rev >= 6) + val |= CTL_EN; +diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c +index 87976e99e6d001..049b4d154c2337 100644 +--- a/drivers/i2c/busses/i2c-tegra.c ++++ b/drivers/i2c/busses/i2c-tegra.c +@@ -1395,6 +1395,11 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE); + if (ret) + break; ++ ++ /* Validate message length before proceeding */ ++ if (msgs[i].buf[0] == 0 || msgs[i].buf[0] > I2C_SMBUS_BLOCK_MAX) ++ break; ++ + /* Set the msg length from first byte */ + msgs[i].len += msgs[i].buf[0]; + dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len); +diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c +index a71226d7ca5932..5834bf8a3fd9e9 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/core.c ++++ b/drivers/i3c/master/mipi-i3c-hci/core.c +@@ -594,6 +594,7 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) + + if (val) { + reg_write(INTR_STATUS, val); ++ result = IRQ_HANDLED; + } + + if (val & INTR_HC_RESET_CANCEL) { +@@ -605,12 +606,11 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) + val &= ~INTR_HC_INTERNAL_ERR; + } + +- hci->io->irq_handler(hci); ++ if (hci->io->irq_handler(hci)) ++ result = IRQ_HANDLED; + + if (val) + dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val); +- else +- result = IRQ_HANDLED; + + return result; + } +diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c +index bf1d3923a18179..ae965a8f560d3b 100644 +--- a/drivers/iio/accel/fxls8962af-core.c ++++ b/drivers/iio/accel/fxls8962af-core.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -439,8 +440,16 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev, + *val = FXLS8962AF_TEMP_CENTER_VAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: +- *val = 0; +- return fxls8962af_read_full_scale(data, val2); ++ switch (chan->type) { ++ case IIO_TEMP: ++ *val = MILLIDEGREE_PER_DEGREE; ++ return IIO_VAL_INT; ++ case IIO_ACCEL: ++ *val = 0; ++ return fxls8962af_read_full_scale(data, val2); ++ default: ++ return -EINVAL; ++ } + case IIO_CHAN_INFO_SAMP_FREQ: + return fxls8962af_read_samp_freq(data, val, val2); + default: +@@ -736,9 +745,11 @@ static const struct iio_event_spec fxls8962af_event[] = { + .type = IIO_TEMP, \ + .address = FXLS8962AF_TEMP_OUT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET),\ + .scan_index = -1, \ + .scan_type = { \ ++ .sign = 's', \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ +diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig +index 6529df1a498c2c..b7aac84e5224af 100644 +--- a/drivers/iio/adc/Kconfig ++++ b/drivers/iio/adc/Kconfig +@@ -129,8 +129,9 @@ config AD7173 + tristate "Analog Devices AD7173 driver" + depends on SPI_MASTER + select AD_SIGMA_DELTA +- select GPIO_REGMAP if GPIOLIB +- select REGMAP_SPI if GPIOLIB ++ select GPIOLIB ++ select GPIO_REGMAP ++ select REGMAP_SPI + help + Say yes here to build support for Analog Devices AD7173 and similar ADC + Currently supported models: +@@ -1546,6 +1547,7 @@ config TI_ADS1298 + tristate "Texas Instruments ADS1298" + depends on SPI + select IIO_BUFFER ++ select IIO_KFIFO_BUF + help + If you say yes here you get support for Texas Instruments ADS1298 + medical ADC chips +diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c +index 69de5886474ce2..b3e6bd2a55d717 100644 +--- a/drivers/iio/adc/ad7173.c ++++ b/drivers/iio/adc/ad7173.c +@@ -230,10 +230,8 @@ struct ad7173_state { + unsigned long long *config_cnts; + struct clk *ext_clk; + struct clk_hw int_clk_hw; +-#if IS_ENABLED(CONFIG_GPIOLIB) + struct regmap *reg_gpiocon_regmap; + struct gpio_regmap *gpio_regmap; +-#endif + }; + + static unsigned int ad4115_sinc5_data_rates[] = { +@@ -288,8 +286,6 @@ static const char *const ad7173_clk_sel[] = { + "ext-clk", "xtal" + }; + +-#if IS_ENABLED(CONFIG_GPIOLIB) +- + static const struct regmap_range ad7173_range_gpio[] = { + regmap_reg_range(AD7173_REG_GPIO, AD7173_REG_GPIO), + }; +@@ -543,12 +539,6 @@ static int ad7173_gpio_init(struct ad7173_state *st) + + return 0; + } +-#else +-static int ad7173_gpio_init(struct ad7173_state *st) +-{ +- return 0; +-} +-#endif /* CONFIG_GPIOLIB */ + + static struct ad7173_state *ad_sigma_delta_to_ad7173(struct ad_sigma_delta *sd) + { +@@ -1797,10 +1787,7 @@ static int ad7173_probe(struct spi_device *spi) + if (ret) + return ret; + +- if (IS_ENABLED(CONFIG_GPIOLIB)) +- return ad7173_gpio_init(st); +- +- return 0; ++ return ad7173_gpio_init(st); + } + + static const struct of_device_id ad7173_of_match[] = { +diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c +index 703556eb7257ea..8ed65a35b48623 100644 +--- a/drivers/iio/adc/ad7606.c ++++ b/drivers/iio/adc/ad7606.c +@@ -727,17 +727,16 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, + goto error_ret; + + chan = &indio_dev->channels[ch + 1]; +- if (chan->scan_type.sign == 'u') { +- if (realbits > 16) +- *val = st->data.buf32[ch]; +- else +- *val = st->data.buf16[ch]; +- } else { +- if (realbits > 16) +- *val = sign_extend32(st->data.buf32[ch], realbits - 1); +- else +- *val = sign_extend32(st->data.buf16[ch], realbits - 1); +- } ++ ++ if (realbits > 16) ++ *val = st->data.buf32[ch]; ++ else ++ *val = st->data.buf16[ch]; ++ ++ *val &= GENMASK(realbits - 1, 0); ++ ++ if (chan->scan_type.sign == 's') ++ *val = sign_extend32(*val, realbits - 1); + + error_ret: + if (!st->gpio_convst) { +diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c +index 179115e909888b..b37458ce3c7087 100644 +--- a/drivers/iio/adc/ad7606_spi.c ++++ b/drivers/iio/adc/ad7606_spi.c +@@ -155,7 +155,7 @@ static int ad7606_spi_reg_write(struct ad7606_state *st, + struct spi_device *spi = to_spi_device(st->dev); + + st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) | +- (val & 0x1FF)); ++ (val & 0xFF)); + + return spi_write(spi, &st->d16[0], sizeof(st->d16[0])); + } +diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c +index 2f949fe5587318..37a137bd83571b 100644 +--- a/drivers/iio/adc/ad7944.c ++++ b/drivers/iio/adc/ad7944.c +@@ -377,6 +377,8 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, + + if (chan->scan_type.sign == 's') + *val = sign_extend32(*val, chan->scan_type.realbits - 1); ++ else ++ *val &= GENMASK(chan->scan_type.realbits - 1, 0); + + return IIO_VAL_INT; + } +diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +index 213cce1c31110e..91f0f381082bda 100644 +--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c ++++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +@@ -67,16 +67,18 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev, + return IIO_VAL_INT; + /* + * T°C = (temp / 132.48) + 25 +- * Tm°C = 1000 * ((temp * 100 / 13248) + 25) ++ * Tm°C = 1000 * ((temp / 132.48) + 25) ++ * Tm°C = 7.548309 * temp + 25000 ++ * Tm°C = (temp + 3312) * 7.548309 + * scale: 100000 / 13248 ~= 7.548309 +- * offset: 25000 ++ * offset: 3312 + */ + case IIO_CHAN_INFO_SCALE: + *val = 7; + *val2 = 548309; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: +- *val = 25000; ++ *val = 3312; + return IIO_VAL_INT; + default: + return -EINVAL; +diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c +index f4486cbd8f45a9..62410578dec37d 100644 +--- a/drivers/infiniband/core/iwcm.c ++++ b/drivers/infiniband/core/iwcm.c +@@ -368,12 +368,9 @@ EXPORT_SYMBOL(iw_cm_disconnect); + /* + * CM_ID <-- DESTROYING + * +- * Clean up all resources associated with the connection and release +- * the initial reference taken by iw_create_cm_id. +- * +- * Returns true if and only if the last cm_id_priv reference has been dropped. ++ * Clean up all resources associated with the connection. + */ +-static bool destroy_cm_id(struct iw_cm_id *cm_id) ++static void destroy_cm_id(struct iw_cm_id *cm_id) + { + struct iwcm_id_private *cm_id_priv; + struct ib_qp *qp; +@@ -442,20 +439,22 @@ static bool destroy_cm_id(struct iw_cm_id *cm_id) + iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr); + iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM); + } +- +- return iwcm_deref_id(cm_id_priv); + } + + /* +- * This function is only called by the application thread and cannot +- * be called by the event thread. The function will wait for all +- * references to be released on the cm_id and then kfree the cm_id +- * object. ++ * Destroy cm_id. If the cm_id still has other references, wait for all ++ * references to be released on the cm_id and then release the initial ++ * reference taken by iw_create_cm_id. + */ + void iw_destroy_cm_id(struct iw_cm_id *cm_id) + { +- if (!destroy_cm_id(cm_id)) ++ struct iwcm_id_private *cm_id_priv; ++ ++ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); ++ destroy_cm_id(cm_id); ++ if (refcount_read(&cm_id_priv->refcount) > 1) + flush_workqueue(iwcm_wq); ++ iwcm_deref_id(cm_id_priv); + } + EXPORT_SYMBOL(iw_destroy_cm_id); + +@@ -1035,8 +1034,10 @@ static void cm_work_handler(struct work_struct *_work) + + if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) { + ret = process_event(cm_id_priv, &levent); +- if (ret) +- WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id)); ++ if (ret) { ++ destroy_cm_id(&cm_id_priv->id); ++ WARN_ON_ONCE(iwcm_deref_id(cm_id_priv)); ++ } + } else + pr_debug("dropping event %d\n", levent.event); + if (iwcm_deref_id(cm_id_priv)) +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 59352d1b62099f..bbf6e1983704cf 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -942,7 +942,7 @@ static void fill_wqe_idx(struct hns_roce_srq *srq, unsigned int wqe_idx) + static void update_srq_db(struct hns_roce_srq *srq) + { + struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device); +- struct hns_roce_v2_db db; ++ struct hns_roce_v2_db db = {}; + + hr_reg_write(&db, DB_TAG, srq->srqn); + hr_reg_write(&db, DB_CMD, HNS_ROCE_V2_SRQ_DB); +diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c +index 5c39a217b94c8a..f9db86da0818b2 100644 +--- a/drivers/input/keyboard/gpio_keys.c ++++ b/drivers/input/keyboard/gpio_keys.c +@@ -449,6 +449,8 @@ static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t) + release_timer); + struct input_dev *input = bdata->input; + ++ guard(spinlock_irqsave)(&bdata->lock); ++ + if (bdata->key_pressed) { + input_report_key(input, *bdata->code, 0); + input_sync(input); +@@ -486,7 +488,7 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) + if (bdata->release_delay) + hrtimer_start(&bdata->release_timer, + ms_to_ktime(bdata->release_delay), +- HRTIMER_MODE_REL_HARD); ++ HRTIMER_MODE_REL); + out: + return IRQ_HANDLED; + } +@@ -628,7 +630,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, + + bdata->release_delay = button->debounce_interval; + hrtimer_setup(&bdata->release_timer, gpio_keys_irq_timer, +- CLOCK_REALTIME, HRTIMER_MODE_REL_HARD); ++ CLOCK_REALTIME, HRTIMER_MODE_REL); + + isr = gpio_keys_irq_isr; + irqflags = 0; +diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c +index d9ee14b1f45184..4581f1c536442b 100644 +--- a/drivers/input/misc/ims-pcu.c ++++ b/drivers/input/misc/ims-pcu.c +@@ -844,6 +844,12 @@ static int ims_pcu_flash_firmware(struct ims_pcu *pcu, + addr = be32_to_cpu(rec->addr) / 2; + len = be16_to_cpu(rec->len); + ++ if (len > sizeof(pcu->cmd_buf) - 1 - sizeof(*fragment)) { ++ dev_err(pcu->dev, ++ "Invalid record length in firmware: %d\n", len); ++ return -EINVAL; ++ } ++ + fragment = (void *)&pcu->cmd_buf[1]; + put_unaligned_le32(addr, &fragment->addr); + fragment->len = len; +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index f34209b08b4c54..31f8d208dedb7a 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -241,7 +241,9 @@ static inline int get_acpihid_device_id(struct device *dev, + struct acpihid_map_entry **entry) + { + struct acpi_device *adev = ACPI_COMPANION(dev); +- struct acpihid_map_entry *p; ++ struct acpihid_map_entry *p, *p1 = NULL; ++ int hid_count = 0; ++ bool fw_bug; + + if (!adev) + return -ENODEV; +@@ -249,12 +251,33 @@ static inline int get_acpihid_device_id(struct device *dev, + list_for_each_entry(p, &acpihid_map, list) { + if (acpi_dev_hid_uid_match(adev, p->hid, + p->uid[0] ? p->uid : NULL)) { +- if (entry) +- *entry = p; +- return p->devid; ++ p1 = p; ++ fw_bug = false; ++ hid_count = 1; ++ break; ++ } ++ ++ /* ++ * Count HID matches w/o UID, raise FW_BUG but allow exactly one match ++ */ ++ if (acpi_dev_hid_match(adev, p->hid)) { ++ p1 = p; ++ hid_count++; ++ fw_bug = true; + } + } +- return -EINVAL; ++ ++ if (!p1) ++ return -EINVAL; ++ if (fw_bug) ++ dev_err_once(dev, FW_BUG "No ACPI device matched UID, but %d device%s matched HID.\n", ++ hid_count, hid_count > 1 ? "s" : ""); ++ if (hid_count > 1) ++ return -EINVAL; ++ if (entry) ++ *entry = p1; ++ ++ return p1->devid; + } + + static inline int get_device_sbdf_id(struct device *dev) +@@ -982,6 +1005,14 @@ int amd_iommu_register_ga_log_notifier(int (*notifier)(u32)) + { + iommu_ga_log_notifier = notifier; + ++ /* ++ * Ensure all in-flight IRQ handlers run to completion before returning ++ * to the caller, e.g. to ensure module code isn't unloaded while it's ++ * being executed in the IRQ handler. ++ */ ++ if (!notifier) ++ synchronize_rcu(); ++ + return 0; + } + EXPORT_SYMBOL(amd_iommu_register_ga_log_notifier); +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index cb0b993bebb4dd..9d2d34c1b2ff8f 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1859,6 +1859,7 @@ static int dmar_domain_attach_device(struct dmar_domain *domain, + return ret; + + info->domain = domain; ++ info->domain_attached = true; + spin_lock_irqsave(&domain->lock, flags); + list_add(&info->link, &domain->devices); + spin_unlock_irqrestore(&domain->lock, flags); +@@ -3257,6 +3258,10 @@ void device_block_translation(struct device *dev) + struct intel_iommu *iommu = info->iommu; + unsigned long flags; + ++ /* Device in DMA blocking state. Noting to do. */ ++ if (!info->domain_attached) ++ return; ++ + if (info->domain) + cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID); + +@@ -3268,6 +3273,9 @@ void device_block_translation(struct device *dev) + domain_context_clear(info); + } + ++ /* Device now in DMA blocking state. */ ++ info->domain_attached = false; ++ + if (!info->domain) + return; + +@@ -4357,6 +4365,9 @@ static int identity_domain_attach_dev(struct iommu_domain *domain, struct device + else + ret = device_setup_pass_through(dev); + ++ if (!ret) ++ info->domain_attached = true; ++ + return ret; + } + +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index c4916886da5a08..8661e0864701ce 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -773,6 +773,7 @@ struct device_domain_info { + u8 ats_supported:1; + u8 ats_enabled:1; + u8 dtlb_extra_inval:1; /* Quirk for devices need extra flush */ ++ u8 domain_attached:1; /* Device has domain attached */ + u8 ats_qdep; + unsigned int iopf_refcount; + struct device *dev; /* it's NULL for PCIe-to-PCI bridge */ +diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c +index 6ac5c534bef437..1e149169ee77b0 100644 +--- a/drivers/iommu/intel/nested.c ++++ b/drivers/iommu/intel/nested.c +@@ -27,8 +27,7 @@ static int intel_nested_attach_dev(struct iommu_domain *domain, + unsigned long flags; + int ret = 0; + +- if (info->domain) +- device_block_translation(dev); ++ device_block_translation(dev); + + if (iommu->agaw < dmar_domain->s2_domain->agaw) { + dev_err_ratelimited(dev, "Adjusted guest address width not compatible\n"); +@@ -62,6 +61,7 @@ static int intel_nested_attach_dev(struct iommu_domain *domain, + goto unassign_tag; + + info->domain = dmar_domain; ++ info->domain_attached = true; + spin_lock_irqsave(&dmar_domain->lock, flags); + list_add(&info->link, &dmar_domain->devices); + spin_unlock_irqrestore(&dmar_domain->lock, flags); +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index e4628d96216102..df871a500b283e 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2208,6 +2208,19 @@ static void *iommu_make_pasid_array_entry(struct iommu_domain *domain, + return xa_tag_pointer(domain, IOMMU_PASID_ARRAY_DOMAIN); + } + ++static bool domain_iommu_ops_compatible(const struct iommu_ops *ops, ++ struct iommu_domain *domain) ++{ ++ if (domain->owner == ops) ++ return true; ++ ++ /* For static domains, owner isn't set. */ ++ if (domain == ops->blocked_domain || domain == ops->identity_domain) ++ return true; ++ ++ return false; ++} ++ + static int __iommu_attach_group(struct iommu_domain *domain, + struct iommu_group *group) + { +@@ -2218,7 +2231,8 @@ static int __iommu_attach_group(struct iommu_domain *domain, + return -EBUSY; + + dev = iommu_group_first_dev(group); +- if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner) ++ if (!dev_has_iommu(dev) || ++ !domain_iommu_ops_compatible(dev_iommu_ops(dev), domain)) + return -EINVAL; + + return __iommu_group_set_domain(group, domain); +@@ -3456,7 +3470,8 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, + !ops->blocked_domain->ops->set_dev_pasid) + return -EOPNOTSUPP; + +- if (ops != domain->owner || pasid == IOMMU_NO_PASID) ++ if (!domain_iommu_ops_compatible(ops, domain) || ++ pasid == IOMMU_NO_PASID) + return -EINVAL; + + mutex_lock(&group->mutex); +@@ -3538,7 +3553,7 @@ int iommu_replace_device_pasid(struct iommu_domain *domain, + if (!domain->ops->set_dev_pasid) + return -EOPNOTSUPP; + +- if (dev_iommu_ops(dev) != domain->owner || ++ if (!domain_iommu_ops_compatible(dev_iommu_ops(dev), domain) || + pasid == IOMMU_NO_PASID || !handle) + return -EINVAL; + +diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c +index 9e615b4f1f5e66..785af481658406 100644 +--- a/drivers/md/dm-raid1.c ++++ b/drivers/md/dm-raid1.c +@@ -133,10 +133,9 @@ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw) + spin_lock_irqsave(&ms->lock, flags); + should_wake = !(bl->head); + bio_list_add(bl, bio); +- spin_unlock_irqrestore(&ms->lock, flags); +- + if (should_wake) + wakeup_mirrord(ms); ++ spin_unlock_irqrestore(&ms->lock, flags); + } + + static void dispatch_bios(void *context, struct bio_list *bio_list) +@@ -646,9 +645,9 @@ static void write_callback(unsigned long error, void *context) + if (!ms->failures.head) + should_wake = 1; + bio_list_add(&ms->failures, bio); +- spin_unlock_irqrestore(&ms->lock, flags); + if (should_wake) + wakeup_mirrord(ms); ++ spin_unlock_irqrestore(&ms->lock, flags); + } + + static void do_write(struct mirror_set *ms, struct bio *bio) +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index e009bba52d4c0c..dd074c8ecbbad0 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -431,6 +431,13 @@ static int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, + return 0; + } + ++ mutex_lock(&q->limits_lock); ++ /* ++ * BLK_FEAT_ATOMIC_WRITES is not inherited from the bottom device in ++ * blk_stack_limits(), so do it manually. ++ */ ++ limits->features |= (q->limits.features & BLK_FEAT_ATOMIC_WRITES); ++ + if (blk_stack_limits(limits, &q->limits, + get_start_sect(bdev) + start) < 0) + DMWARN("%s: adding target device %pg caused an alignment inconsistency: " +@@ -448,6 +455,7 @@ static int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, + */ + if (!dm_target_has_integrity(ti->type)) + queue_limits_stack_integrity_bdev(limits, bdev); ++ mutex_unlock(&q->limits_lock); + return 0; + } + +@@ -1733,8 +1741,12 @@ static int device_not_write_zeroes_capable(struct dm_target *ti, struct dm_dev * + sector_t start, sector_t len, void *data) + { + struct request_queue *q = bdev_get_queue(dev->bdev); ++ int b; + +- return !q->limits.max_write_zeroes_sectors; ++ mutex_lock(&q->limits_lock); ++ b = !q->limits.max_write_zeroes_sectors; ++ mutex_unlock(&q->limits_lock); ++ return b; + } + + static bool dm_table_supports_write_zeroes(struct dm_table *t) +diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c +index 0c41949db784ba..631a887b487cc4 100644 +--- a/drivers/md/dm-verity-fec.c ++++ b/drivers/md/dm-verity-fec.c +@@ -593,6 +593,10 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, + (*argc)--; + + if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) { ++ if (v->fec->dev) { ++ ti->error = "FEC device already specified"; ++ return -EINVAL; ++ } + r = dm_get_device(ti, arg_value, BLK_OPEN_READ, &v->fec->dev); + if (r) { + ti->error = "FEC device lookup failed"; +diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c +index 3c427f18a04b33..ed49bcbd224fa2 100644 +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -1120,6 +1120,9 @@ static int verity_alloc_most_once(struct dm_verity *v) + { + struct dm_target *ti = v->ti; + ++ if (v->validated_blocks) ++ return 0; ++ + /* the bitset can only handle INT_MAX blocks */ + if (v->data_blocks > INT_MAX) { + ti->error = "device too large to use check_at_most_once"; +@@ -1143,6 +1146,9 @@ static int verity_alloc_zero_digest(struct dm_verity *v) + struct dm_verity_io *io; + u8 *zero_data; + ++ if (v->zero_digest) ++ return 0; ++ + v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL); + + if (!v->zero_digest) +@@ -1577,7 +1583,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv) + goto bad; + } + +- /* Root hash signature is a optional parameter*/ ++ /* Root hash signature is an optional parameter */ + r = verity_verify_root_hash(root_hash_digest_to_validate, + strlen(root_hash_digest_to_validate), + verify_args.sig, +diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c +index a9e2c6c0a33c6d..d5261a0e4232e1 100644 +--- a/drivers/md/dm-verity-verify-sig.c ++++ b/drivers/md/dm-verity-verify-sig.c +@@ -71,9 +71,14 @@ int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, + const char *arg_name) + { + struct dm_target *ti = v->ti; +- int ret = 0; ++ int ret; + const char *sig_key = NULL; + ++ if (v->signature_key_desc) { ++ ti->error = DM_VERITY_VERIFY_ERR("root_hash_sig_key_desc already specified"); ++ return -EINVAL; ++ } ++ + if (!*argc) { + ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); + return -EINVAL; +@@ -83,14 +88,18 @@ int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, + (*argc)--; + + ret = verity_verify_get_sig_from_key(sig_key, sig_opts); +- if (ret < 0) ++ if (ret < 0) { + ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); ++ return ret; ++ } + + v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); +- if (!v->signature_key_desc) ++ if (!v->signature_key_desc) { ++ ti->error = DM_VERITY_VERIFY_ERR("Could not allocate memory for signature key"); + return -ENOMEM; ++ } + +- return ret; ++ return 0; + } + + /* +diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +index cfbfc4c1b2e67f..41d019b01ec09d 100644 +--- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c ++++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +@@ -1002,8 +1002,8 @@ static int extron_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) + { + struct extron_port *port = cec_get_drvdata(adap); +- char buf[CEC_MAX_MSG_SIZE * 3 + 1]; +- char cmd[CEC_MAX_MSG_SIZE * 3 + 13]; ++ char buf[(CEC_MAX_MSG_SIZE - 1) * 3 + 1]; ++ char cmd[sizeof(buf) + 14]; + unsigned int i; + + if (port->disconnected) +diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c +index c6ddf2357c58c1..b3bf2173c14e1b 100644 +--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c ++++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c +@@ -469,7 +469,7 @@ vb2_dma_sg_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf, + struct vb2_dma_sg_buf *buf = dbuf->priv; + struct sg_table *sgt = buf->dma_sgt; + +- dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); ++ dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir); + return 0; + } + +@@ -480,7 +480,7 @@ vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, + struct vb2_dma_sg_buf *buf = dbuf->priv; + struct sg_table *sgt = buf->dma_sgt; + +- dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); ++ dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir); + return 0; + } + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index 34ccda66652458..2051f1f292294a 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -312,6 +312,11 @@ __ccs_pll_calculate_vt_tree(struct device *dev, + dev_dbg(dev, "more_mul2: %u\n", more_mul); + + pll_fr->pll_multiplier = mul * more_mul; ++ if (pll_fr->pll_multiplier > lim_fr->max_pll_multiplier) { ++ dev_dbg(dev, "pll multiplier %u too high\n", ++ pll_fr->pll_multiplier); ++ return -EINVAL; ++ } + + if (pll_fr->pll_multiplier * pll_fr->pll_ip_clk_freq_hz > + lim_fr->max_pll_op_clk_freq_hz) +@@ -397,6 +402,8 @@ static int ccs_pll_calculate_vt_tree(struct device *dev, + min_pre_pll_clk_div = max_t(u16, min_pre_pll_clk_div, + pll->ext_clk_freq_hz / + lim_fr->max_pll_ip_clk_freq_hz); ++ if (!(pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER)) ++ min_pre_pll_clk_div = clk_div_even(min_pre_pll_clk_div); + + dev_dbg(dev, "vt min/max_pre_pll_clk_div: %u,%u\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); +@@ -435,7 +442,7 @@ static int ccs_pll_calculate_vt_tree(struct device *dev, + return -EINVAL; + } + +-static void ++static int + ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr, +@@ -558,6 +565,8 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, + if (best_pix_div < SHRT_MAX >> 1) + break; + } ++ if (best_pix_div == SHRT_MAX >> 1) ++ return -EINVAL; + + pll->vt_bk.sys_clk_div = DIV_ROUND_UP(vt_div, best_pix_div); + pll->vt_bk.pix_clk_div = best_pix_div; +@@ -570,6 +579,8 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, + out_calc_pixel_rate: + pll->pixel_rate_pixel_array = + pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes; ++ ++ return 0; + } + + /* +@@ -792,7 +803,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pre_pll_clk_div, op_lim_fr->max_pre_pll_clk_div); + max_op_pre_pll_clk_div = + min_t(u16, op_lim_fr->max_pre_pll_clk_div, +- clk_div_even(pll->ext_clk_freq_hz / ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +@@ -815,6 +826,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + one_or_more( + DIV_ROUND_UP(op_lim_fr->max_pll_op_clk_freq_hz, + pll->ext_clk_freq_hz)))); ++ if (!(pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER)) ++ min_op_pre_pll_clk_div = clk_div_even(min_op_pre_pll_clk_div); + dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +@@ -843,8 +856,10 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) + break; + +- ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, +- op_pll_bk, cphy, phy_const); ++ rval = ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, ++ op_pll_bk, cphy, phy_const); ++ if (rval) ++ continue; + + rval = check_bk_bounds(dev, lim, pll, PLL_VT); + if (rval) +diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c +index fd2d2d5272bfb6..1445ebbcc9cabb 100644 +--- a/drivers/media/i2c/ds90ub913.c ++++ b/drivers/media/i2c/ds90ub913.c +@@ -450,10 +450,10 @@ static int ub913_set_fmt(struct v4l2_subdev *sd, + if (!fmt) + return -EINVAL; + +- format->format.code = finfo->outcode; +- + *fmt = format->format; + ++ fmt->code = finfo->outcode; ++ + return 0; + } + +diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c +index a544fc3df39c28..b47cb3b8f36897 100644 +--- a/drivers/media/i2c/imx334.c ++++ b/drivers/media/i2c/imx334.c +@@ -352,6 +352,12 @@ static const struct imx334_reg mode_3840x2160_regs[] = { + {0x302d, 0x00}, + {0x302e, 0x00}, + {0x302f, 0x0f}, ++ {0x3074, 0xb0}, ++ {0x3075, 0x00}, ++ {0x308e, 0xb1}, ++ {0x308f, 0x00}, ++ {0x30d8, 0x20}, ++ {0x30d9, 0x12}, + {0x3076, 0x70}, + {0x3077, 0x08}, + {0x3090, 0x70}, +@@ -1391,6 +1397,9 @@ static int imx334_probe(struct i2c_client *client) + goto error_handler_free; + } + ++ pm_runtime_set_active(imx334->dev); ++ pm_runtime_enable(imx334->dev); ++ + ret = v4l2_async_register_subdev_sensor(&imx334->sd); + if (ret < 0) { + dev_err(imx334->dev, +@@ -1398,13 +1407,13 @@ static int imx334_probe(struct i2c_client *client) + goto error_media_entity; + } + +- pm_runtime_set_active(imx334->dev); +- pm_runtime_enable(imx334->dev); + pm_runtime_idle(imx334->dev); + + return 0; + + error_media_entity: ++ pm_runtime_disable(imx334->dev); ++ pm_runtime_set_suspended(imx334->dev); + media_entity_cleanup(&imx334->sd.entity); + error_handler_free: + v4l2_ctrl_handler_free(imx334->sd.ctrl_handler); +@@ -1432,7 +1441,10 @@ static void imx334_remove(struct i2c_client *client) + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); +- pm_runtime_suspended(&client->dev); ++ if (!pm_runtime_status_suspended(&client->dev)) { ++ imx334_power_off(&client->dev); ++ pm_runtime_set_suspended(&client->dev); ++ } + + mutex_destroy(&imx334->mutex); + } +diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c +index 0beb80b8c45815..9b4db4cd4929ca 100644 +--- a/drivers/media/i2c/imx335.c ++++ b/drivers/media/i2c/imx335.c +@@ -31,7 +31,7 @@ + #define IMX335_REG_CPWAIT_TIME CCI_REG8(0x300d) + #define IMX335_REG_WINMODE CCI_REG8(0x3018) + #define IMX335_REG_HTRIMMING_START CCI_REG16_LE(0x302c) +-#define IMX335_REG_HNUM CCI_REG8(0x302e) ++#define IMX335_REG_HNUM CCI_REG16_LE(0x302e) + + /* Lines per frame */ + #define IMX335_REG_VMAX CCI_REG24_LE(0x3030) +@@ -660,7 +660,8 @@ static int imx335_enum_frame_size(struct v4l2_subdev *sd, + struct imx335 *imx335 = to_imx335(sd); + u32 code; + +- if (fsize->index > ARRAY_SIZE(imx335_mbus_codes)) ++ /* Only a single supported_mode available. */ ++ if (fsize->index > 0) + return -EINVAL; + + code = imx335_get_format_code(imx335, fsize->code); +diff --git a/drivers/media/i2c/lt6911uxe.c b/drivers/media/i2c/lt6911uxe.c +index c5b40bb58a373d..24857d683fcfcf 100644 +--- a/drivers/media/i2c/lt6911uxe.c ++++ b/drivers/media/i2c/lt6911uxe.c +@@ -605,10 +605,10 @@ static int lt6911uxe_probe(struct i2c_client *client) + return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio), + "failed to get reset gpio\n"); + +- lt6911uxe->irq_gpio = devm_gpiod_get(dev, "readystat", GPIOD_IN); ++ lt6911uxe->irq_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN); + if (IS_ERR(lt6911uxe->irq_gpio)) + return dev_err_probe(dev, PTR_ERR(lt6911uxe->irq_gpio), +- "failed to get ready_stat gpio\n"); ++ "failed to get hpd gpio\n"); + + ret = lt6911uxe_fwnode_parse(lt6911uxe, dev); + if (ret) +diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c +index cf0e41fc30719d..54575eea3c4906 100644 +--- a/drivers/media/i2c/ov08x40.c ++++ b/drivers/media/i2c/ov08x40.c +@@ -1341,7 +1341,7 @@ static int ov08x40_power_on(struct device *dev) + } + + gpiod_set_value_cansleep(ov08x->reset_gpio, 0); +- usleep_range(1500, 1800); ++ usleep_range(5000, 5500); + + return 0; + +diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c +index 80d151e8ae294d..6cf461e3373ceb 100644 +--- a/drivers/media/i2c/ov2740.c ++++ b/drivers/media/i2c/ov2740.c +@@ -1456,12 +1456,12 @@ static int ov2740_probe(struct i2c_client *client) + return 0; + + probe_error_v4l2_subdev_cleanup: ++ pm_runtime_disable(&client->dev); ++ pm_runtime_set_suspended(&client->dev); + v4l2_subdev_cleanup(&ov2740->sd); + + probe_error_media_entity_cleanup: + media_entity_cleanup(&ov2740->sd.entity); +- pm_runtime_disable(&client->dev); +- pm_runtime_set_suspended(&client->dev); + + probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov2740->sd.ctrl_handler); +diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c +index c1081deffc2f99..e7aec281e9a49d 100644 +--- a/drivers/media/i2c/ov5675.c ++++ b/drivers/media/i2c/ov5675.c +@@ -1295,11 +1295,8 @@ static int ov5675_probe(struct i2c_client *client) + return -ENOMEM; + + ret = ov5675_get_hwcfg(ov5675, &client->dev); +- if (ret) { +- dev_err(&client->dev, "failed to get HW configuration: %d", +- ret); ++ if (ret) + return ret; +- } + + v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); + +diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c +index e6704d01824815..4b6874d2a104ad 100644 +--- a/drivers/media/i2c/ov8856.c ++++ b/drivers/media/i2c/ov8856.c +@@ -2276,8 +2276,8 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) + if (!is_acpi_node(fwnode)) { + ov8856->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov8856->xvclk)) { +- dev_err(dev, "could not get xvclk clock (%pe)\n", +- ov8856->xvclk); ++ dev_err_probe(dev, PTR_ERR(ov8856->xvclk), ++ "could not get xvclk clock\n"); + return PTR_ERR(ov8856->xvclk); + } + +@@ -2382,11 +2382,8 @@ static int ov8856_probe(struct i2c_client *client) + return -ENOMEM; + + ret = ov8856_get_hwcfg(ov8856, &client->dev); +- if (ret) { +- dev_err(&client->dev, "failed to get HW configuration: %d", +- ret); ++ if (ret) + return ret; +- } + + v4l2_i2c_subdev_init(&ov8856->sd, client, &ov8856_subdev_ops); + +diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c +index 2d5f42f111583b..dcef93e1a3bcdf 100644 +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -313,6 +313,10 @@ static int tc358743_get_detected_timings(struct v4l2_subdev *sd, + + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + ++ /* if HPD is low, ignore any video */ ++ if (!(i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0)) ++ return -ENOLINK; ++ + if (no_signal(sd)) { + v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); + return -ENOLINK; +diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c +index 1ca60ca79dba3b..7296373d36b0aa 100644 +--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c ++++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c +@@ -172,7 +172,7 @@ void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size, + count = PHYS_PFN(size); + + iova = alloc_iova(&mmu->dmap->iovad, count, +- PHYS_PFN(dma_get_mask(dev)), 0); ++ PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0); + if (!iova) + goto out_kfree; + +@@ -398,7 +398,7 @@ int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + nents, npages); + + iova = alloc_iova(&mmu->dmap->iovad, npages, +- PHYS_PFN(dma_get_mask(dev)), 0); ++ PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0); + if (!iova) + return 0; + +diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c +index 277af7cda8eec1..b00d0705fefa86 100644 +--- a/drivers/media/pci/intel/ipu6/ipu6.c ++++ b/drivers/media/pci/intel/ipu6/ipu6.c +@@ -464,11 +464,6 @@ static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver) + { + int ret; + +- /* disable IPU6 PCI ATS on mtl ES2 */ +- if (is_ipu6ep_mtl(hw_ver) && boot_cpu_data.x86_stepping == 0x2 && +- pci_ats_supported(dev)) +- pci_disable_ats(dev); +- + /* No PCI msi capability for IPU6EP */ + if (is_ipu6ep(hw_ver) || is_ipu6ep_mtl(hw_ver)) { + /* likely do nothing as msi not enabled by default */ +diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c +index c194f830577f9a..ae868d9f73e13f 100644 +--- a/drivers/media/platform/imagination/e5010-jpeg-enc.c ++++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c +@@ -1057,8 +1057,11 @@ static int e5010_probe(struct platform_device *pdev) + e5010->vdev->lock = &e5010->mutex; + + ret = v4l2_device_register(dev, &e5010->v4l2_dev); +- if (ret) +- return dev_err_probe(dev, ret, "failed to register v4l2 device\n"); ++ if (ret) { ++ dev_err_probe(dev, ret, "failed to register v4l2 device\n"); ++ goto fail_after_video_device_alloc; ++ } ++ + + e5010->m2m_dev = v4l2_m2m_init(&e5010_m2m_ops); + if (IS_ERR(e5010->m2m_dev)) { +@@ -1118,6 +1121,8 @@ static int e5010_probe(struct platform_device *pdev) + v4l2_m2m_release(e5010->m2m_dev); + fail_after_v4l2_register: + v4l2_device_unregister(&e5010->v4l2_dev); ++fail_after_video_device_alloc: ++ video_device_release(e5010->vdev); + return ret; + } + +diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c +index aa721cc43647c7..2725db882e5b30 100644 +--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c ++++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c +@@ -821,7 +821,7 @@ static int vdec_hevc_slice_setup_core_buffer(struct vdec_hevc_slice_inst *inst, + inst->vsi_core->fb.y.dma_addr = y_fb_dma; + inst->vsi_core->fb.y.size = ctx->picinfo.fb_sz[0]; + inst->vsi_core->fb.c.dma_addr = c_fb_dma; +- inst->vsi_core->fb.y.size = ctx->picinfo.fb_sz[1]; ++ inst->vsi_core->fb.c.size = ctx->picinfo.fb_sz[1]; + + inst->vsi_core->dec.vdec_fb_va = (unsigned long)fb; + +diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c +index 7a9d8928ae4019..3022fdcf66ec7a 100644 +--- a/drivers/media/platform/nuvoton/npcm-video.c ++++ b/drivers/media/platform/nuvoton/npcm-video.c +@@ -863,7 +863,6 @@ static void npcm_video_detect_resolution(struct npcm_video *video) + struct regmap *gfxi = video->gfx_regmap; + unsigned int dispst; + +- video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + +@@ -892,12 +891,16 @@ static void npcm_video_detect_resolution(struct npcm_video *video) + clear_bit(VIDEO_RES_CHANGING, &video->flags); + } + +- if (det->width && det->height) ++ if (det->width && det->height) { + video->v4l2_input_status = 0; +- +- dev_dbg(video->dev, "Got resolution[%dx%d] -> [%dx%d], status %d\n", +- act->width, act->height, det->width, det->height, +- video->v4l2_input_status); ++ dev_dbg(video->dev, "Got resolution[%dx%d] -> [%dx%d], status %d\n", ++ act->width, act->height, det->width, det->height, ++ video->v4l2_input_status); ++ } else { ++ video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; ++ dev_err(video->dev, "Got invalid resolution[%dx%d]\n", det->width, ++ det->height); ++ } + } + + static int npcm_video_set_resolution(struct npcm_video *video, +diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +index d579c804b04790..adb93e977be91a 100644 +--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h ++++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +@@ -89,6 +89,7 @@ + /* SLOT_STATUS fields for slots 0..3 */ + #define SLOT_STATUS_FRMDONE (0x1 << 3) + #define SLOT_STATUS_ENC_CONFIG_ERR (0x1 << 8) ++#define SLOT_STATUS_ONGOING (0x1 << 31) + + /* SLOT_IRQ_EN fields TBD */ + +diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +index 1221b309a91639..dce5620d29e477 100644 +--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c ++++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +@@ -752,6 +752,32 @@ static int mxc_get_free_slot(struct mxc_jpeg_slot_data *slot_data) + return -1; + } + ++static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg) ++{ ++ /* free descriptor for decoding/encoding phase */ ++ dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), ++ jpeg->slot_data.desc, ++ jpeg->slot_data.desc_handle); ++ jpeg->slot_data.desc = NULL; ++ jpeg->slot_data.desc_handle = 0; ++ ++ /* free descriptor for encoder configuration phase / decoder DHT */ ++ dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), ++ jpeg->slot_data.cfg_desc, ++ jpeg->slot_data.cfg_desc_handle); ++ jpeg->slot_data.cfg_desc_handle = 0; ++ jpeg->slot_data.cfg_desc = NULL; ++ ++ /* free configuration stream */ ++ dma_free_coherent(jpeg->dev, MXC_JPEG_MAX_CFG_STREAM, ++ jpeg->slot_data.cfg_stream_vaddr, ++ jpeg->slot_data.cfg_stream_handle); ++ jpeg->slot_data.cfg_stream_vaddr = NULL; ++ jpeg->slot_data.cfg_stream_handle = 0; ++ ++ jpeg->slot_data.used = false; ++} ++ + static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg) + { + struct mxc_jpeg_desc *desc; +@@ -794,30 +820,11 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg) + return true; + err: + dev_err(jpeg->dev, "Could not allocate descriptors for slot %d", jpeg->slot_data.slot); ++ mxc_jpeg_free_slot_data(jpeg); + + return false; + } + +-static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg) +-{ +- /* free descriptor for decoding/encoding phase */ +- dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), +- jpeg->slot_data.desc, +- jpeg->slot_data.desc_handle); +- +- /* free descriptor for encoder configuration phase / decoder DHT */ +- dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), +- jpeg->slot_data.cfg_desc, +- jpeg->slot_data.cfg_desc_handle); +- +- /* free configuration stream */ +- dma_free_coherent(jpeg->dev, MXC_JPEG_MAX_CFG_STREAM, +- jpeg->slot_data.cfg_stream_vaddr, +- jpeg->slot_data.cfg_stream_handle); +- +- jpeg->slot_data.used = false; +-} +- + static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + struct vb2_v4l2_buffer *dst_buf) +@@ -877,6 +884,34 @@ static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no) + return size; + } + ++static bool mxc_dec_is_ongoing(struct mxc_jpeg_ctx *ctx) ++{ ++ struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; ++ u32 curr_desc; ++ u32 slot_status; ++ ++ curr_desc = readl(jpeg->base_reg + MXC_SLOT_OFFSET(ctx->slot, SLOT_CUR_DESCPT_PTR)); ++ if (curr_desc == jpeg->slot_data.cfg_desc_handle) ++ return true; ++ ++ slot_status = readl(jpeg->base_reg + MXC_SLOT_OFFSET(ctx->slot, SLOT_STATUS)); ++ if (slot_status & SLOT_STATUS_ONGOING) ++ return true; ++ ++ /* ++ * The curr_desc register is updated when next_descpt_ptr is loaded, ++ * the ongoing bit of slot_status is set when the 32 bytes descriptor is loaded. ++ * So there will be a short time interval in between, which may cause fake false. ++ * Consider read register is quite slow compared with IP read 32byte from memory, ++ * read twice slot_status can avoid this situation. ++ */ ++ slot_status = readl(jpeg->base_reg + MXC_SLOT_OFFSET(ctx->slot, SLOT_STATUS)); ++ if (slot_status & SLOT_STATUS_ONGOING) ++ return true; ++ ++ return false; ++} ++ + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) + { + struct mxc_jpeg_dev *jpeg = priv; +@@ -946,7 +981,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) + mxc_jpeg_enc_mode_go(dev, reg, mxc_jpeg_is_extended_sequential(q_data->fmt)); + goto job_unlock; + } +- if (jpeg->mode == MXC_JPEG_DECODE && jpeg_src_buf->dht_needed) { ++ if (jpeg->mode == MXC_JPEG_DECODE && jpeg_src_buf->dht_needed && ++ mxc_dec_is_ongoing(ctx)) { + jpeg_src_buf->dht_needed = false; + dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n"); + goto job_unlock; +@@ -1918,9 +1954,19 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) + jpeg_src_buf = vb2_to_mxc_buf(vb); + jpeg_src_buf->jpeg_parse_error = false; + ret = mxc_jpeg_parse(ctx, vb); +- if (ret) ++ if (ret) { + jpeg_src_buf->jpeg_parse_error = true; + ++ /* ++ * if the capture queue is not setup, the device_run() won't be scheduled, ++ * need to drop the error buffer, so that the decoding can continue ++ */ ++ if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) { ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); ++ return; ++ } ++ } ++ + end: + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + } +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +index 794050a6a919b8..22e49d3a128732 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +@@ -43,6 +43,7 @@ struct mxc_isi_m2m_ctx_queue_data { + struct v4l2_pix_format_mplane format; + const struct mxc_isi_format_info *info; + u32 sequence; ++ bool streaming; + }; + + struct mxc_isi_m2m_ctx { +@@ -484,15 +485,18 @@ static int mxc_isi_m2m_streamon(struct file *file, void *fh, + enum v4l2_buf_type type) + { + struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); ++ struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); + const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format; + const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format; + const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info; + const struct mxc_isi_format_info *out_info = ctx->queues.out.info; + struct mxc_isi_m2m *m2m = ctx->m2m; + bool bypass; +- + int ret; + ++ if (q->streaming) ++ return 0; ++ + mutex_lock(&m2m->lock); + + if (m2m->usage_count == INT_MAX) { +@@ -545,6 +549,8 @@ static int mxc_isi_m2m_streamon(struct file *file, void *fh, + goto unchain; + } + ++ q->streaming = true; ++ + return 0; + + unchain: +@@ -567,10 +573,14 @@ static int mxc_isi_m2m_streamoff(struct file *file, void *fh, + enum v4l2_buf_type type) + { + struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); ++ struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); + struct mxc_isi_m2m *m2m = ctx->m2m; + + v4l2_m2m_ioctl_streamoff(file, fh, type); + ++ if (!q->streaming) ++ return 0; ++ + mutex_lock(&m2m->lock); + + /* +@@ -596,6 +606,8 @@ static int mxc_isi_m2m_streamoff(struct file *file, void *fh, + + mutex_unlock(&m2m->lock); + ++ q->streaming = false; ++ + return 0; + } + +diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c +index d08117f46f3b9b..5284b5857368c3 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid.c ++++ b/drivers/media/platform/qcom/camss/camss-csid.c +@@ -613,8 +613,8 @@ u32 csid_hw_version(struct csid_device *csid) + hw_gen = (hw_version >> HW_VERSION_GENERATION) & 0xF; + hw_rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF; + hw_step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF; +- dev_info(csid->camss->dev, "CSID:%d HW Version = %u.%u.%u\n", +- csid->id, hw_gen, hw_rev, hw_step); ++ dev_dbg(csid->camss->dev, "CSID:%d HW Version = %u.%u.%u\n", ++ csid->id, hw_gen, hw_rev, hw_step); + + return hw_version; + } +diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c +index cf0e8f5c004a20..91bc0cb7781e44 100644 +--- a/drivers/media/platform/qcom/camss/camss-vfe.c ++++ b/drivers/media/platform/qcom/camss/camss-vfe.c +@@ -428,8 +428,8 @@ u32 vfe_hw_version(struct vfe_device *vfe) + u32 rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF; + u32 step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF; + +- dev_info(vfe->camss->dev, "VFE:%d HW Version = %u.%u.%u\n", +- vfe->id, gen, rev, step); ++ dev_dbg(vfe->camss->dev, "VFE:%d HW Version = %u.%u.%u\n", ++ vfe->id, gen, rev, step); + + return hw_version; + } +diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c +index 7c493b4a75dbb2..f1b5cd56db3225 100644 +--- a/drivers/media/platform/qcom/iris/iris_firmware.c ++++ b/drivers/media/platform/qcom/iris/iris_firmware.c +@@ -53,8 +53,10 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) + } + + mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC); +- if (!mem_virt) ++ if (!mem_virt) { ++ ret = -ENOMEM; + goto err_release_fw; ++ } + + ret = qcom_mdt_load(dev, firmware, fw_name, + pas_id, mem_virt, mem_phys, res_size, NULL); +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index 77d48578ecd288..d305d74bb152d2 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -438,7 +438,7 @@ static int venus_probe(struct platform_device *pdev) + + ret = v4l2_device_register(dev, &core->v4l2_dev); + if (ret) +- goto err_core_deinit; ++ goto err_hfi_destroy; + + platform_set_drvdata(pdev, core); + +@@ -476,24 +476,24 @@ static int venus_probe(struct platform_device *pdev) + + ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); + if (ret) +- goto err_venus_shutdown; ++ goto err_core_deinit; + + ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); + if (ret) +- goto err_venus_shutdown; ++ goto err_core_deinit; + + ret = pm_runtime_put_sync(dev); + if (ret) { + pm_runtime_get_noresume(dev); +- goto err_dev_unregister; ++ goto err_core_deinit; + } + + venus_dbgfs_init(core); + + return 0; + +-err_dev_unregister: +- v4l2_device_unregister(&core->v4l2_dev); ++err_core_deinit: ++ hfi_core_deinit(core, false); + err_venus_shutdown: + venus_shutdown(core); + err_firmware_deinit: +@@ -506,9 +506,9 @@ static int venus_probe(struct platform_device *pdev) + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); ++ v4l2_device_unregister(&core->v4l2_dev); ++err_hfi_destroy: + hfi_destroy(core); +-err_core_deinit: +- hfi_core_deinit(core, false); + err_core_put: + if (core->pm_ops->core_put) + core->pm_ops->core_put(core); +diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c +index 9f82882b77bcc5..39d0556d7237d7 100644 +--- a/drivers/media/platform/qcom/venus/vdec.c ++++ b/drivers/media/platform/qcom/venus/vdec.c +@@ -154,14 +154,14 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) + return NULL; + + for (i = 0; i < size; i++) { +- bool valid; ++ bool valid = false; + + if (fmt[i].type != type) + continue; + + if (V4L2_TYPE_IS_OUTPUT(type)) { + valid = venus_helper_check_codec(inst, fmt[i].pixfmt); +- } else if (V4L2_TYPE_IS_CAPTURE(type)) { ++ } else { + valid = venus_helper_check_format(inst, fmt[i].pixfmt); + + if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && +diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +index 8de8712404409c..3af67c1b303d6e 100644 +--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c ++++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +@@ -679,22 +679,6 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) + + fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); + stride = vin->format.bytesperline / fmt->bpp; +- +- /* For RAW8 format bpp is 1, but the hardware process RAW8 +- * format in 2 pixel unit hence configure VNIS_REG as stride / 2. +- */ +- switch (vin->format.pixelformat) { +- case V4L2_PIX_FMT_SBGGR8: +- case V4L2_PIX_FMT_SGBRG8: +- case V4L2_PIX_FMT_SGRBG8: +- case V4L2_PIX_FMT_SRGGB8: +- case V4L2_PIX_FMT_GREY: +- stride /= 2; +- break; +- default: +- break; +- } +- + rvin_write(vin, stride, VNIS_REG); + } + +@@ -910,7 +894,7 @@ static int rvin_setup(struct rvin_dev *vin) + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: +- dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR; ++ dmr = VNDMR_RMODE_RAW10; + break; + default: + vin_err(vin, "Invalid pixelformat (0x%x)\n", +diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +index 756fdfdbce616c..65da8d513b527d 100644 +--- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c ++++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +@@ -88,19 +88,19 @@ static const struct rvin_video_format rvin_formats[] = { + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, +- .bpp = 4, ++ .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, +- .bpp = 4, ++ .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, +- .bpp = 4, ++ .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, +- .bpp = 4, ++ .bpp = 2, + }, + }; + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 9d38203e73d00b..1b4bac7b7cfa1c 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -76,11 +76,20 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, + format = v4l2_subdev_state_get_format(state, fmt->pad); + + if (fmt->pad == RWPF_PAD_SOURCE) { ++ const struct v4l2_mbus_framefmt *sink_format = ++ v4l2_subdev_state_get_format(state, RWPF_PAD_SINK); ++ + /* + * The RWPF performs format conversion but can't scale, only the +- * format code can be changed on the source pad. ++ * format code can be changed on the source pad when converting ++ * between RGB and YUV. + */ +- format->code = fmt->format.code; ++ if (sink_format->code != MEDIA_BUS_FMT_AHSV8888_1X32 && ++ fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32) ++ format->code = fmt->format.code; ++ else ++ format->code = sink_format->code; ++ + fmt->format = *format; + goto done; + } +diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-regs.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-regs.c +index 366e6393817d21..5f9c44e825a5fa 100644 +--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-regs.c ++++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-regs.c +@@ -164,6 +164,7 @@ int fimc_is_hw_change_mode(struct fimc_is *is) + if (WARN_ON(is->config_index >= ARRAY_SIZE(cmd))) + return -EINVAL; + ++ fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(cmd[is->config_index], is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2)); +diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c +index e29743ae61e27e..c16754c136ca04 100644 +--- a/drivers/media/platform/ti/cal/cal-video.c ++++ b/drivers/media/platform/ti/cal/cal-video.c +@@ -758,7 +758,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) + + ret = pm_runtime_resume_and_get(ctx->cal->dev); + if (ret < 0) +- goto error_pipeline; ++ goto error_unprepare; + + cal_ctx_set_dma_addr(ctx, addr); + cal_ctx_start(ctx); +@@ -775,8 +775,8 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) + error_stop: + cal_ctx_stop(ctx); + pm_runtime_put_sync(ctx->cal->dev); ++error_unprepare: + cal_ctx_unprepare(ctx); +- + error_pipeline: + video_device_pipeline_stop(&ctx->vdev); + error_release_buffers: +diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c +index a81719702a22d1..969d623fc842e5 100644 +--- a/drivers/media/platform/ti/davinci/vpif.c ++++ b/drivers/media/platform/ti/davinci/vpif.c +@@ -504,7 +504,7 @@ static int vpif_probe(struct platform_device *pdev) + pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL); + if (!pdev_display) { + ret = -ENOMEM; +- goto err_put_pdev_capture; ++ goto err_del_pdev_capture; + } + + pdev_display->name = "vpif_display"; +@@ -527,6 +527,8 @@ static int vpif_probe(struct platform_device *pdev) + + err_put_pdev_display: + platform_device_put(pdev_display); ++err_del_pdev_capture: ++ platform_device_del(pdev_capture); + err_put_pdev_capture: + platform_device_put(pdev_capture); + err_put_rpm: +diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c +index dd375c4e180d1b..7d0c723dcd119a 100644 +--- a/drivers/media/platform/ti/omap3isp/ispccdc.c ++++ b/drivers/media/platform/ti/omap3isp/ispccdc.c +@@ -446,8 +446,8 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, + if (ret < 0) + goto done; + +- dma_sync_sg_for_cpu(isp->dev, req->table.sgt.sgl, +- req->table.sgt.nents, DMA_TO_DEVICE); ++ dma_sync_sgtable_for_cpu(isp->dev, &req->table.sgt, ++ DMA_TO_DEVICE); + + if (copy_from_user(req->table.addr, config->lsc, + req->config.size)) { +@@ -455,8 +455,8 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, + goto done; + } + +- dma_sync_sg_for_device(isp->dev, req->table.sgt.sgl, +- req->table.sgt.nents, DMA_TO_DEVICE); ++ dma_sync_sgtable_for_device(isp->dev, &req->table.sgt, ++ DMA_TO_DEVICE); + } + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); +diff --git a/drivers/media/platform/ti/omap3isp/ispstat.c b/drivers/media/platform/ti/omap3isp/ispstat.c +index 359a846205b0ff..d3da68408ecb16 100644 +--- a/drivers/media/platform/ti/omap3isp/ispstat.c ++++ b/drivers/media/platform/ti/omap3isp/ispstat.c +@@ -161,8 +161,7 @@ static void isp_stat_buf_sync_for_device(struct ispstat *stat, + if (ISP_STAT_USES_DMAENGINE(stat)) + return; + +- dma_sync_sg_for_device(stat->isp->dev, buf->sgt.sgl, +- buf->sgt.nents, DMA_FROM_DEVICE); ++ dma_sync_sgtable_for_device(stat->isp->dev, &buf->sgt, DMA_FROM_DEVICE); + } + + static void isp_stat_buf_sync_for_cpu(struct ispstat *stat, +@@ -171,8 +170,7 @@ static void isp_stat_buf_sync_for_cpu(struct ispstat *stat, + if (ISP_STAT_USES_DMAENGINE(stat)) + return; + +- dma_sync_sg_for_cpu(stat->isp->dev, buf->sgt.sgl, +- buf->sgt.nents, DMA_FROM_DEVICE); ++ dma_sync_sgtable_for_cpu(stat->isp->dev, &buf->sgt, DMA_FROM_DEVICE); + } + + static void isp_stat_buf_clear(struct ispstat *stat) +diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c +index 964122e7c35593..b64f0658f7f1e7 100644 +--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c ++++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c +@@ -85,10 +85,10 @@ static const struct hantro_fmt rockchip_vpu981_postproc_fmts[] = { + .postprocessed = true, + .frmsize = { + .min_width = ROCKCHIP_VPU981_MIN_SIZE, +- .max_width = FMT_UHD_WIDTH, ++ .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = ROCKCHIP_VPU981_MIN_SIZE, +- .max_height = FMT_UHD_HEIGHT, ++ .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +@@ -99,10 +99,10 @@ static const struct hantro_fmt rockchip_vpu981_postproc_fmts[] = { + .postprocessed = true, + .frmsize = { + .min_width = ROCKCHIP_VPU981_MIN_SIZE, +- .max_width = FMT_UHD_WIDTH, ++ .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = ROCKCHIP_VPU981_MIN_SIZE, +- .max_height = FMT_UHD_HEIGHT, ++ .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +@@ -318,10 +318,10 @@ static const struct hantro_fmt rockchip_vpu981_dec_fmts[] = { + .match_depth = true, + .frmsize = { + .min_width = ROCKCHIP_VPU981_MIN_SIZE, +- .max_width = FMT_UHD_WIDTH, ++ .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = ROCKCHIP_VPU981_MIN_SIZE, +- .max_height = FMT_UHD_HEIGHT, ++ .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +@@ -331,10 +331,10 @@ static const struct hantro_fmt rockchip_vpu981_dec_fmts[] = { + .match_depth = true, + .frmsize = { + .min_width = ROCKCHIP_VPU981_MIN_SIZE, +- .max_width = FMT_UHD_WIDTH, ++ .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = ROCKCHIP_VPU981_MIN_SIZE, +- .max_height = FMT_UHD_HEIGHT, ++ .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +@@ -344,10 +344,10 @@ static const struct hantro_fmt rockchip_vpu981_dec_fmts[] = { + .max_depth = 2, + .frmsize = { + .min_width = ROCKCHIP_VPU981_MIN_SIZE, +- .max_width = FMT_UHD_WIDTH, ++ .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = ROCKCHIP_VPU981_MIN_SIZE, +- .max_height = FMT_UHD_HEIGHT, ++ .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c b/drivers/media/test-drivers/vidtv/vidtv_channel.c +index 7838e62727128f..f3023e91b3ebc8 100644 +--- a/drivers/media/test-drivers/vidtv/vidtv_channel.c ++++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c +@@ -497,7 +497,7 @@ int vidtv_channel_si_init(struct vidtv_mux *m) + vidtv_psi_sdt_table_destroy(m->si.sdt); + free_pat: + vidtv_psi_pat_table_destroy(m->si.pat); +- return 0; ++ return -EINVAL; + } + + void vidtv_channel_si_destroy(struct vidtv_mux *m) +diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +index b166d90177c641..df5d1c2a42ef51 100644 +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +@@ -946,8 +946,8 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection + if (dev->has_compose_cap) { + v4l2_rect_set_min_size(compose, &min_rect); + v4l2_rect_set_max_size(compose, &max_rect); +- v4l2_rect_map_inside(compose, &fmt); + } ++ v4l2_rect_map_inside(compose, &fmt); + dev->fmt_cap_rect = fmt; + tpg_s_buf_height(&dev->tpg, fmt.height); + } else if (dev->has_compose_cap) { +diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c +index f44529b40989b1..d0501c1e81d63e 100644 +--- a/drivers/media/usb/dvb-usb/cxusb.c ++++ b/drivers/media/usb/dvb-usb/cxusb.c +@@ -119,9 +119,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) + + o[0] = GPIO_TUNER; + o[1] = onoff; +- cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + +- if (i != 0x01) ++ if (!cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1) && i != 0x01) + dev_info(&d->udev->dev, "gpio_write failed.\n"); + + st->gpio_write_state[GPIO_TUNER] = onoff; +diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c +index 5a47dcbf1c8e55..303b055fefea98 100644 +--- a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c ++++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c +@@ -520,12 +520,13 @@ static int hdcs_init(struct sd *sd) + static int hdcs_dump(struct sd *sd) + { + u16 reg, val; ++ int err = 0; + + pr_info("Dumping sensor registers:\n"); + +- for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { +- stv06xx_read_sensor(sd, reg, &val); ++ for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH && !err; reg++) { ++ err = stv06xx_read_sensor(sd, reg, &val); + pr_info("reg 0x%02x = 0x%02x\n", reg, val); + } +- return 0; ++ return (err < 0) ? err : 0; + } +diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c +index cbf19aa1d82374..bc7e2005fc6c72 100644 +--- a/drivers/media/usb/uvc/uvc_ctrl.c ++++ b/drivers/media/usb/uvc/uvc_ctrl.c +@@ -1943,7 +1943,9 @@ static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, + } + + static void uvc_ctrl_send_events(struct uvc_fh *handle, +- const struct v4l2_ext_control *xctrls, unsigned int xctrls_count) ++ struct uvc_entity *entity, ++ const struct v4l2_ext_control *xctrls, ++ unsigned int xctrls_count) + { + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl; +@@ -1955,6 +1957,9 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, + s32 value; + + ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); ++ if (ctrl->entity != entity) ++ continue; ++ + if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) + /* Notification will be sent from an Interrupt event. */ + continue; +@@ -2090,12 +2095,17 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain) + return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; + } + ++/* ++ * Returns the number of uvc controls that have been correctly set, or a ++ * negative number if there has been an error. ++ */ + static int uvc_ctrl_commit_entity(struct uvc_device *dev, + struct uvc_fh *handle, + struct uvc_entity *entity, + int rollback, + struct uvc_control **err_ctrl) + { ++ unsigned int processed_ctrls = 0; + struct uvc_control *ctrl; + unsigned int i; + int ret; +@@ -2130,6 +2140,9 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, + else + ret = 0; + ++ if (!ret) ++ processed_ctrls++; ++ + if (rollback || ret < 0) + memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), +@@ -2148,7 +2161,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, + uvc_ctrl_set_handle(handle, ctrl, handle); + } + +- return 0; ++ return processed_ctrls; + } + + static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, +@@ -2190,11 +2203,13 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, + uvc_ctrl_find_ctrl_idx(entity, ctrls, + err_ctrl); + goto done; ++ } else if (ret > 0 && !rollback) { ++ uvc_ctrl_send_events(handle, entity, ++ ctrls->controls, ctrls->count); + } + } + +- if (!rollback) +- uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count); ++ ret = 0; + done: + mutex_unlock(&chain->ctrl_mutex); + return ret; +diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c +index 107e0fafd80f54..25e9aea81196e0 100644 +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -2232,13 +2232,16 @@ static int uvc_probe(struct usb_interface *intf, + #endif + + /* Parse the Video Class control descriptor. */ +- if (uvc_parse_control(dev) < 0) { ++ ret = uvc_parse_control(dev); ++ if (ret < 0) { ++ ret = -ENODEV; + uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); + goto error; + } + + /* Parse the associated GPIOs. */ +- if (uvc_gpio_parse(dev) < 0) { ++ ret = uvc_gpio_parse(dev); ++ if (ret < 0) { + uvc_dbg(dev, PROBE, "Unable to parse UVC GPIOs\n"); + goto error; + } +@@ -2264,24 +2267,32 @@ static int uvc_probe(struct usb_interface *intf, + } + + /* Register the V4L2 device. */ +- if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) ++ ret = v4l2_device_register(&intf->dev, &dev->vdev); ++ if (ret < 0) + goto error; + + /* Scan the device for video chains. */ +- if (uvc_scan_device(dev) < 0) ++ if (uvc_scan_device(dev) < 0) { ++ ret = -ENODEV; + goto error; ++ } + + /* Initialize controls. */ +- if (uvc_ctrl_init_device(dev) < 0) ++ if (uvc_ctrl_init_device(dev) < 0) { ++ ret = -ENODEV; + goto error; ++ } + + /* Register video device nodes. */ +- if (uvc_register_chains(dev) < 0) ++ if (uvc_register_chains(dev) < 0) { ++ ret = -ENODEV; + goto error; ++ } + + #ifdef CONFIG_MEDIA_CONTROLLER + /* Register the media device node */ +- if (media_device_register(&dev->mdev) < 0) ++ ret = media_device_register(&dev->mdev); ++ if (ret < 0) + goto error; + #endif + /* Save our data pointer in the interface data. */ +@@ -2315,7 +2326,7 @@ static int uvc_probe(struct usb_interface *intf, + error: + uvc_unregister_video(dev); + kref_put(&dev->ref, uvc_delete); +- return -ENODEV; ++ return ret; + } + + static void uvc_disconnect(struct usb_interface *intf) +diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c +index b40c08ce909d44..c369235113d98a 100644 +--- a/drivers/media/v4l2-core/v4l2-dev.c ++++ b/drivers/media/v4l2-core/v4l2-dev.c +@@ -1054,25 +1054,25 @@ int __video_register_device(struct video_device *vdev, + vdev->dev.class = &video_class; + vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); + vdev->dev.parent = vdev->dev_parent; ++ vdev->dev.release = v4l2_device_release; + dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); ++ ++ /* Increase v4l2_device refcount */ ++ v4l2_device_get(vdev->v4l2_dev); ++ + mutex_lock(&videodev_lock); + ret = device_register(&vdev->dev); + if (ret < 0) { + mutex_unlock(&videodev_lock); + pr_err("%s: device_register failed\n", __func__); +- goto cleanup; ++ put_device(&vdev->dev); ++ return ret; + } +- /* Register the release callback that will be called when the last +- reference to the device goes away. */ +- vdev->dev.release = v4l2_device_release; + + if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) + pr_warn("%s: requested %s%d, got %s\n", __func__, + name_base, nr, video_device_node_name(vdev)); + +- /* Increase v4l2_device refcount */ +- v4l2_device_get(vdev->v4l2_dev); +- + /* Part 5: Register the entity. */ + ret = video_register_media_controller(vdev); + +diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h +index 3205feb1e8ff6a..9cbdd240c3a7d4 100644 +--- a/drivers/mmc/core/card.h ++++ b/drivers/mmc/core/card.h +@@ -89,6 +89,7 @@ struct mmc_fixup { + #define CID_MANFID_MICRON 0x13 + #define CID_MANFID_SAMSUNG 0x15 + #define CID_MANFID_APACER 0x27 ++#define CID_MANFID_SWISSBIT 0x5D + #define CID_MANFID_KINGSTON 0x70 + #define CID_MANFID_HYNIX 0x90 + #define CID_MANFID_KINGSTON_SD 0x9F +@@ -294,4 +295,9 @@ static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c) + return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY; + } + ++static inline int mmc_card_no_uhs_ddr50_tuning(const struct mmc_card *c) ++{ ++ return c->quirks & MMC_QUIRK_NO_UHS_DDR50_TUNING; ++} ++ + #endif +diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h +index 89b512905be140..7f893bafaa607d 100644 +--- a/drivers/mmc/core/quirks.h ++++ b/drivers/mmc/core/quirks.h +@@ -34,6 +34,16 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = { + MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY, + EXT_CSD_REV_ANY), + ++ /* ++ * Swissbit series S46-u cards throw I/O errors during tuning requests ++ * after the initial tuning request expectedly times out. This has ++ * only been observed on cards manufactured on 01/2019 that are using ++ * Bay Trail host controllers. ++ */ ++ _FIXUP_EXT("0016G", CID_MANFID_SWISSBIT, 0x5342, 2019, 1, ++ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, ++ MMC_QUIRK_NO_UHS_DDR50_TUNING, EXT_CSD_REV_ANY), ++ + END_FIXUP + }; + +diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c +index 8eba697d3d8671..6847b3fe8887aa 100644 +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -617,6 +617,29 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status) + return 0; + } + ++/* ++ * Determine if the card should tune or not. ++ */ ++static bool mmc_sd_use_tuning(struct mmc_card *card) ++{ ++ /* ++ * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and ++ * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. ++ */ ++ if (mmc_host_is_spi(card->host)) ++ return false; ++ ++ switch (card->host->ios.timing) { ++ case MMC_TIMING_UHS_SDR50: ++ case MMC_TIMING_UHS_SDR104: ++ return true; ++ case MMC_TIMING_UHS_DDR50: ++ return !mmc_card_no_uhs_ddr50_tuning(card); ++ } ++ ++ return false; ++} ++ + /* + * UHS-I specific initialization procedure + */ +@@ -660,14 +683,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) + if (err) + goto out; + +- /* +- * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and +- * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. +- */ +- if (!mmc_host_is_spi(card->host) && +- (card->host->ios.timing == MMC_TIMING_UHS_SDR50 || +- card->host->ios.timing == MMC_TIMING_UHS_DDR50 || +- card->host->ios.timing == MMC_TIMING_UHS_SDR104)) { ++ if (mmc_sd_use_tuning(card)) { + err = mmc_execute_tuning(card); + + /* +diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c +index e0ed25b5afea9b..4dc4d65e7d323e 100644 +--- a/drivers/mtd/nand/qpic_common.c ++++ b/drivers/mtd/nand/qpic_common.c +@@ -236,21 +236,21 @@ int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + int i, ret; + struct bam_cmd_element *bam_ce_buffer; + struct bam_transaction *bam_txn = nandc->bam_txn; ++ u32 offset; + + bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos]; + + /* fill the command desc */ + for (i = 0; i < size; i++) { ++ offset = nandc->props->bam_offset + reg_off + 4 * i; + if (read) + bam_prep_ce(&bam_ce_buffer[i], +- nandc_reg_phys(nandc, reg_off + 4 * i), +- BAM_READ_COMMAND, ++ offset, BAM_READ_COMMAND, + reg_buf_dma_addr(nandc, + (__le32 *)vaddr + i)); + else + bam_prep_ce_le32(&bam_ce_buffer[i], +- nandc_reg_phys(nandc, reg_off + 4 * i), +- BAM_WRITE_COMMAND, ++ offset, BAM_WRITE_COMMAND, + *((__le32 *)vaddr + i)); + } + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index 5eaa0be367cdb8..1003cf118c01b8 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -1863,7 +1863,12 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + const struct nand_op_instr *instr = NULL; + unsigned int op_id = 0; + unsigned int len = 0; +- int ret; ++ int ret, reg_base; ++ ++ reg_base = NAND_READ_LOCATION_0; ++ ++ if (nandc->props->qpic_version2) ++ reg_base = NAND_READ_LOCATION_LAST_CW_0; + + ret = qcom_parse_instructions(chip, subop, &q_op); + if (ret) +@@ -1915,14 +1920,17 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + +- nandc_set_read_loc(chip, 0, 0, 0, len, 1); ++ if (nandc->props->qpic_version2) ++ nandc_set_read_loc_last(chip, reg_base, 0, len, 1); ++ else ++ nandc_set_read_loc_first(chip, reg_base, 0, len, 1); + + if (!nandc->props->qpic_version2) { + qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + } + +- nandc->buf_count = len; ++ nandc->buf_count = 512; + memset(nandc->data_buffer, 0xff, nandc->buf_count); + + config_nand_single_cw_page_read(chip, false, 0); +@@ -2360,6 +2368,7 @@ static const struct qcom_nandc_props ipq806x_nandc_props = { + .supports_bam = false, + .use_codeword_fixup = true, + .dev_cmd_reg_start = 0x0, ++ .bam_offset = 0x30000, + }; + + static const struct qcom_nandc_props ipq4019_nandc_props = { +@@ -2367,6 +2376,7 @@ static const struct qcom_nandc_props ipq4019_nandc_props = { + .supports_bam = true, + .nandc_part_of_qpic = true, + .dev_cmd_reg_start = 0x0, ++ .bam_offset = 0x30000, + }; + + static const struct qcom_nandc_props ipq8074_nandc_props = { +@@ -2374,6 +2384,7 @@ static const struct qcom_nandc_props ipq8074_nandc_props = { + .supports_bam = true, + .nandc_part_of_qpic = true, + .dev_cmd_reg_start = 0x7000, ++ .bam_offset = 0x30000, + }; + + static const struct qcom_nandc_props sdx55_nandc_props = { +@@ -2382,6 +2393,7 @@ static const struct qcom_nandc_props sdx55_nandc_props = { + .nandc_part_of_qpic = true, + .qpic_version2 = true, + .dev_cmd_reg_start = 0x7000, ++ .bam_offset = 0x30000, + }; + + /* +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index fab371e3e9b780..162cd5f4f2344c 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -817,6 +817,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, + if (ret) + return ret; + ++ sunxi_nfc_randomizer_config(nand, page, false); + sunxi_nfc_randomizer_enable(nand); + writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, + nfc->regs + NFC_REG_CMD); +@@ -1049,6 +1050,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, + if (ret) + return ret; + ++ sunxi_nfc_randomizer_config(nand, page, false); + sunxi_nfc_randomizer_enable(nand); + sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, 0, bbm, page); + +diff --git a/drivers/mtd/nand/spi/alliancememory.c b/drivers/mtd/nand/spi/alliancememory.c +index 6046c73f8424e9..0f9522009843bc 100644 +--- a/drivers/mtd/nand/spi/alliancememory.c ++++ b/drivers/mtd/nand/spi/alliancememory.c +@@ -17,12 +17,12 @@ + #define AM_STATUS_ECC_MAX_CORRECTED (3 << 4) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/ato.c b/drivers/mtd/nand/spi/ato.c +index bb5298911137f0..88dc51308e1b84 100644 +--- a/drivers/mtd/nand/spi/ato.c ++++ b/drivers/mtd/nand/spi/ato.c +@@ -14,9 +14,9 @@ + + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c +index a164d821464d27..cda718e385a22f 100644 +--- a/drivers/mtd/nand/spi/esmt.c ++++ b/drivers/mtd/nand/spi/esmt.c +@@ -18,10 +18,10 @@ + (CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c +index ecd5f6bffa3342..21ad44032286ff 100644 +--- a/drivers/mtd/nand/spi/foresee.c ++++ b/drivers/mtd/nand/spi/foresee.c +@@ -12,10 +12,10 @@ + #define SPINAND_MFR_FORESEE 0xCD + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c +index d620bb02a20a0d..3ce79ae1bac4e8 100644 +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -24,36 +24,36 @@ + #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(read_cache_variants_f, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP_3A(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP_3A(0, 0, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0)); + + static SPINAND_OP_VARIANTS(read_cache_variants_1gq5, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(read_cache_variants_2gq5, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c +index 1ef08ad850a2fe..208db1a2151049 100644 +--- a/drivers/mtd/nand/spi/macronix.c ++++ b/drivers/mtd/nand/spi/macronix.c +@@ -28,10 +28,10 @@ struct macronix_priv { + }; + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c +index 691f8a2e0791d0..f92c28b8d55712 100644 +--- a/drivers/mtd/nand/spi/micron.c ++++ b/drivers/mtd/nand/spi/micron.c +@@ -35,12 +35,12 @@ + (CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE) + + static SPINAND_OP_VARIANTS(quadio_read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(x4_write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +@@ -52,10 +52,10 @@ static SPINAND_OP_VARIANTS(x4_update_cache_variants, + + /* Micron MT29F2G01AAAED Device */ + static SPINAND_OP_VARIANTS(x4_read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(x1_write_cache_variants, + SPINAND_PROG_LOAD(true, 0, NULL, 0)); +diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c +index 6e7cc6995380c0..b5ea248618036d 100644 +--- a/drivers/mtd/nand/spi/paragon.c ++++ b/drivers/mtd/nand/spi/paragon.c +@@ -22,12 +22,12 @@ + + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/skyhigh.c b/drivers/mtd/nand/spi/skyhigh.c +index 961df0d74984a8..ac73f43e9365c7 100644 +--- a/drivers/mtd/nand/spi/skyhigh.c ++++ b/drivers/mtd/nand/spi/skyhigh.c +@@ -17,12 +17,12 @@ + #define SKYHIGH_CONFIG_PROTECT_EN BIT(1) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c +index 2e2106b2705f08..f3f2c0ed1d0cae 100644 +--- a/drivers/mtd/nand/spi/toshiba.c ++++ b/drivers/mtd/nand/spi/toshiba.c +@@ -15,10 +15,10 @@ + #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_x4_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index 8394a1b1fb0c12..397c90b745e3af 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -24,25 +24,25 @@ + */ + + static SPINAND_OP_VARIANTS(read_cache_dtr_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_DTR_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ), +- SPINAND_PAGE_READ_FROM_CACHE_X4_DTR_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_DTR_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ), +- SPINAND_PAGE_READ_FROM_CACHE_X2_DTR_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DTR_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)); + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/mtd/nand/spi/xtx.c b/drivers/mtd/nand/spi/xtx.c +index 3f539ca0de861c..abbbcd594c2c1f 100644 +--- a/drivers/mtd/nand/spi/xtx.c ++++ b/drivers/mtd/nand/spi/xtx.c +@@ -23,12 +23,12 @@ + #define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2) + + static SPINAND_OP_VARIANTS(read_cache_variants, +- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0), +- SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0)); ++ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0)); + + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), +diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c +index f6921368cd14e9..0071a51ce2c1b2 100644 +--- a/drivers/net/can/kvaser_pciefd.c ++++ b/drivers/net/can/kvaser_pciefd.c +@@ -966,7 +966,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) + u32 status, tx_nr_packets_max; + + netdev = alloc_candev(sizeof(struct kvaser_pciefd_can), +- KVASER_PCIEFD_CAN_TX_MAX_COUNT); ++ roundup_pow_of_two(KVASER_PCIEFD_CAN_TX_MAX_COUNT)); + if (!netdev) + return -ENOMEM; + +@@ -995,7 +995,6 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) + can->tx_max_count = min(KVASER_PCIEFD_CAN_TX_MAX_COUNT, tx_nr_packets_max - 1); + + can->can.clock.freq = pcie->freq; +- can->can.echo_skb_max = roundup_pow_of_two(can->tx_max_count); + spin_lock_init(&can->lock); + + can->can.bittiming_const = &kvaser_pciefd_bittiming_const; +diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c +index e5c162f8c589b2..8edaa339d590b6 100644 +--- a/drivers/net/can/m_can/tcan4x5x-core.c ++++ b/drivers/net/can/m_can/tcan4x5x-core.c +@@ -411,10 +411,11 @@ static int tcan4x5x_can_probe(struct spi_device *spi) + priv = cdev_to_priv(mcan_class); + + priv->power = devm_regulator_get_optional(&spi->dev, "vsup"); +- if (PTR_ERR(priv->power) == -EPROBE_DEFER) { +- ret = -EPROBE_DEFER; +- goto out_m_can_class_free_dev; +- } else { ++ if (IS_ERR(priv->power)) { ++ if (PTR_ERR(priv->power) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ goto out_m_can_class_free_dev; ++ } + priv->power = NULL; + } + +diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c +index c1d1673c5749d6..b565189e591398 100644 +--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c ++++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c +@@ -123,7 +123,6 @@ static netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *nd + } + #endif + +- skb_tx_timestamp(skb); + return aq_nic_xmit(aq_nic, skb); + } + +diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +index bf3aa46887a1c1..e71cd10e4e1f14 100644 +--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c ++++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +@@ -898,6 +898,8 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb) + + frags = aq_nic_map_skb(self, skb, ring); + ++ skb_tx_timestamp(skb); ++ + if (likely(frags)) { + err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw, + ring, frags); +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 6afc2ab6fad228..c365a9e64f7281 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -10738,6 +10738,72 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx, + bp->num_rss_ctx--; + } + ++static bool bnxt_vnic_has_rx_ring(struct bnxt *bp, struct bnxt_vnic_info *vnic, ++ int rxr_id) ++{ ++ u16 tbl_size = bnxt_get_rxfh_indir_size(bp->dev); ++ int i, vnic_rx; ++ ++ /* Ntuple VNIC always has all the rx rings. Any change of ring id ++ * must be updated because a future filter may use it. ++ */ ++ if (vnic->flags & BNXT_VNIC_NTUPLE_FLAG) ++ return true; ++ ++ for (i = 0; i < tbl_size; i++) { ++ if (vnic->flags & BNXT_VNIC_RSSCTX_FLAG) ++ vnic_rx = ethtool_rxfh_context_indir(vnic->rss_ctx)[i]; ++ else ++ vnic_rx = bp->rss_indir_tbl[i]; ++ ++ if (rxr_id == vnic_rx) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic, ++ u16 mru, int rxr_id) ++{ ++ int rc; ++ ++ if (!bnxt_vnic_has_rx_ring(bp, vnic, rxr_id)) ++ return 0; ++ ++ if (mru) { ++ rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true); ++ if (rc) { ++ netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n", ++ vnic->vnic_id, rc); ++ return rc; ++ } ++ } ++ vnic->mru = mru; ++ bnxt_hwrm_vnic_update(bp, vnic, ++ VNIC_UPDATE_REQ_ENABLES_MRU_VALID); ++ ++ return 0; ++} ++ ++static int bnxt_set_rss_ctx_vnic_mru(struct bnxt *bp, u16 mru, int rxr_id) ++{ ++ struct ethtool_rxfh_context *ctx; ++ unsigned long context; ++ int rc; ++ ++ xa_for_each(&bp->dev->ethtool->rss_ctx, context, ctx) { ++ struct bnxt_rss_ctx *rss_ctx = ethtool_rxfh_context_priv(ctx); ++ struct bnxt_vnic_info *vnic = &rss_ctx->vnic; ++ ++ rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, rxr_id); ++ if (rc) ++ return rc; ++ } ++ ++ return 0; ++} ++ + static void bnxt_hwrm_realloc_rss_ctx_vnic(struct bnxt *bp) + { + bool set_tpa = !!(bp->flags & BNXT_FLAG_TPA); +@@ -15884,6 +15950,7 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx) + struct bnxt_vnic_info *vnic; + struct bnxt_napi *bnapi; + int i, rc; ++ u16 mru; + + rxr = &bp->rx_ring[idx]; + clone = qmem; +@@ -15933,21 +16000,15 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx) + napi_enable_locked(&bnapi->napi); + bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons); + ++ mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN; + for (i = 0; i < bp->nr_vnics; i++) { + vnic = &bp->vnic_info[i]; + +- rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true); +- if (rc) { +- netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n", +- vnic->vnic_id, rc); ++ rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, idx); ++ if (rc) + return rc; +- } +- vnic->mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN; +- bnxt_hwrm_vnic_update(bp, vnic, +- VNIC_UPDATE_REQ_ENABLES_MRU_VALID); + } +- +- return 0; ++ return bnxt_set_rss_ctx_vnic_mru(bp, mru, idx); + + err_reset: + netdev_err(bp->dev, "Unexpected HWRM error during queue start rc: %d\n", +@@ -15969,10 +16030,10 @@ static int bnxt_queue_stop(struct net_device *dev, void *qmem, int idx) + + for (i = 0; i < bp->nr_vnics; i++) { + vnic = &bp->vnic_info[i]; +- vnic->mru = 0; +- bnxt_hwrm_vnic_update(bp, vnic, +- VNIC_UPDATE_REQ_ENABLES_MRU_VALID); ++ ++ bnxt_set_vnic_mru_p5(bp, vnic, 0, idx); + } ++ bnxt_set_rss_ctx_vnic_mru(bp, 0, idx); + /* Make sure NAPI sees that the VNIC is disabled */ + synchronize_net(); + rxr = &bp->rx_ring[idx]; +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +index 7564705d64783e..2450a369b79201 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +@@ -149,7 +149,6 @@ void bnxt_unregister_dev(struct bnxt_en_dev *edev) + struct net_device *dev = edev->net; + struct bnxt *bp = netdev_priv(dev); + struct bnxt_ulp *ulp; +- int i = 0; + + ulp = edev->ulp_tbl; + netdev_lock(dev); +@@ -165,10 +164,6 @@ void bnxt_unregister_dev(struct bnxt_en_dev *edev) + synchronize_rcu(); + ulp->max_async_event_id = 0; + ulp->async_events_bmap = NULL; +- while (atomic_read(&ulp->ref_count) != 0 && i < 10) { +- msleep(100); +- i++; +- } + mutex_unlock(&edev->en_dev_lock); + netdev_unlock(dev); + return; +@@ -236,10 +231,9 @@ void bnxt_ulp_stop(struct bnxt *bp) + return; + + mutex_lock(&edev->en_dev_lock); +- if (!bnxt_ulp_registered(edev)) { +- mutex_unlock(&edev->en_dev_lock); +- return; +- } ++ if (!bnxt_ulp_registered(edev) || ++ (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) ++ goto ulp_stop_exit; + + edev->flags |= BNXT_EN_FLAG_ULP_STOPPED; + if (aux_priv) { +@@ -255,6 +249,7 @@ void bnxt_ulp_stop(struct bnxt *bp) + adrv->suspend(adev, pm); + } + } ++ulp_stop_exit: + mutex_unlock(&edev->en_dev_lock); + } + +@@ -263,19 +258,13 @@ void bnxt_ulp_start(struct bnxt *bp, int err) + struct bnxt_aux_priv *aux_priv = bp->aux_priv; + struct bnxt_en_dev *edev = bp->edev; + +- if (!edev) +- return; +- +- edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED; +- +- if (err) ++ if (!edev || err) + return; + + mutex_lock(&edev->en_dev_lock); +- if (!bnxt_ulp_registered(edev)) { +- mutex_unlock(&edev->en_dev_lock); +- return; +- } ++ if (!bnxt_ulp_registered(edev) || ++ !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) ++ goto ulp_start_exit; + + if (edev->ulp_tbl->msix_requested) + bnxt_fill_msix_vecs(bp, edev->msix_entries); +@@ -292,6 +281,8 @@ void bnxt_ulp_start(struct bnxt *bp, int err) + adrv->resume(adev); + } + } ++ulp_start_exit: ++ edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED; + mutex_unlock(&edev->en_dev_lock); + } + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +index 7fa3b8d1ebd288..f6b5efb5e77535 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +@@ -50,7 +50,6 @@ struct bnxt_ulp { + unsigned long *async_events_bmap; + u16 max_async_event_id; + u16 msix_requested; +- atomic_t ref_count; + }; + + struct bnxt_en_dev { +diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c +index e1e8bd2ec155b8..d1f1ae5ea161cc 100644 +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -5283,7 +5283,11 @@ static int macb_probe(struct platform_device *pdev) + + #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { +- dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); ++ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); ++ if (err) { ++ dev_err(&pdev->dev, "failed to set DMA mask\n"); ++ goto err_out_free_netdev; ++ } + bp->hw_dma_cap |= HW_DMA_CAP_64B; + } + #endif +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 517a15904fb085..6a2004bbe87f93 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1144,6 +1144,7 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb, + struct gmac_txdesc *txd; + skb_frag_t *skb_frag; + dma_addr_t mapping; ++ bool tcp = false; + void *buffer; + u16 mss; + int ret; +@@ -1151,6 +1152,13 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb, + word1 = skb->len; + word3 = SOF_BIT; + ++ /* Determine if we are doing TCP */ ++ if (skb->protocol == htons(ETH_P_IP)) ++ tcp = (ip_hdr(skb)->protocol == IPPROTO_TCP); ++ else ++ /* IPv6 */ ++ tcp = (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP); ++ + mss = skb_shinfo(skb)->gso_size; + if (mss) { + /* This means we are dealing with TCP and skb->len is the +@@ -1163,8 +1171,26 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb, + mss, skb->len); + word1 |= TSS_MTU_ENABLE_BIT; + word3 |= mss; ++ } else if (tcp) { ++ /* Even if we are not using TSO, use the hardware offloader ++ * for transferring the TCP frame: this hardware has partial ++ * TCP awareness (called TOE - TCP Offload Engine) and will ++ * according to the datasheet put packets belonging to the ++ * same TCP connection in the same queue for the TOE/TSO ++ * engine to process. The engine will deal with chopping ++ * up frames that exceed ETH_DATA_LEN which the ++ * checksumming engine cannot handle (see below) into ++ * manageable chunks. It flawlessly deals with quite big ++ * frames and frames containing custom DSA EtherTypes. ++ */ ++ mss = netdev->mtu + skb_tcp_all_headers(skb); ++ mss = min(mss, skb->len); ++ netdev_dbg(netdev, "TOE/TSO len %04x mtu %04x mss %04x\n", ++ skb->len, netdev->mtu, mss); ++ word1 |= TSS_MTU_ENABLE_BIT; ++ word3 |= mss; + } else if (skb->len >= ETH_FRAME_LEN) { +- /* Hardware offloaded checksumming isn't working on frames ++ /* Hardware offloaded checksumming isn't working on non-TCP frames + * bigger than 1514 bytes. A hypothesis about this is that the + * checksum buffer is only 1518 bytes, so when the frames get + * bigger they get truncated, or the last few bytes get +@@ -1181,21 +1207,16 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb, + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { +- int tcp = 0; +- + /* We do not switch off the checksumming on non TCP/UDP + * frames: as is shown from tests, the checksumming engine + * is smart enough to see that a frame is not actually TCP + * or UDP and then just pass it through without any changes + * to the frame. + */ +- if (skb->protocol == htons(ETH_P_IP)) { ++ if (skb->protocol == htons(ETH_P_IP)) + word1 |= TSS_IP_CHKSUM_BIT; +- tcp = ip_hdr(skb)->protocol == IPPROTO_TCP; +- } else { /* IPv6 */ ++ else + word1 |= TSS_IPV6_ENABLE_BIT; +- tcp = ipv6_hdr(skb)->nexthdr == IPPROTO_TCP; +- } + + word1 |= tcp ? TSS_TCP_CHKSUM_BIT : TSS_UDP_CHKSUM_BIT; + } +diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c +index 232e839a9d0719..038a0400c1f956 100644 +--- a/drivers/net/ethernet/dlink/dl2k.c ++++ b/drivers/net/ethernet/dlink/dl2k.c +@@ -146,6 +146,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) + np->ioaddr = ioaddr; + np->chip_id = chip_idx; + np->pdev = pdev; ++ ++ spin_lock_init(&np->stats_lock); + spin_lock_init (&np->tx_lock); + spin_lock_init (&np->rx_lock); + +@@ -865,7 +867,6 @@ tx_error (struct net_device *dev, int tx_status) + frame_id = (tx_status & 0xffff0000); + printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n", + dev->name, tx_status, frame_id); +- dev->stats.tx_errors++; + /* Ttransmit Underrun */ + if (tx_status & 0x10) { + dev->stats.tx_fifo_errors++; +@@ -902,9 +903,15 @@ tx_error (struct net_device *dev, int tx_status) + rio_set_led_mode(dev); + /* Let TxStartThresh stay default value */ + } ++ ++ spin_lock(&np->stats_lock); + /* Maximum Collisions */ + if (tx_status & 0x08) + dev->stats.collisions++; ++ ++ dev->stats.tx_errors++; ++ spin_unlock(&np->stats_lock); ++ + /* Restart the Tx */ + dw32(MACCtrl, dr16(MACCtrl) | TxEnable); + } +@@ -1073,7 +1080,9 @@ get_stats (struct net_device *dev) + int i; + #endif + unsigned int stat_reg; ++ unsigned long flags; + ++ spin_lock_irqsave(&np->stats_lock, flags); + /* All statistics registers need to be acknowledged, + else statistic overflow could cause problems */ + +@@ -1123,6 +1132,9 @@ get_stats (struct net_device *dev) + dr16(TCPCheckSumErrors); + dr16(UDPCheckSumErrors); + dr16(IPCheckSumErrors); ++ ++ spin_unlock_irqrestore(&np->stats_lock, flags); ++ + return &dev->stats; + } + +diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h +index 0e33e2eaae9606..56aff2f0bdbfa0 100644 +--- a/drivers/net/ethernet/dlink/dl2k.h ++++ b/drivers/net/ethernet/dlink/dl2k.h +@@ -372,6 +372,8 @@ struct netdev_private { + struct pci_dev *pdev; + void __iomem *ioaddr; + void __iomem *eeprom_addr; ++ // To ensure synchronization when stats are updated. ++ spinlock_t stats_lock; + spinlock_t tx_lock; + spinlock_t rx_lock; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 51b8377edd1d04..a89aa4ac0a064a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1609,7 +1609,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) + /* version 1 of the cmd is not supported only by BE2 */ + if (BE2_chip(adapter)) + hdr->version = 0; +- if (BE3_chip(adapter) || lancer_chip(adapter)) ++ else if (BE3_chip(adapter) || lancer_chip(adapter)) + hdr->version = 1; + else + hdr->version = 2; +diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig +index c699bd6bcbb938..474073c7f94d74 100644 +--- a/drivers/net/ethernet/faraday/Kconfig ++++ b/drivers/net/ethernet/faraday/Kconfig +@@ -31,6 +31,7 @@ config FTGMAC100 + depends on ARM || COMPILE_TEST + depends on !64BIT || BROKEN + select PHYLIB ++ select FIXED_PHY + select MDIO_ASPEED if MACH_ASPEED_G6 + select CRC32 + help +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 8ebcb6a7d608ae..a0045aa9550b59 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -3534,9 +3534,6 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) + case e1000_pch_cnp: + case e1000_pch_tgp: + case e1000_pch_adp: +- case e1000_pch_mtp: +- case e1000_pch_lnp: +- case e1000_pch_ptp: + case e1000_pch_nvp: + if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { + /* Stable 24MHz frequency */ +@@ -3552,6 +3549,17 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) + adapter->cc.shift = shift; + } + break; ++ case e1000_pch_mtp: ++ case e1000_pch_lnp: ++ case e1000_pch_ptp: ++ /* System firmware can misreport this value, so set it to a ++ * stable 38400KHz frequency. ++ */ ++ incperiod = INCPERIOD_38400KHZ; ++ incvalue = INCVALUE_38400KHZ; ++ shift = INCVALUE_SHIFT_38400KHZ; ++ adapter->cc.shift = shift; ++ break; + case e1000_82574: + case e1000_82583: + /* Stable 25MHz frequency */ +diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c +index 89d57dd911dc89..ea3c3eb2ef2020 100644 +--- a/drivers/net/ethernet/intel/e1000e/ptp.c ++++ b/drivers/net/ethernet/intel/e1000e/ptp.c +@@ -295,15 +295,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) + case e1000_pch_cnp: + case e1000_pch_tgp: + case e1000_pch_adp: +- case e1000_pch_mtp: +- case e1000_pch_lnp: +- case e1000_pch_ptp: + case e1000_pch_nvp: + if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) + adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ; + else + adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ; + break; ++ case e1000_pch_mtp: ++ case e1000_pch_lnp: ++ case e1000_pch_ptp: ++ adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ; ++ break; + case e1000_82574: + case e1000_82583: + adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ; +diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c +index 370b4bddee4419..b11c35e307ca96 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_common.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_common.c +@@ -817,10 +817,11 @@ int i40e_pf_reset(struct i40e_hw *hw) + void i40e_clear_hw(struct i40e_hw *hw) + { + u32 num_queues, base_queue; +- u32 num_pf_int; +- u32 num_vf_int; ++ s32 num_pf_int; ++ s32 num_vf_int; + u32 num_vfs; +- u32 i, j; ++ s32 i; ++ u32 j; + u32 val; + u32 eol = 0x7ff; + +diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c +index 2bc5c7f598444d..1f7834c0355027 100644 +--- a/drivers/net/ethernet/intel/ice/ice_arfs.c ++++ b/drivers/net/ethernet/intel/ice/ice_arfs.c +@@ -377,6 +377,50 @@ ice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto) + return false; + } + ++/** ++ * ice_arfs_cmp - Check if aRFS filter matches this flow. ++ * @fltr_info: filter info of the saved ARFS entry. ++ * @fk: flow dissector keys. ++ * @n_proto: One of htons(ETH_P_IP) or htons(ETH_P_IPV6). ++ * @ip_proto: One of IPPROTO_TCP or IPPROTO_UDP. ++ * ++ * Since this function assumes limited values for n_proto and ip_proto, it ++ * is meant to be called only from ice_rx_flow_steer(). ++ * ++ * Return: ++ * * true - fltr_info refers to the same flow as fk. ++ * * false - fltr_info and fk refer to different flows. ++ */ ++static bool ++ice_arfs_cmp(const struct ice_fdir_fltr *fltr_info, const struct flow_keys *fk, ++ __be16 n_proto, u8 ip_proto) ++{ ++ /* Determine if the filter is for IPv4 or IPv6 based on flow_type, ++ * which is one of ICE_FLTR_PTYPE_NONF_IPV{4,6}_{TCP,UDP}. ++ */ ++ bool is_v4 = fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP || ++ fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP; ++ ++ /* Following checks are arranged in the quickest and most discriminative ++ * fields first for early failure. ++ */ ++ if (is_v4) ++ return n_proto == htons(ETH_P_IP) && ++ fltr_info->ip.v4.src_port == fk->ports.src && ++ fltr_info->ip.v4.dst_port == fk->ports.dst && ++ fltr_info->ip.v4.src_ip == fk->addrs.v4addrs.src && ++ fltr_info->ip.v4.dst_ip == fk->addrs.v4addrs.dst && ++ fltr_info->ip.v4.proto == ip_proto; ++ ++ return fltr_info->ip.v6.src_port == fk->ports.src && ++ fltr_info->ip.v6.dst_port == fk->ports.dst && ++ fltr_info->ip.v6.proto == ip_proto && ++ !memcmp(&fltr_info->ip.v6.src_ip, &fk->addrs.v6addrs.src, ++ sizeof(struct in6_addr)) && ++ !memcmp(&fltr_info->ip.v6.dst_ip, &fk->addrs.v6addrs.dst, ++ sizeof(struct in6_addr)); ++} ++ + /** + * ice_rx_flow_steer - steer the Rx flow to where application is being run + * @netdev: ptr to the netdev being adjusted +@@ -448,6 +492,10 @@ ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb, + continue; + + fltr_info = &arfs_entry->fltr_info; ++ ++ if (!ice_arfs_cmp(fltr_info, &fk, n_proto, ip_proto)) ++ continue; ++ + ret = fltr_info->fltr_id; + + if (fltr_info->q_index == rxq_idx || +diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c +index ed21d7f55ac11b..5b9a7ee278f17b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c ++++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c +@@ -502,10 +502,14 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_repr *repr, unsigned long *id) + */ + int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf) + { +- struct ice_repr *repr = ice_repr_create_vf(vf); + struct devlink *devlink = priv_to_devlink(pf); ++ struct ice_repr *repr; + int err; + ++ if (!ice_is_eswitch_mode_switchdev(pf)) ++ return 0; ++ ++ repr = ice_repr_create_vf(vf); + if (IS_ERR(repr)) + return PTR_ERR(repr); + +diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c +index 4a91e0aaf0a5e5..9d9a7edd3618af 100644 +--- a/drivers/net/ethernet/intel/ice/ice_switch.c ++++ b/drivers/net/ethernet/intel/ice/ice_switch.c +@@ -3146,7 +3146,7 @@ ice_add_update_vsi_list(struct ice_hw *hw, + u16 vsi_handle_arr[2]; + + /* A rule already exists with the new VSI being added */ +- if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) ++ if (cur_fltr->vsi_handle == new_fltr->vsi_handle) + return -EEXIST; + + vsi_handle_arr[0] = cur_fltr->vsi_handle; +@@ -5978,7 +5978,7 @@ ice_adv_add_update_vsi_list(struct ice_hw *hw, + + /* A rule already exists with the new VSI being added */ + if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) +- return 0; ++ return -EEXIST; + + /* Update the previously created VSI list set with + * the new VSI ID passed in +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +index 0a03a8bb5f8869..2d54828bdfbbcc 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +@@ -167,7 +167,7 @@ int ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, + u16 reg, u16 val, bool lock) + { + u32 swfw_mask = hw->phy.phy_semaphore_mask; +- int max_retry = 1; ++ int max_retry = 3; + int retry = 0; + u8 reg_high; + u8 csum; +@@ -2285,7 +2285,7 @@ static int ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 data, bool lock) + { + u32 swfw_mask = hw->phy.phy_semaphore_mask; +- u32 max_retry = 1; ++ u32 max_retry = 3; + u32 retry = 0; + int status; + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c +index c3b6e0f60a7998..7f6a435ac68069 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c +@@ -357,9 +357,12 @@ int cn10k_free_matchall_ipolicer(struct otx2_nic *pfvf) + mutex_lock(&pfvf->mbox.lock); + + /* Remove RQ's policer mapping */ +- for (qidx = 0; qidx < hw->rx_queues; qidx++) +- cn10k_map_unmap_rq_policer(pfvf, qidx, +- hw->matchall_ipolicer, false); ++ for (qidx = 0; qidx < hw->rx_queues; qidx++) { ++ rc = cn10k_map_unmap_rq_policer(pfvf, qidx, hw->matchall_ipolicer, false); ++ if (rc) ++ dev_warn(pfvf->dev, "Failed to unmap RQ %d's policer (error %d).", ++ qidx, rc); ++ } + + rc = cn10k_free_leaf_profile(pfvf, hw->matchall_ipolicer); + +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +index 84cd029a85aab7..1b3004ba4493ed 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -1822,7 +1822,7 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable) + req->chan_cnt = IEEE_8021QAZ_MAX_TCS; + req->bpid_per_chan = 1; + } else { +- req->chan_cnt = 1; ++ req->chan_cnt = pfvf->hw.rx_chan_cnt; + req->bpid_per_chan = 0; + } + +@@ -1847,7 +1847,7 @@ int otx2_nix_cpt_config_bp(struct otx2_nic *pfvf, bool enable) + req->chan_cnt = IEEE_8021QAZ_MAX_TCS; + req->bpid_per_chan = 1; + } else { +- req->chan_cnt = 1; ++ req->chan_cnt = pfvf->hw.rx_chan_cnt; + req->bpid_per_chan = 0; + } + +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +index cd17a3f4faf83e..a68cd3f0304c64 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +@@ -1897,6 +1897,7 @@ static int mlx4_en_get_ts_info(struct net_device *dev, + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) { + info->so_timestamping |= + SOF_TIMESTAMPING_TX_HARDWARE | ++ SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +index 32de8bfc7644f5..3f8f4306d90b38 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +@@ -329,16 +329,12 @@ static void hws_bwc_rule_list_add(struct mlx5hws_bwc_rule *bwc_rule, u16 idx) + { + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + +- atomic_inc(&bwc_matcher->num_of_rules); + bwc_rule->bwc_queue_idx = idx; + list_add(&bwc_rule->list_node, &bwc_matcher->rules[idx]); + } + + static void hws_bwc_rule_list_remove(struct mlx5hws_bwc_rule *bwc_rule) + { +- struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; +- +- atomic_dec(&bwc_matcher->num_of_rules); + list_del_init(&bwc_rule->list_node); + } + +@@ -391,6 +387,7 @@ int mlx5hws_bwc_rule_destroy_simple(struct mlx5hws_bwc_rule *bwc_rule) + mutex_lock(queue_lock); + + ret = hws_bwc_rule_destroy_hws_sync(bwc_rule, &attr); ++ atomic_dec(&bwc_matcher->num_of_rules); + hws_bwc_rule_list_remove(bwc_rule); + + mutex_unlock(queue_lock); +@@ -860,7 +857,7 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + } + + /* check if number of rules require rehash */ +- num_of_rules = atomic_read(&bwc_matcher->num_of_rules); ++ num_of_rules = atomic_inc_return(&bwc_matcher->num_of_rules); + + if (unlikely(hws_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))) { + mutex_unlock(queue_lock); +@@ -874,6 +871,7 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + bwc_matcher->size_log - MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP, + bwc_matcher->size_log, + ret); ++ atomic_dec(&bwc_matcher->num_of_rules); + return ret; + } + +@@ -906,6 +904,7 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + + if (ret) { + mlx5hws_err(ctx, "BWC rule insertion: rehash failed (%d)\n", ret); ++ atomic_dec(&bwc_matcher->num_of_rules); + return ret; + } + +@@ -921,6 +920,7 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + if (unlikely(ret)) { + mutex_unlock(queue_lock); + mlx5hws_err(ctx, "BWC rule insertion failed (%d)\n", ret); ++ atomic_dec(&bwc_matcher->num_of_rules); + return ret; + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c +index 293459458cc5f9..ecda35597111ea 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c +@@ -509,7 +509,7 @@ static int + hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) + { +- bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; ++ bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + u32 *s_ipv6, *d_ipv6; +@@ -521,6 +521,20 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + return -EINVAL; + } + ++ ip_addr_set = HWS_IS_FLD_SET_SZ(match_param, ++ outer_headers.src_ipv4_src_ipv6, ++ 0x80) || ++ HWS_IS_FLD_SET_SZ(match_param, ++ outer_headers.dst_ipv4_dst_ipv6, 0x80); ++ ip_ver_set = HWS_IS_FLD_SET(match_param, outer_headers.ip_version) || ++ HWS_IS_FLD_SET(match_param, outer_headers.ethertype); ++ ++ if (ip_addr_set && !ip_ver_set) { ++ mlx5hws_err(cd->ctx, ++ "Unsupported match on IP address without version or ethertype\n"); ++ return -EINVAL; ++ } ++ + /* L2 Check ethertype */ + HWS_SET_HDR(fc, match_param, ETH_TYPE_O, + outer_headers.ethertype, +@@ -573,10 +587,16 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + outer_headers.dst_ipv4_dst_ipv6.ipv6_layout); + + /* Assume IPv6 is used if ipv6 bits are set */ +- is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; +- is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; ++ is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] || ++ d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; + +- if (is_s_ipv6) { ++ /* IHL is an IPv4-specific field. */ ++ if (is_ipv6 && HWS_IS_FLD_SET(match_param, outer_headers.ipv4_ihl)) { ++ mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n"); ++ return -EINVAL; ++ } ++ ++ if (is_ipv6) { + /* Handle IPv6 source address */ + HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, +@@ -590,13 +610,6 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_src_outer.ipv6_address_31_0); +- } else { +- /* Handle IPv4 source address */ +- HWS_SET_HDR(fc, match_param, IPV4_SRC_O, +- outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, +- ipv4_src_dest_outer.source_address); +- } +- if (is_d_ipv6) { + /* Handle IPv6 destination address */ + HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, +@@ -611,6 +624,10 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_dst_outer.ipv6_address_31_0); + } else { ++ /* Handle IPv4 source address */ ++ HWS_SET_HDR(fc, match_param, IPV4_SRC_O, ++ outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, ++ ipv4_src_dest_outer.source_address); + /* Handle IPv4 destination address */ + HWS_SET_HDR(fc, match_param, IPV4_DST_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, +@@ -668,7 +685,7 @@ static int + hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) + { +- bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; ++ bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + u32 *s_ipv6, *d_ipv6; +@@ -680,6 +697,20 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + return -EINVAL; + } + ++ ip_addr_set = HWS_IS_FLD_SET_SZ(match_param, ++ inner_headers.src_ipv4_src_ipv6, ++ 0x80) || ++ HWS_IS_FLD_SET_SZ(match_param, ++ inner_headers.dst_ipv4_dst_ipv6, 0x80); ++ ip_ver_set = HWS_IS_FLD_SET(match_param, inner_headers.ip_version) || ++ HWS_IS_FLD_SET(match_param, inner_headers.ethertype); ++ ++ if (ip_addr_set && !ip_ver_set) { ++ mlx5hws_err(cd->ctx, ++ "Unsupported match on IP address without version or ethertype\n"); ++ return -EINVAL; ++ } ++ + /* L2 Check ethertype */ + HWS_SET_HDR(fc, match_param, ETH_TYPE_I, + inner_headers.ethertype, +@@ -731,10 +762,16 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + inner_headers.dst_ipv4_dst_ipv6.ipv6_layout); + + /* Assume IPv6 is used if ipv6 bits are set */ +- is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; +- is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; ++ is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] || ++ d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; + +- if (is_s_ipv6) { ++ /* IHL is an IPv4-specific field. */ ++ if (is_ipv6 && HWS_IS_FLD_SET(match_param, inner_headers.ipv4_ihl)) { ++ mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n"); ++ return -EINVAL; ++ } ++ ++ if (is_ipv6) { + /* Handle IPv6 source address */ + HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, +@@ -748,13 +785,6 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_src_inner.ipv6_address_31_0); +- } else { +- /* Handle IPv4 source address */ +- HWS_SET_HDR(fc, match_param, IPV4_SRC_I, +- inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, +- ipv4_src_dest_inner.source_address); +- } +- if (is_d_ipv6) { + /* Handle IPv6 destination address */ + HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, +@@ -769,6 +799,10 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_dst_inner.ipv6_address_31_0); + } else { ++ /* Handle IPv4 source address */ ++ HWS_SET_HDR(fc, match_param, IPV4_SRC_I, ++ inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, ++ ipv4_src_dest_inner.source_address); + /* Handle IPv4 destination address */ + HWS_SET_HDR(fc, match_param, IPV4_DST_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +index d10d4c39604085..da5c24fc7b30ab 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +@@ -465,19 +465,22 @@ int mlx5_query_nic_vport_node_guid(struct mlx5_core_dev *mdev, u64 *node_guid) + { + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); ++ int err; + + out = kvzalloc(outlen, GFP_KERNEL); + if (!out) + return -ENOMEM; + +- mlx5_query_nic_vport_context(mdev, 0, out); ++ err = mlx5_query_nic_vport_context(mdev, 0, out); ++ if (err) ++ goto out; + + *node_guid = MLX5_GET64(query_nic_vport_context_out, out, + nic_vport_context.node_guid); +- ++out: + kvfree(out); + +- return 0; ++ return err; + } + EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_node_guid); + +@@ -519,19 +522,22 @@ int mlx5_query_nic_vport_qkey_viol_cntr(struct mlx5_core_dev *mdev, + { + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); ++ int err; + + out = kvzalloc(outlen, GFP_KERNEL); + if (!out) + return -ENOMEM; + +- mlx5_query_nic_vport_context(mdev, 0, out); ++ err = mlx5_query_nic_vport_context(mdev, 0, out); ++ if (err) ++ goto out; + + *qkey_viol_cntr = MLX5_GET(query_nic_vport_context_out, out, + nic_vport_context.qkey_violation_counter); +- ++out: + kvfree(out); + +- return 0; ++ return err; + } + EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_qkey_viol_cntr); + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index fb2e5b844c150d..d76d7a945899c6 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -447,8 +447,10 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); + + phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0); +- if (phy_irq < 0) { +- dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead"); ++ if (phy_irq == -EPROBE_DEFER) { ++ err = -EPROBE_DEFER; ++ goto out; ++ } else if (phy_irq < 0) { + phy_irq = PHY_POLL; + } + +diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +index 3d9636a6c968ec..0c3985613ea181 100644 +--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c ++++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +@@ -127,11 +127,8 @@ static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx, + return -EBUSY; + + addr = dma_map_single(fbd->dev, msg, PAGE_SIZE, direction); +- if (dma_mapping_error(fbd->dev, addr)) { +- free_page((unsigned long)msg); +- ++ if (dma_mapping_error(fbd->dev, addr)) + return -ENOSPC; +- } + + mbx->buf_info[tail].msg = msg; + mbx->buf_info[tail].addr = addr; +diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c +index 1459acfb1e618b..64a3b953cc175d 100644 +--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c ++++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c +@@ -18,6 +18,8 @@ + #define EEPROM_MAC_OFFSET (0x01) + #define MAX_EEPROM_SIZE (512) + #define MAX_OTP_SIZE (1024) ++#define MAX_HS_OTP_SIZE (8 * 1024) ++#define MAX_HS_EEPROM_SIZE (64 * 1024) + #define OTP_INDICATOR_1 (0xF3) + #define OTP_INDICATOR_2 (0xF7) + +@@ -272,6 +274,9 @@ static int lan743x_hs_otp_read(struct lan743x_adapter *adapter, u32 offset, + int ret; + int i; + ++ if (offset + length > MAX_HS_OTP_SIZE) ++ return -EINVAL; ++ + ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); + if (ret < 0) + return ret; +@@ -320,6 +325,9 @@ static int lan743x_hs_otp_write(struct lan743x_adapter *adapter, u32 offset, + int ret; + int i; + ++ if (offset + length > MAX_HS_OTP_SIZE) ++ return -EINVAL; ++ + ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); + if (ret < 0) + return ret; +@@ -497,6 +505,9 @@ static int lan743x_hs_eeprom_read(struct lan743x_adapter *adapter, + u32 val; + int i; + ++ if (offset + length > MAX_HS_EEPROM_SIZE) ++ return -EINVAL; ++ + retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); + if (retval < 0) + return retval; +@@ -539,6 +550,9 @@ static int lan743x_hs_eeprom_write(struct lan743x_adapter *adapter, + u32 val; + int i; + ++ if (offset + length > MAX_HS_EEPROM_SIZE) ++ return -EINVAL; ++ + retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); + if (retval < 0) + return retval; +@@ -604,9 +618,9 @@ static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev) + struct lan743x_adapter *adapter = netdev_priv(netdev); + + if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) +- return MAX_OTP_SIZE; ++ return adapter->is_pci11x1x ? MAX_HS_OTP_SIZE : MAX_OTP_SIZE; + +- return MAX_EEPROM_SIZE; ++ return adapter->is_pci11x1x ? MAX_HS_EEPROM_SIZE : MAX_EEPROM_SIZE; + } + + static int lan743x_ethtool_get_eeprom(struct net_device *netdev, +diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h +index 0d29914cd46063..225e8232474d73 100644 +--- a/drivers/net/ethernet/microchip/lan743x_ptp.h ++++ b/drivers/net/ethernet/microchip/lan743x_ptp.h +@@ -18,9 +18,9 @@ + */ + #define LAN743X_PTP_N_EVENT_CHAN 2 + #define LAN743X_PTP_N_PEROUT LAN743X_PTP_N_EVENT_CHAN +-#define LAN743X_PTP_N_EXTTS 4 +-#define LAN743X_PTP_N_PPS 0 + #define PCI11X1X_PTP_IO_MAX_CHANNELS 8 ++#define LAN743X_PTP_N_EXTTS PCI11X1X_PTP_IO_MAX_CHANNELS ++#define LAN743X_PTP_N_PPS 0 + #define PTP_CMD_CTL_TIMEOUT_CNT 50 + + struct lan743x_adapter; +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c +index daf1e82cb76b34..0e60a6bef99a3e 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c +@@ -516,9 +516,9 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds, + unsigned long start_time; + unsigned long max_wait; + unsigned long duration; +- int done = 0; + bool fw_up; + int opcode; ++ bool done; + int err; + + /* Wait for dev cmd to complete, retrying if we get EAGAIN, +@@ -526,6 +526,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds, + */ + max_wait = jiffies + (max_seconds * HZ); + try_again: ++ done = false; + opcode = idev->opcode; + start_time = jiffies; + for (fw_up = ionic_is_fw_running(idev); +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 3a049a158ea111..1d716cee0cb108 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -4493,8 +4493,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) + if (priv->sarc_type) + stmmac_set_desc_sarc(priv, first, priv->sarc_type); + +- skb_tx_timestamp(skb); +- + if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en)) { + /* declare that device is doing timestamping */ +@@ -4527,6 +4525,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) + } + + netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len); ++ skb_tx_timestamp(skb); + + stmmac_flush_tx_descriptors(priv, queue); + stmmac_tx_timer_arm(priv, queue); +@@ -4770,8 +4769,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) + if (priv->sarc_type) + stmmac_set_desc_sarc(priv, first, priv->sarc_type); + +- skb_tx_timestamp(skb); +- + /* Ready to fill the first descriptor and set the OWN bit w/o any + * problems because all the descriptors are actually ready to be + * passed to the DMA engine. +@@ -4818,7 +4815,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) + netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len); + + stmmac_enable_dma_transmission(priv, priv->ioaddr, queue); +- ++ skb_tx_timestamp(skb); + stmmac_flush_tx_descriptors(priv, queue); + stmmac_tx_timer_arm(priv, queue); + +diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +index 30665ffe78cf91..4cec05e0e3d9bb 100644 +--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c ++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c +@@ -2679,7 +2679,9 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) + goto of_node_put; + + ret = of_get_mac_address(port_np, port->slave.mac_addr); +- if (ret) { ++ if (ret == -EPROBE_DEFER) { ++ goto of_node_put; ++ } else if (ret) { + am65_cpsw_am654_get_efuse_macid(port_np, + port->port_id, + port->slave.mac_addr); +@@ -3561,6 +3563,16 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) + return ret; + } + ++ am65_cpsw_nuss_get_ver(common); ++ ++ ret = am65_cpsw_nuss_init_host_p(common); ++ if (ret) ++ goto err_pm_clear; ++ ++ ret = am65_cpsw_nuss_init_slave_ports(common); ++ if (ret) ++ goto err_pm_clear; ++ + node = of_get_child_by_name(dev->of_node, "mdio"); + if (!node) { + dev_warn(dev, "MDIO node not found\n"); +@@ -3577,16 +3589,6 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) + } + of_node_put(node); + +- am65_cpsw_nuss_get_ver(common); +- +- ret = am65_cpsw_nuss_init_host_p(common); +- if (ret) +- goto err_of_clear; +- +- ret = am65_cpsw_nuss_init_slave_ports(common); +- if (ret) +- goto err_of_clear; +- + /* init common data */ + ale_params.dev = dev; + ale_params.ale_ageout = AM65_CPSW_ALE_AGEOUT_DEFAULT; +diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c +index d88a0180294e0f..7ae069e7af92ba 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_common.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_common.c +@@ -98,20 +98,11 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn, + { + struct cppi5_host_desc_t *first_desc, *next_desc; + dma_addr_t buf_dma, next_desc_dma; +- struct prueth_swdata *swdata; +- struct page *page; + u32 buf_dma_len; + + first_desc = desc; + next_desc = first_desc; + +- swdata = cppi5_hdesc_get_swdata(desc); +- if (swdata->type == PRUETH_SWDATA_PAGE) { +- page = swdata->data.page; +- page_pool_recycle_direct(page->pp, swdata->data.page); +- goto free_desc; +- } +- + cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); + k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); + +@@ -135,7 +126,6 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn, + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + } + +-free_desc: + k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); + } + EXPORT_SYMBOL_GPL(prueth_xmit_free); +@@ -612,13 +602,8 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac, + k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); + cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len); + swdata = cppi5_hdesc_get_swdata(first_desc); +- if (page) { +- swdata->type = PRUETH_SWDATA_PAGE; +- swdata->data.page = page; +- } else { +- swdata->type = PRUETH_SWDATA_XDPF; +- swdata->data.xdpf = xdpf; +- } ++ swdata->type = PRUETH_SWDATA_XDPF; ++ swdata->data.xdpf = xdpf; + + /* Report BQL before sending the packet */ + netif_txq = netdev_get_tx_queue(ndev, tx_chn->id); +diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c +index e4d993f3137407..545177e84c0eba 100644 +--- a/drivers/net/ethernet/vertexcom/mse102x.c ++++ b/drivers/net/ethernet/vertexcom/mse102x.c +@@ -306,7 +306,7 @@ static void mse102x_dump_packet(const char *msg, int len, const char *data) + data, len, true); + } + +-static void mse102x_rx_pkt_spi(struct mse102x_net *mse) ++static irqreturn_t mse102x_rx_pkt_spi(struct mse102x_net *mse) + { + struct sk_buff *skb; + unsigned int rxalign; +@@ -327,7 +327,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + mse102x_tx_cmd_spi(mse, CMD_CTR); + ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx); + if (ret) +- return; ++ return IRQ_NONE; + + cmd_resp = be16_to_cpu(rx); + if ((cmd_resp & CMD_MASK) != CMD_RTS) { +@@ -360,7 +360,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4); + skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign); + if (!skb) +- return; ++ return IRQ_NONE; + + /* 2 bytes Start of frame (before ethernet header) + * 2 bytes Data frame tail (after ethernet frame) +@@ -370,7 +370,7 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + if (mse102x_rx_frame_spi(mse, rxpkt, rxlen, drop)) { + mse->ndev->stats.rx_errors++; + dev_kfree_skb(skb); +- return; ++ return IRQ_HANDLED; + } + + if (netif_msg_pktdata(mse)) +@@ -381,6 +381,8 @@ static void mse102x_rx_pkt_spi(struct mse102x_net *mse) + + mse->ndev->stats.rx_packets++; + mse->ndev->stats.rx_bytes += rxlen; ++ ++ return IRQ_HANDLED; + } + + static int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb, +@@ -512,12 +514,13 @@ static irqreturn_t mse102x_irq(int irq, void *_mse) + { + struct mse102x_net *mse = _mse; + struct mse102x_net_spi *mses = to_mse102x_spi(mse); ++ irqreturn_t ret; + + mutex_lock(&mses->lock); +- mse102x_rx_pkt_spi(mse); ++ ret = mse102x_rx_pkt_spi(mse); + mutex_unlock(&mses->lock); + +- return IRQ_HANDLED; ++ return ret; + } + + static int mse102x_net_open(struct net_device *ndev) +diff --git a/drivers/net/hyperv/netvsc_bpf.c b/drivers/net/hyperv/netvsc_bpf.c +index e01c5997a551c6..1dd3755d9e6df3 100644 +--- a/drivers/net/hyperv/netvsc_bpf.c ++++ b/drivers/net/hyperv/netvsc_bpf.c +@@ -183,7 +183,7 @@ int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog) + xdp.command = XDP_SETUP_PROG; + xdp.prog = prog; + +- ret = dev_xdp_propagate(vf_netdev, &xdp); ++ ret = netif_xdp_propagate(vf_netdev, &xdp); + + if (ret && prog) + bpf_prog_put(prog); +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index d8b169ac0343c5..31242921c8285a 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -2462,8 +2462,6 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev) + + netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name); + +- netvsc_vf_setxdp(vf_netdev, NULL); +- + reinit_completion(&net_device_ctx->vf_add); + netdev_rx_handler_unregister(vf_netdev); + netdev_upper_dev_unlink(vf_netdev, ndev); +@@ -2631,7 +2629,9 @@ static int netvsc_probe(struct hv_device *dev, + continue; + + netvsc_prepare_bonding(vf_netdev); ++ netdev_lock_ops(vf_netdev); + netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE); ++ netdev_unlock_ops(vf_netdev); + __netvsc_vf_setup(net, vf_netdev); + break; + } +diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c +index 31a06e71be25bb..b2a3518015372f 100644 +--- a/drivers/net/netdevsim/netdev.c ++++ b/drivers/net/netdevsim/netdev.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include "netdevsim.h" + +@@ -357,6 +358,7 @@ static int nsim_rcv(struct nsim_rq *rq, int budget) + break; + + skb = skb_dequeue(&rq->skb_queue); ++ skb_mark_napi_id(skb, &rq->napi); + netif_receive_skb(skb); + } + +diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c +index 23e1f0521f5498..65f31d3c348106 100644 +--- a/drivers/net/phy/marvell-88q2xxx.c ++++ b/drivers/net/phy/marvell-88q2xxx.c +@@ -119,7 +119,6 @@ + #define MV88Q2XXX_LED_INDEX_GPIO 1 + + struct mv88q2xxx_priv { +- bool enable_temp; + bool enable_led0; + }; + +@@ -482,49 +481,6 @@ static int mv88q2xxx_config_aneg(struct phy_device *phydev) + return phydev->drv->soft_reset(phydev); + } + +-static int mv88q2xxx_config_init(struct phy_device *phydev) +-{ +- struct mv88q2xxx_priv *priv = phydev->priv; +- int ret; +- +- /* The 88Q2XXX PHYs do have the extended ability register available, but +- * register MDIO_PMA_EXTABLE where they should signalize it does not +- * work according to specification. Therefore, we force it here. +- */ +- phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; +- +- /* Configure interrupt with default settings, output is driven low for +- * active interrupt and high for inactive. +- */ +- if (phy_interrupt_is_valid(phydev)) { +- ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, +- MDIO_MMD_PCS_MV_GPIO_INT_CTRL, +- MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); +- if (ret < 0) +- return ret; +- } +- +- /* Enable LED function and disable TX disable feature on LED/TX_ENABLE */ +- if (priv->enable_led0) { +- ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, +- MDIO_MMD_PCS_MV_RESET_CTRL, +- MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE); +- if (ret < 0) +- return ret; +- } +- +- /* Enable temperature sense */ +- if (priv->enable_temp) { +- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, +- MDIO_MMD_PCS_MV_TEMP_SENSOR2, +- MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, 0); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- + static int mv88q2xxx_get_sqi(struct phy_device *phydev) + { + int ret; +@@ -667,6 +623,12 @@ static int mv88q2xxx_resume(struct phy_device *phydev) + } + + #if IS_ENABLED(CONFIG_HWMON) ++static int mv88q2xxx_enable_temp_sense(struct phy_device *phydev) ++{ ++ return phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TEMP_SENSOR2, ++ MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, 0); ++} ++ + static const struct hwmon_channel_info * const mv88q2xxx_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM), + NULL +@@ -762,11 +724,13 @@ static const struct hwmon_chip_info mv88q2xxx_hwmon_chip_info = { + + static int mv88q2xxx_hwmon_probe(struct phy_device *phydev) + { +- struct mv88q2xxx_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct device *hwmon; ++ int ret; + +- priv->enable_temp = true; ++ ret = mv88q2xxx_enable_temp_sense(phydev); ++ if (ret < 0) ++ return ret; + + hwmon = devm_hwmon_device_register_with_info(dev, NULL, phydev, + &mv88q2xxx_hwmon_chip_info, +@@ -776,6 +740,11 @@ static int mv88q2xxx_hwmon_probe(struct phy_device *phydev) + } + + #else ++static int mv88q2xxx_enable_temp_sense(struct phy_device *phydev) ++{ ++ return 0; ++} ++ + static int mv88q2xxx_hwmon_probe(struct phy_device *phydev) + { + return 0; +@@ -853,6 +822,48 @@ static int mv88q222x_probe(struct phy_device *phydev) + return mv88q2xxx_hwmon_probe(phydev); + } + ++static int mv88q2xxx_config_init(struct phy_device *phydev) ++{ ++ struct mv88q2xxx_priv *priv = phydev->priv; ++ int ret; ++ ++ /* The 88Q2XXX PHYs do have the extended ability register available, but ++ * register MDIO_PMA_EXTABLE where they should signalize it does not ++ * work according to specification. Therefore, we force it here. ++ */ ++ phydev->pma_extable = MDIO_PMA_EXTABLE_BT1; ++ ++ /* Configure interrupt with default settings, output is driven low for ++ * active interrupt and high for inactive. ++ */ ++ if (phy_interrupt_is_valid(phydev)) { ++ ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, ++ MDIO_MMD_PCS_MV_GPIO_INT_CTRL, ++ MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Enable LED function and disable TX disable feature on LED/TX_ENABLE */ ++ if (priv->enable_led0) { ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, ++ MDIO_MMD_PCS_MV_RESET_CTRL, ++ MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Enable temperature sense again. There might have been a hard reset ++ * of the PHY and in this case the register content is restored to ++ * defaults and we need to enable it again. ++ */ ++ ret = mv88q2xxx_enable_temp_sense(phydev); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ + static int mv88q2110_config_init(struct phy_device *phydev) + { + int ret; +diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c +index 175cf5239bba86..21975ef946d5b7 100644 +--- a/drivers/net/phy/mediatek/mtk-ge-soc.c ++++ b/drivers/net/phy/mediatek/mtk-ge-soc.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include "../phylib.h" + #include "mtk.h" +@@ -1319,6 +1320,7 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) + { + struct device_node *np = dev_of_node(&phydev->mdio.bus->dev); + struct mtk_socphy_shared *shared = phy_package_get_priv(phydev); ++ struct device_node *pio_np; + struct regmap *regmap; + u32 reg; + int ret; +@@ -1336,7 +1338,13 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) + * The 4 bits in TPBANK0 are kept as package shared data and are used to + * set LED polarity for each of the LED0. + */ +- regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio"); ++ pio_np = of_parse_phandle(np, "mediatek,pio", 0); ++ if (!pio_np) ++ return -ENODEV; ++ ++ regmap = device_node_to_regmap(pio_np); ++ of_node_put(pio_np); ++ + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + +diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h +index 74162190bccc10..8531b804021aa4 100644 +--- a/drivers/net/usb/asix.h ++++ b/drivers/net/usb/asix.h +@@ -224,7 +224,6 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm); + + u16 asix_read_medium_status(struct usbnet *dev, int in_pm); + int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm); +-void asix_adjust_link(struct net_device *netdev); + + int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm); + +diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c +index 72ffc89b477ad8..7fd763917ae2cf 100644 +--- a/drivers/net/usb/asix_common.c ++++ b/drivers/net/usb/asix_common.c +@@ -414,28 +414,6 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm) + return ret; + } + +-/* set MAC link settings according to information from phylib */ +-void asix_adjust_link(struct net_device *netdev) +-{ +- struct phy_device *phydev = netdev->phydev; +- struct usbnet *dev = netdev_priv(netdev); +- u16 mode = 0; +- +- if (phydev->link) { +- mode = AX88772_MEDIUM_DEFAULT; +- +- if (phydev->duplex == DUPLEX_HALF) +- mode &= ~AX_MEDIUM_FD; +- +- if (phydev->speed != SPEED_100) +- mode &= ~AX_MEDIUM_PS; +- } +- +- asix_write_medium_mode(dev, mode, 0); +- phy_print_status(phydev); +- usbnet_link_change(dev, phydev->link, 0); +-} +- + int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm) + { + int ret; +diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c +index da24941a6e4446..9b0318fb50b55c 100644 +--- a/drivers/net/usb/asix_devices.c ++++ b/drivers/net/usb/asix_devices.c +@@ -752,7 +752,6 @@ static void ax88772_mac_link_down(struct phylink_config *config, + struct usbnet *dev = netdev_priv(to_net_dev(config->dev)); + + asix_write_medium_mode(dev, 0, 0); +- usbnet_link_change(dev, false, false); + } + + static void ax88772_mac_link_up(struct phylink_config *config, +@@ -783,7 +782,6 @@ static void ax88772_mac_link_up(struct phylink_config *config, + m |= AX_MEDIUM_RFC; + + asix_write_medium_mode(dev, m, 0); +- usbnet_link_change(dev, true, false); + } + + static const struct phylink_mac_ops ax88772_phylink_mac_ops = { +@@ -1350,10 +1348,9 @@ static const struct driver_info ax88772_info = { + .description = "ASIX AX88772 USB 2.0 Ethernet", + .bind = ax88772_bind, + .unbind = ax88772_unbind, +- .status = asix_status, + .reset = ax88772_reset, + .stop = ax88772_stop, +- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + }; +@@ -1362,11 +1359,9 @@ static const struct driver_info ax88772b_info = { + .description = "ASIX AX88772B USB 2.0 Ethernet", + .bind = ax88772_bind, + .unbind = ax88772_unbind, +- .status = asix_status, + .reset = ax88772_reset, + .stop = ax88772_stop, +- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | +- FLAG_MULTI_PACKET, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + .data = FLAG_EEPROM_MAC, +@@ -1376,11 +1371,9 @@ static const struct driver_info lxausb_t1l_info = { + .description = "Linux Automation GmbH USB 10Base-T1L", + .bind = ax88772_bind, + .unbind = ax88772_unbind, +- .status = asix_status, + .reset = ax88772_reset, + .stop = ax88772_stop, +- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | +- FLAG_MULTI_PACKET, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + .data = FLAG_EEPROM_MAC, +@@ -1412,10 +1405,8 @@ static const struct driver_info hg20f9_info = { + .description = "HG20F9 USB 2.0 Ethernet", + .bind = ax88772_bind, + .unbind = ax88772_unbind, +- .status = asix_status, + .reset = ax88772_reset, +- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | +- FLAG_MULTI_PACKET, ++ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + .data = FLAG_EEPROM_MAC, +diff --git a/drivers/net/usb/ch9200.c b/drivers/net/usb/ch9200.c +index f69d9b902da04a..a206ffa76f1b93 100644 +--- a/drivers/net/usb/ch9200.c ++++ b/drivers/net/usb/ch9200.c +@@ -178,6 +178,7 @@ static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc) + { + struct usbnet *dev = netdev_priv(netdev); + unsigned char buff[2]; ++ int ret; + + netdev_dbg(netdev, "%s phy_id:%02x loc:%02x\n", + __func__, phy_id, loc); +@@ -185,8 +186,10 @@ static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc) + if (phy_id != 0) + return -ENODEV; + +- control_read(dev, REQUEST_READ, 0, loc * 2, buff, 0x02, +- CONTROL_TIMEOUT_MS); ++ ret = control_read(dev, REQUEST_READ, 0, loc * 2, buff, 0x02, ++ CONTROL_TIMEOUT_MS); ++ if (ret < 0) ++ return ret; + + return (buff[0] | buff[1] << 8); + } +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 9ccc3f09f71b8c..edbf1088c7d741 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -610,10 +610,10 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, + if (rd == NULL) + return -ENOMEM; + +- if (dst_cache_init(&rd->dst_cache, GFP_ATOMIC)) { +- kfree(rd); +- return -ENOMEM; +- } ++ /* The driver can work correctly without a dst cache, so do not treat ++ * dst cache initialization errors as fatal. ++ */ ++ dst_cache_init(&rd->dst_cache, GFP_ATOMIC | __GFP_NOWARN); + + rd->remote_ip = *ip; + rd->remote_port = port; +@@ -1916,12 +1916,15 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) + goto out; + } + ++ rcu_read_lock(); + f = vxlan_find_mac(vxlan, n->ha, vni); + if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) { + /* bridge-local neighbor */ + neigh_release(n); ++ rcu_read_unlock(); + goto out; + } ++ rcu_read_unlock(); + + reply = arp_create(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, + n->ha, sha); +@@ -2648,14 +2651,10 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, + memset(&nh_rdst, 0, sizeof(struct vxlan_rdst)); + hash = skb_get_hash(skb); + +- rcu_read_lock(); + nh = rcu_dereference(f->nh); +- if (!nh) { +- rcu_read_unlock(); ++ if (!nh) + goto drop; +- } + do_xmit = vxlan_fdb_nh_path_select(nh, hash, &nh_rdst); +- rcu_read_unlock(); + + if (likely(do_xmit)) + vxlan_xmit_one(skb, dev, vni, &nh_rdst, did_rsc); +@@ -2782,6 +2781,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) + } + + eth = eth_hdr(skb); ++ rcu_read_lock(); + f = vxlan_find_mac(vxlan, eth->h_dest, vni); + did_rsc = false; + +@@ -2804,7 +2804,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) + vxlan_vnifilter_count(vxlan, vni, NULL, + VXLAN_VNI_STATS_TX_DROPS, 0); + kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET); +- return NETDEV_TX_OK; ++ goto out; + } + } + +@@ -2829,6 +2829,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) + kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET); + } + ++out: ++ rcu_read_unlock(); + return NETDEV_TX_OK; + } + +diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c +index e66e86bdec20ff..9d8efec46508a1 100644 +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -393,11 +393,10 @@ static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, + goto err; + } + ++ /* Make sure descriptor is read after the head pointer. */ ++ dma_rmb(); ++ + *nbytes = ath11k_hal_ce_dst_status_get_length(desc); +- if (*nbytes == 0) { +- ret = -EIO; +- goto err; +- } + + *skb = pipe->dest_ring->skb[sw_index]; + pipe->dest_ring->skb[sw_index] = NULL; +@@ -430,8 +429,8 @@ static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) + dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, + max_nbytes, DMA_FROM_DEVICE); + +- if (unlikely(max_nbytes < nbytes)) { +- ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)", ++ if (unlikely(max_nbytes < nbytes || nbytes == 0)) { ++ ath11k_warn(ab, "unexpected rx length (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; +diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c +index 22eb1b0377ffed..0281ce6fb71773 100644 +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -907,6 +907,52 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + }, + }; + ++static const struct dmi_system_id ath11k_pm_quirk_table[] = { ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21J4"), ++ }, ++ }, ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21K4"), ++ }, ++ }, ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21K6"), ++ }, ++ }, ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21K8"), ++ }, ++ }, ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21KA"), ++ }, ++ }, ++ { ++ .driver_data = (void *)ATH11K_PM_WOW, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "21F9"), ++ }, ++ }, ++ {} ++}; ++ + static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab) + { + WARN_ON(!ab->hw_params.single_pdev_only); +@@ -2334,8 +2380,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init); + + int ath11k_core_init(struct ath11k_base *ab) + { ++ const struct dmi_system_id *dmi_id; + int ret; + ++ dmi_id = dmi_first_match(ath11k_pm_quirk_table); ++ if (dmi_id) ++ ab->pm_policy = (kernel_ulong_t)dmi_id->driver_data; ++ else ++ ab->pm_policy = ATH11K_PM_DEFAULT; ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n", ab->pm_policy); ++ + ret = ath11k_core_soc_create(ab); + if (ret) { + ath11k_err(ab, "failed to create soc core: %d\n", ret); +diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h +index 529aca4f40621e..81a8fe7bed4484 100644 +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -894,6 +894,11 @@ struct ath11k_msi_config { + u16 hw_rev; + }; + ++enum ath11k_pm_policy { ++ ATH11K_PM_DEFAULT, ++ ATH11K_PM_WOW, ++}; ++ + /* Master structure to hold the hw data which may be used in core module */ + struct ath11k_base { + enum ath11k_hw_rev hw_rev; +@@ -1060,6 +1065,8 @@ struct ath11k_base { + } testmode; + #endif + ++ enum ath11k_pm_policy pm_policy; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c +index 218ab41c0f3c9a..ea2959305dec65 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2637,7 +2637,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, + struct ath11k *ar; + struct hal_reo_dest_ring *desc; + enum hal_reo_dest_ring_push_reason push_reason; +- u32 cookie; ++ u32 cookie, info0, rx_msdu_info0, rx_mpdu_info0; + int i; + + for (i = 0; i < MAX_RADIOS; i++) +@@ -2650,11 +2650,14 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, + try_again: + ath11k_hal_srng_access_begin(ab, srng); + ++ /* Make sure descriptor is read after the head pointer. */ ++ dma_rmb(); ++ + while (likely(desc = + (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, + srng))) { + cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, +- desc->buf_addr_info.info1); ++ READ_ONCE(desc->buf_addr_info.info1)); + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, + cookie); + mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); +@@ -2683,8 +2686,9 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, + + num_buffs_reaped[mac_id]++; + ++ info0 = READ_ONCE(desc->info0); + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, +- desc->info0); ++ info0); + if (unlikely(push_reason != + HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { + dev_kfree_skb_any(msdu); +@@ -2692,18 +2696,21 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, + continue; + } + +- rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & ++ rx_msdu_info0 = READ_ONCE(desc->rx_msdu_info.info0); ++ rx_mpdu_info0 = READ_ONCE(desc->rx_mpdu_info.info0); ++ ++ rxcb->is_first_msdu = !!(rx_msdu_info0 & + RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); +- rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & ++ rxcb->is_last_msdu = !!(rx_msdu_info0 & + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); +- rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & ++ rxcb->is_continuation = !!(rx_msdu_info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); + rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, +- desc->rx_mpdu_info.meta_data); ++ READ_ONCE(desc->rx_mpdu_info.meta_data)); + rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, +- desc->rx_mpdu_info.info0); ++ rx_mpdu_info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, +- desc->info0); ++ info0); + + rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list[mac_id], msdu); +diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c +index 61f4b6dd53807f..8cb1505a5a0c3f 100644 +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -599,7 +599,7 @@ u32 ath11k_hal_ce_dst_status_get_length(void *buf) + struct hal_ce_srng_dst_status_desc *desc = buf; + u32 len; + +- len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags); ++ len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, READ_ONCE(desc->flags)); + desc->flags &= ~HAL_CE_DST_STATUS_DESC_FLAGS_LEN; + + return len; +@@ -829,7 +829,7 @@ void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng) + srng->u.src_ring.cached_tp = + *(volatile u32 *)srng->u.src_ring.tp_addr; + } else { +- srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr; ++ srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + + /* Try to prefetch the next descriptor in the ring */ + if (srng->flags & HAL_SRNG_FLAGS_CACHED) +diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c +index 4f8b08ed1bbc6e..83a48a77c53ee5 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1993,6 +1993,15 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) + chunk->prev_size == chunk->size) + continue; + ++ if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "size/type mismatch (current %d %u) (prev %d %u), try later with small size\n", ++ chunk->size, chunk->type, ++ chunk->prev_size, chunk->prev_type); ++ ab->qmi.target_mem_delayed = true; ++ return 0; ++ } ++ + /* cannot reuse the existing chunk */ + dma_free_coherent(ab->dev, chunk->prev_size, + chunk->vaddr, chunk->paddr); +diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c +index be0d669d31fcce..740586fe49d1f9 100644 +--- a/drivers/net/wireless/ath/ath12k/ce.c ++++ b/drivers/net/wireless/ath/ath12k/ce.c +@@ -343,11 +343,10 @@ static int ath12k_ce_completed_recv_next(struct ath12k_ce_pipe *pipe, + goto err; + } + ++ /* Make sure descriptor is read after the head pointer. */ ++ dma_rmb(); ++ + *nbytes = ath12k_hal_ce_dst_status_get_length(desc); +- if (*nbytes == 0) { +- ret = -EIO; +- goto err; +- } + + *skb = pipe->dest_ring->skb[sw_index]; + pipe->dest_ring->skb[sw_index] = NULL; +@@ -380,8 +379,8 @@ static void ath12k_ce_recv_process_cb(struct ath12k_ce_pipe *pipe) + dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, + max_nbytes, DMA_FROM_DEVICE); + +- if (unlikely(max_nbytes < nbytes)) { +- ath12k_warn(ab, "rxed more than expected (nbytes %d, max %d)", ++ if (unlikely(max_nbytes < nbytes || nbytes == 0)) { ++ ath12k_warn(ab, "unexpected rx length (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; +diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h +index 1a14b9fb86b885..f85188af5de2f0 100644 +--- a/drivers/net/wireless/ath/ath12k/ce.h ++++ b/drivers/net/wireless/ath/ath12k/ce.h +@@ -1,7 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef ATH12K_CE_H +@@ -39,8 +39,8 @@ + #define PIPEDIR_INOUT_H2H 4 /* bidirectional, host to host */ + + /* CE address/mask */ +-#define CE_HOST_IE_ADDRESS 0x00A1803C +-#define CE_HOST_IE_2_ADDRESS 0x00A18040 ++#define CE_HOST_IE_ADDRESS 0x75804C ++#define CE_HOST_IE_2_ADDRESS 0x758050 + #define CE_HOST_IE_3_ADDRESS CE_HOST_IE_ADDRESS + + #define CE_HOST_IE_3_SHIFT 0xC +diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c +index 50c36e6ea10278..34e1bd2934ce3d 100644 +--- a/drivers/net/wireless/ath/ath12k/dp.c ++++ b/drivers/net/wireless/ath/ath12k/dp.c +@@ -1261,22 +1261,24 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab) + if (!ab->hw_params->reoq_lut_support) + return; + +- if (dp->reoq_lut.vaddr) { ++ if (dp->reoq_lut.vaddr_unaligned) { + ath12k_hif_write32(ab, + HAL_SEQ_WCSS_UMAC_REO_REG + + HAL_REO1_QDESC_LUT_BASE0(ab), 0); +- dma_free_coherent(ab->dev, DP_REOQ_LUT_SIZE, +- dp->reoq_lut.vaddr, dp->reoq_lut.paddr); +- dp->reoq_lut.vaddr = NULL; ++ dma_free_coherent(ab->dev, dp->reoq_lut.size, ++ dp->reoq_lut.vaddr_unaligned, ++ dp->reoq_lut.paddr_unaligned); ++ dp->reoq_lut.vaddr_unaligned = NULL; + } + +- if (dp->ml_reoq_lut.vaddr) { ++ if (dp->ml_reoq_lut.vaddr_unaligned) { + ath12k_hif_write32(ab, + HAL_SEQ_WCSS_UMAC_REO_REG + + HAL_REO1_QDESC_LUT_BASE1(ab), 0); +- dma_free_coherent(ab->dev, DP_REOQ_LUT_SIZE, +- dp->ml_reoq_lut.vaddr, dp->ml_reoq_lut.paddr); +- dp->ml_reoq_lut.vaddr = NULL; ++ dma_free_coherent(ab->dev, dp->ml_reoq_lut.size, ++ dp->ml_reoq_lut.vaddr_unaligned, ++ dp->ml_reoq_lut.paddr_unaligned); ++ dp->ml_reoq_lut.vaddr_unaligned = NULL; + } + } + +@@ -1608,39 +1610,66 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) + return ret; + } + ++static int ath12k_dp_alloc_reoq_lut(struct ath12k_base *ab, ++ struct ath12k_reo_q_addr_lut *lut) ++{ ++ lut->size = DP_REOQ_LUT_SIZE + HAL_REO_QLUT_ADDR_ALIGN - 1; ++ lut->vaddr_unaligned = dma_alloc_coherent(ab->dev, lut->size, ++ &lut->paddr_unaligned, ++ GFP_KERNEL | __GFP_ZERO); ++ if (!lut->vaddr_unaligned) ++ return -ENOMEM; ++ ++ lut->vaddr = PTR_ALIGN(lut->vaddr_unaligned, HAL_REO_QLUT_ADDR_ALIGN); ++ lut->paddr = lut->paddr_unaligned + ++ ((unsigned long)lut->vaddr - (unsigned long)lut->vaddr_unaligned); ++ return 0; ++} ++ + static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab) + { + struct ath12k_dp *dp = &ab->dp; ++ u32 val; ++ int ret; + + if (!ab->hw_params->reoq_lut_support) + return 0; + +- dp->reoq_lut.vaddr = dma_alloc_coherent(ab->dev, +- DP_REOQ_LUT_SIZE, +- &dp->reoq_lut.paddr, +- GFP_KERNEL | __GFP_ZERO); +- if (!dp->reoq_lut.vaddr) { ++ ret = ath12k_dp_alloc_reoq_lut(ab, &dp->reoq_lut); ++ if (ret) { + ath12k_warn(ab, "failed to allocate memory for reoq table"); +- return -ENOMEM; ++ return ret; + } + +- dp->ml_reoq_lut.vaddr = dma_alloc_coherent(ab->dev, +- DP_REOQ_LUT_SIZE, +- &dp->ml_reoq_lut.paddr, +- GFP_KERNEL | __GFP_ZERO); +- if (!dp->ml_reoq_lut.vaddr) { ++ ret = ath12k_dp_alloc_reoq_lut(ab, &dp->ml_reoq_lut); ++ if (ret) { + ath12k_warn(ab, "failed to allocate memory for ML reoq table"); +- dma_free_coherent(ab->dev, DP_REOQ_LUT_SIZE, +- dp->reoq_lut.vaddr, dp->reoq_lut.paddr); +- dp->reoq_lut.vaddr = NULL; +- return -ENOMEM; ++ dma_free_coherent(ab->dev, dp->reoq_lut.size, ++ dp->reoq_lut.vaddr_unaligned, ++ dp->reoq_lut.paddr_unaligned); ++ dp->reoq_lut.vaddr_unaligned = NULL; ++ return ret; + } + ++ /* Bits in the register have address [39:8] LUT base address to be ++ * allocated such that LSBs are assumed to be zero. Also, current ++ * design supports paddr upto 4 GB max hence it fits in 32 bit register only ++ */ ++ + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab), +- dp->reoq_lut.paddr); ++ dp->reoq_lut.paddr >> 8); ++ + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE1(ab), + dp->ml_reoq_lut.paddr >> 8); + ++ val = ath12k_hif_read32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab)); ++ ++ ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab), ++ val | HAL_REO_QDESC_ADDR_READ_LUT_ENABLE); ++ ++ ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_MAX_PEERID(ab), ++ HAL_REO_QDESC_MAX_PEERID); ++ + return 0; + } + +diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h +index 427a87b63dec3b..e8dbba0c3bb7d4 100644 +--- a/drivers/net/wireless/ath/ath12k/dp.h ++++ b/drivers/net/wireless/ath/ath12k/dp.h +@@ -311,8 +311,11 @@ struct ath12k_reo_queue_ref { + } __packed; + + struct ath12k_reo_q_addr_lut { +- dma_addr_t paddr; ++ u32 *vaddr_unaligned; + u32 *vaddr; ++ dma_addr_t paddr_unaligned; ++ dma_addr_t paddr; ++ u32 size; + }; + + struct ath12k_dp { +diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c +index 600d97169f241a..826c9723a7a68d 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_mon.c ++++ b/drivers/net/wireless/ath/ath12k/dp_mon.c +@@ -2097,6 +2097,8 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct + bool is_mcbc = rxcb->is_mcbc; + bool is_eapol_tkip = rxcb->is_eapol; + ++ status->link_valid = 0; ++ + if ((status->encoding == RX_ENC_HE) && !(status->flag & RX_FLAG_RADIOTAP_HE) && + !(status->flag & RX_FLAG_SKIP_MONITOR)) { + he = skb_push(msdu, sizeof(known)); +diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c +index 7fadd366ec13de..cc5a23a46ea151 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath12k/dp_rx.c +@@ -2259,6 +2259,11 @@ static void ath12k_dp_rx_h_mpdu(struct ath12k *ar, + spin_lock_bh(&ar->ab->base_lock); + peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu, rx_info); + if (peer) { ++ /* resetting mcbc bit because mcbc packets are unicast ++ * packets only for AP as STA sends unicast packets. ++ */ ++ rxcb->is_mcbc = rxcb->is_mcbc && !peer->ucast_ra_only; ++ + if (rxcb->is_mcbc) + enctype = peer->sec_type_grp; + else +@@ -3250,8 +3255,14 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, + reo_ent_ring->rx_mpdu_info.peer_meta_data = + reo_dest_ring->rx_mpdu_info.peer_meta_data; + +- reo_ent_ring->queue_addr_lo = cpu_to_le32(lower_32_bits(rx_tid->paddr)); +- queue_addr_hi = upper_32_bits(rx_tid->paddr); ++ if (ab->hw_params->reoq_lut_support) { ++ reo_ent_ring->queue_addr_lo = reo_dest_ring->rx_mpdu_info.peer_meta_data; ++ queue_addr_hi = 0; ++ } else { ++ reo_ent_ring->queue_addr_lo = cpu_to_le32(lower_32_bits(rx_tid->paddr)); ++ queue_addr_hi = upper_32_bits(rx_tid->paddr); ++ } ++ + reo_ent_ring->info0 = le32_encode_bits(queue_addr_hi, + HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI) | + le32_encode_bits(dst_ind, +diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c +index d00869a33fea06..faf74b54594109 100644 +--- a/drivers/net/wireless/ath/ath12k/hal.c ++++ b/drivers/net/wireless/ath/ath12k/hal.c +@@ -449,8 +449,8 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) + + static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) + { +- return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & +- RX_MPDU_START_INFO6_MCAST_BCAST; ++ return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & ++ RX_MSDU_END_INFO5_DA_IS_MCBC; + } + + static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, +@@ -902,8 +902,8 @@ static u8 *ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2(struct hal_rx_desc + + static bool ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) + { +- return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info6) & +- RX_MPDU_START_INFO6_MCAST_BCAST; ++ return __le16_to_cpu(desc->u.qcn9274_compact.msdu_end.info5) & ++ RX_MSDU_END_INFO5_DA_IS_MCBC; + } + + static void ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, +@@ -1943,7 +1943,7 @@ u32 ath12k_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc + { + u32 len; + +- len = le32_get_bits(desc->flags, HAL_CE_DST_STATUS_DESC_FLAGS_LEN); ++ len = le32_get_bits(READ_ONCE(desc->flags), HAL_CE_DST_STATUS_DESC_FLAGS_LEN); + desc->flags &= ~cpu_to_le32(HAL_CE_DST_STATUS_DESC_FLAGS_LEN); + + return len; +@@ -2113,7 +2113,7 @@ void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng) + srng->u.src_ring.cached_tp = + *(volatile u32 *)srng->u.src_ring.tp_addr; + else +- srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr; ++ srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + } + + /* Update cached ring head/tail pointers to HW. ath12k_hal_srng_access_begin() +diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h +index c8205672cd3dd5..cb8530dfdd911d 100644 +--- a/drivers/net/wireless/ath/ath12k/hal.h ++++ b/drivers/net/wireless/ath/ath12k/hal.h +@@ -21,6 +21,7 @@ struct ath12k_base; + #define HAL_MAX_AVAIL_BLK_RES 3 + + #define HAL_RING_BASE_ALIGN 8 ++#define HAL_REO_QLUT_ADDR_ALIGN 256 + + #define HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX 32704 + /* TODO: Check with hw team on the supported scatter buf size */ +@@ -39,6 +40,7 @@ struct ath12k_base; + #define HAL_OFFSET_FROM_HP_TO_TP 4 + + #define HAL_SHADOW_REG(x) (HAL_SHADOW_BASE_ADDR + (4 * (x))) ++#define HAL_REO_QDESC_MAX_PEERID 8191 + + /* WCSS Relative address */ + #define HAL_SEQ_WCSS_UMAC_OFFSET 0x00a00000 +@@ -139,6 +141,8 @@ struct ath12k_base; + #define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008 + #define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c + #define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010 ++#define HAL_REO1_QDESC_ADDR(ab) ((ab)->hw_params->regs->hal_reo1_qdesc_addr) ++#define HAL_REO1_QDESC_MAX_PEERID(ab) ((ab)->hw_params->regs->hal_reo1_qdesc_max_peerid) + #define HAL_REO1_SW_COOKIE_CFG0(ab) ((ab)->hw_params->regs->hal_reo1_sw_cookie_cfg0) + #define HAL_REO1_SW_COOKIE_CFG1(ab) ((ab)->hw_params->regs->hal_reo1_sw_cookie_cfg1) + #define HAL_REO1_QDESC_LUT_BASE0(ab) ((ab)->hw_params->regs->hal_reo1_qdesc_lut_base0) +@@ -326,6 +330,8 @@ struct ath12k_base; + #define HAL_REO1_SW_COOKIE_CFG_ALIGN BIT(18) + #define HAL_REO1_SW_COOKIE_CFG_ENABLE BIT(19) + #define HAL_REO1_SW_COOKIE_CFG_GLOBAL_ENABLE BIT(20) ++#define HAL_REO_QDESC_ADDR_READ_LUT_ENABLE BIT(7) ++#define HAL_REO_QDESC_ADDR_READ_CLEAR_QDESC_ARRAY BIT(6) + + /* CE ring bit field mask and shift */ + #define HAL_CE_DST_R0_DEST_CTRL_MAX_LEN GENMASK(15, 0) +diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h +index 63d279fab32249..f8a51aa0217a8e 100644 +--- a/drivers/net/wireless/ath/ath12k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath12k/hal_desc.h +@@ -707,7 +707,7 @@ enum hal_rx_msdu_desc_reo_dest_ind { + #define RX_MSDU_DESC_INFO0_DECAP_FORMAT GENMASK(30, 29) + + #define HAL_RX_MSDU_PKT_LENGTH_GET(val) \ +- (u32_get_bits((val), RX_MSDU_DESC_INFO0_MSDU_LENGTH)) ++ (le32_get_bits((val), RX_MSDU_DESC_INFO0_MSDU_LENGTH)) + + struct rx_msdu_desc { + __le32 info0; +diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c +index 1bfb11bae7add3..a5fa3b6a831ae4 100644 +--- a/drivers/net/wireless/ath/ath12k/hw.c ++++ b/drivers/net/wireless/ath/ath12k/hw.c +@@ -748,6 +748,8 @@ static const struct ath12k_hw_regs qcn9274_v2_regs = { + .hal_reo1_sw_cookie_cfg1 = 0x00000070, + .hal_reo1_qdesc_lut_base0 = 0x00000074, + .hal_reo1_qdesc_lut_base1 = 0x00000078, ++ .hal_reo1_qdesc_addr = 0x0000007c, ++ .hal_reo1_qdesc_max_peerid = 0x00000088, + .hal_reo1_ring_base_lsb = 0x00000500, + .hal_reo1_ring_base_msb = 0x00000504, + .hal_reo1_ring_id = 0x00000508, +diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h +index 862b11325a9021..e1ad03daebcd48 100644 +--- a/drivers/net/wireless/ath/ath12k/hw.h ++++ b/drivers/net/wireless/ath/ath12k/hw.h +@@ -299,6 +299,9 @@ struct ath12k_hw_regs { + + u32 hal_tcl_status_ring_base_lsb; + ++ u32 hal_reo1_qdesc_addr; ++ u32 hal_reo1_qdesc_max_peerid; ++ + u32 hal_wbm_idle_ring_base_lsb; + u32 hal_wbm_idle_ring_misc_addr; + u32 hal_wbm_r0_idle_list_cntl_addr; +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index 331bcf5e6c4cce..d1d3c9f34372da 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -3451,7 +3451,10 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, + } + + sband = hw->wiphy->bands[def->chan->band]; +- basic_rate_idx = ffs(bss_conf->basic_rates) - 1; ++ if (bss_conf->basic_rates) ++ basic_rate_idx = __ffs(bss_conf->basic_rates); ++ else ++ basic_rate_idx = 0; + bitrate = sband->bitrates[basic_rate_idx].bitrate; + + hw_rate_code = ath12k_mac_get_rate_hw_value(bitrate); +@@ -3703,6 +3706,8 @@ static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, + unsigned long links = ahvif->links_map; + struct ieee80211_bss_conf *info; + struct ath12k_link_vif *arvif; ++ struct ieee80211_sta *sta; ++ struct ath12k_sta *ahsta; + struct ath12k *ar; + u8 link_id; + +@@ -3715,6 +3720,35 @@ static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, + } + + if (changed & BSS_CHANGED_ASSOC) { ++ if (vif->cfg.assoc) { ++ /* only in station mode we can get here, so it's safe ++ * to use ap_addr ++ */ ++ rcu_read_lock(); ++ sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); ++ if (!sta) { ++ rcu_read_unlock(); ++ WARN_ONCE(1, "failed to find sta with addr %pM\n", ++ vif->cfg.ap_addr); ++ return; ++ } ++ ++ ahsta = ath12k_sta_to_ahsta(sta); ++ arvif = wiphy_dereference(hw->wiphy, ++ ahvif->link[ahsta->assoc_link_id]); ++ rcu_read_unlock(); ++ ++ ar = arvif->ar; ++ /* there is no reason for which an assoc link's ++ * bss info does not exist ++ */ ++ info = ath12k_mac_get_link_bss_conf(arvif); ++ ath12k_bss_assoc(ar, arvif, info); ++ ++ /* exclude assoc link as it is done above */ ++ links &= ~BIT(ahsta->assoc_link_id); ++ } ++ + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->ar) +@@ -3984,10 +4018,14 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, + band = def.chan->band; + mcast_rate = info->mcast_rate[band]; + +- if (mcast_rate > 0) ++ if (mcast_rate > 0) { + rateidx = mcast_rate - 1; +- else +- rateidx = ffs(info->basic_rates) - 1; ++ } else { ++ if (info->basic_rates) ++ rateidx = __ffs(info->basic_rates); ++ else ++ rateidx = 0; ++ } + + if (ar->pdev->cap.supported_bands & WMI_HOST_WLAN_5GHZ_CAP) + rateidx += ATH12K_MAC_FIRST_OFDM_RATE_IDX; +@@ -5522,10 +5560,13 @@ static int ath12k_mac_station_add(struct ath12k *ar, + ar->max_num_stations); + goto exit; + } +- arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); ++ + if (!arsta->rx_stats) { +- ret = -ENOMEM; +- goto dec_num_station; ++ arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); ++ if (!arsta->rx_stats) { ++ ret = -ENOMEM; ++ goto dec_num_station; ++ } + } + + peer_param.vdev_id = arvif->vdev_id; +diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c +index 2e7d302ace679d..9289910887217f 100644 +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -1491,6 +1491,9 @@ void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend) + { + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + ++ if (!test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags)) ++ return; ++ + /* restore aspm in case firmware bootup fails */ + ath12k_pci_aspm_restore(ab_pci); + +diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c +index 792cca8a3fb1b0..ec7236bbccc0fe 100644 +--- a/drivers/net/wireless/ath/ath12k/peer.c ++++ b/drivers/net/wireless/ath/ath12k/peer.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include "core.h" +@@ -383,6 +383,9 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, + arvif->ast_idx = peer->hw_peer_id; + } + ++ if (vif->type == NL80211_IFTYPE_AP) ++ peer->ucast_ra_only = true; ++ + if (sta) { + ahsta = ath12k_sta_to_ahsta(sta); + arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy, +diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h +index 5870ee11a8c7ec..f3a5e054d2b556 100644 +--- a/drivers/net/wireless/ath/ath12k/peer.h ++++ b/drivers/net/wireless/ath/ath12k/peer.h +@@ -1,7 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef ATH12K_PEER_H +@@ -62,6 +62,7 @@ struct ath12k_peer { + + /* for reference to ath12k_link_sta */ + u8 link_id; ++ bool ucast_ra_only; + }; + + struct ath12k_ml_peer { +diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c +index fe50c3d3cb8201..a44fc9106634b6 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -1037,14 +1037,24 @@ int ath12k_wmi_vdev_down(struct ath12k *ar, u8 vdev_id) + static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan, + struct wmi_vdev_start_req_arg *arg) + { ++ u32 center_freq1 = arg->band_center_freq1; ++ + memset(chan, 0, sizeof(*chan)); + + chan->mhz = cpu_to_le32(arg->freq); +- chan->band_center_freq1 = cpu_to_le32(arg->band_center_freq1); +- if (arg->mode == MODE_11AC_VHT80_80) ++ chan->band_center_freq1 = cpu_to_le32(center_freq1); ++ if (arg->mode == MODE_11BE_EHT160) { ++ if (arg->freq > center_freq1) ++ chan->band_center_freq1 = cpu_to_le32(center_freq1 + 40); ++ else ++ chan->band_center_freq1 = cpu_to_le32(center_freq1 - 40); ++ ++ chan->band_center_freq2 = cpu_to_le32(center_freq1); ++ } else if (arg->mode == MODE_11BE_EHT80_80) { + chan->band_center_freq2 = cpu_to_le32(arg->band_center_freq2); +- else ++ } else { + chan->band_center_freq2 = 0; ++ } + + chan->info |= le32_encode_bits(arg->mode, WMI_CHAN_INFO_MODE); + if (arg->passive) +@@ -3665,7 +3675,8 @@ ath12k_fill_band_to_mac_param(struct ath12k_base *soc, + } + + static void +-ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cfg, ++ath12k_wmi_copy_resource_config(struct ath12k_base *ab, ++ struct ath12k_wmi_resource_config_params *wmi_cfg, + struct ath12k_wmi_resource_config_arg *tg_cfg) + { + wmi_cfg->num_vdevs = cpu_to_le32(tg_cfg->num_vdevs); +@@ -3732,6 +3743,9 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf + WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << + WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); ++ if (ab->hw_params->reoq_lut_support) ++ wmi_cfg->host_service_flags |= ++ cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REO_QREF_SUPPORT_BIT); + wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt); + wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period); + wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET); +@@ -3772,7 +3786,7 @@ static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, + ptr = skb->data + sizeof(*cmd); + cfg = ptr; + +- ath12k_wmi_copy_resource_config(cfg, &arg->res_cfg); ++ ath12k_wmi_copy_resource_config(ab, cfg, &arg->res_cfg); + + cfg->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_RESOURCE_CONFIG, + sizeof(*cfg)); +@@ -6019,7 +6033,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk + goto fallback; + } + +- spin_lock(&ab->base_lock); ++ spin_lock_bh(&ab->base_lock); + if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) { + /* Once mac is registered, ar is valid and all CC events from + * fw is considered to be received due to user requests +@@ -6043,7 +6057,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk + ab->default_regd[pdev_idx] = regd; + } + ab->dfs_region = reg_info->dfs_region; +- spin_unlock(&ab->base_lock); ++ spin_unlock_bh(&ab->base_lock); + + goto mem_free; + +diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h +index be4ac91dd34f50..bd7312f3cf24aa 100644 +--- a/drivers/net/wireless/ath/ath12k/wmi.h ++++ b/drivers/net/wireless/ath/ath12k/wmi.h +@@ -2461,6 +2461,7 @@ struct wmi_init_cmd { + } __packed; + + #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 ++#define WMI_RSRC_CFG_HOST_SVC_FLAG_REO_QREF_SUPPORT_BIT 12 + #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) + #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) + #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) +diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c +index a3e03580cd9ff0..564ca6a619856b 100644 +--- a/drivers/net/wireless/ath/carl9170/usb.c ++++ b/drivers/net/wireless/ath/carl9170/usb.c +@@ -438,14 +438,21 @@ static void carl9170_usb_rx_complete(struct urb *urb) + + if (atomic_read(&ar->rx_anch_urbs) == 0) { + /* +- * The system is too slow to cope with +- * the enormous workload. We have simply +- * run out of active rx urbs and this +- * unfortunately leads to an unpredictable +- * device. ++ * At this point, either the system is too slow to ++ * cope with the enormous workload (so we have simply ++ * run out of active rx urbs and this unfortunately ++ * leads to an unpredictable device), or the device ++ * is not fully functional after an unsuccessful ++ * firmware loading attempts (so it doesn't pass ++ * ieee80211_register_hw() and there is no internal ++ * workqueue at all). + */ + +- ieee80211_queue_work(ar->hw, &ar->ping_work); ++ if (ar->registered) ++ ieee80211_queue_work(ar->hw, &ar->ping_work); ++ else ++ pr_warn_once("device %s is not registered\n", ++ dev_name(&ar->udev->dev)); + } + } else { + /* +diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +index 130b9a8aa7ebe1..67ee3b6e6d85c0 100644 +--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c ++++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +@@ -44,6 +44,8 @@ + IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode" + #define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ + IWL_QU_B_JF_B_FW_PRE "-" __stringify(api) ".ucode" ++#define IWL_QU_C_JF_B_MODULE_FIRMWARE(api) \ ++ IWL_QU_C_JF_B_FW_PRE "-" __stringify(api) ".ucode" + #define IWL_CC_A_MODULE_FIRMWARE(api) \ + IWL_CC_A_FW_PRE "-" __stringify(api) ".ucode" + +@@ -422,6 +424,7 @@ const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { + MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); ++MODULE_FIRMWARE(IWL_QU_C_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c +index a27a72cc017a30..a7f9e244c0975e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c ++++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c +@@ -1382,14 +1382,14 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, + + err = iwl_trans_start_hw(priv->trans); + if (err) +- goto out_free_hw; ++ goto out_leave_trans; + + /* Read the EEPROM */ + err = iwl_read_eeprom(priv->trans, &priv->eeprom_blob, + &priv->eeprom_blob_size); + if (err) { + IWL_ERR(priv, "Unable to init EEPROM\n"); +- goto out_free_hw; ++ goto out_leave_trans; + } + + /* Reset chip to save power until we load uCode during "up". */ +@@ -1508,6 +1508,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, + kfree(priv->eeprom_blob); + out_free_eeprom: + kfree(priv->nvm_data); ++out_leave_trans: ++ iwl_trans_op_mode_leave(priv->trans); + out_free_hw: + ieee80211_free_hw(priv->hw); + out: +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c +index ee99298eebf595..7ce01ad3608e18 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c +@@ -1757,7 +1757,7 @@ iwl_mld_send_proto_offload(struct iwl_mld *mld, + + addrconf_addr_solict_mult(&wowlan_data->target_ipv6_addrs[i], + &solicited_addr); +- for (j = 0; j < c; j++) ++ for (j = 0; j < n_nsc && j < c; j++) + if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, + &solicited_addr) == 0) + break; +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +index 68d97d3b8f0260..2d5233dc3e2423 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +@@ -2460,7 +2460,7 @@ iwl_mld_change_vif_links(struct ieee80211_hw *hw, + added |= BIT(0); + + for (int i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { +- if (removed & BIT(i)) ++ if (removed & BIT(i) && !WARN_ON(!old[i])) + iwl_mld_remove_link(mld, old[i]); + } + +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c +index 7a098942dc8021..21f65442638dda 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c +@@ -475,8 +475,9 @@ iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode) + iwl_mld_ptp_remove(mld); + iwl_mld_leds_exit(mld); + +- wiphy_lock(mld->wiphy); + iwl_mld_thermal_exit(mld); ++ ++ wiphy_lock(mld->wiphy); + iwl_mld_low_latency_stop(mld); + iwl_mld_deinit_time_sync(mld); + wiphy_unlock(mld->wiphy); +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c +index 1909953a9be984..670ac43528006b 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c +@@ -419,6 +419,8 @@ static void iwl_mld_cooling_device_unregister(struct iwl_mld *mld) + + void iwl_mld_thermal_initialize(struct iwl_mld *mld) + { ++ lockdep_assert_not_held(&mld->wiphy->mtx); ++ + wiphy_delayed_work_init(&mld->ct_kill_exit_wk, iwl_mld_exit_ctkill); + + #ifdef CONFIG_THERMAL +@@ -429,7 +431,9 @@ void iwl_mld_thermal_initialize(struct iwl_mld *mld) + + void iwl_mld_thermal_exit(struct iwl_mld *mld) + { ++ wiphy_lock(mld->wiphy); + wiphy_delayed_work_cancel(mld->wiphy, &mld->ct_kill_exit_wk); ++ wiphy_unlock(mld->wiphy); + + #ifdef CONFIG_THERMAL + iwl_mld_cooling_device_unregister(mld); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +index bec18d197f3102..83f1ed94ccab99 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright (C) 2012-2014, 2018-2024 Intel Corporation ++ * Copyright (C) 2012-2014, 2018-2025 Intel Corporation + * Copyright (C) 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015-2017 Intel Deutschland GmbH + */ +@@ -941,7 +941,7 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx) + u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx); + bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10; + +- if (rate_idx <= IWL_FIRST_CCK_RATE) ++ if (rate_idx <= IWL_LAST_CCK_RATE) + flags |= is_new_rate ? IWL_MAC_BEACON_CCK + : IWL_MAC_BEACON_CCK_V1; + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +index 102a6123bba0e4..4cc7a2e5746d2b 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +@@ -2942,6 +2942,8 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + for (i = 0; i < trans->num_rx_queues && pos < bufsz; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + ++ spin_lock_bh(&rxq->lock); ++ + pos += scnprintf(buf + pos, bufsz - pos, "queue#: %2d\n", + i); + pos += scnprintf(buf + pos, bufsz - pos, "\tread: %u\n", +@@ -2962,6 +2964,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + pos += scnprintf(buf + pos, bufsz - pos, + "\tclosed_rb_num: Not Allocated\n"); + } ++ spin_unlock_bh(&rxq->lock); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); +@@ -3662,8 +3665,11 @@ iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, + /* Dump RBs is supported only for pre-9000 devices (1 queue) */ + struct iwl_rxq *rxq = &trans_pcie->rxq[0]; + /* RBs */ ++ spin_lock_bh(&rxq->lock); + num_rbs = iwl_get_closed_rb_stts(trans, rxq); + num_rbs = (num_rbs - rxq->read) & RX_QUEUE_MASK; ++ spin_unlock_bh(&rxq->lock); ++ + len += num_rbs * (sizeof(*data) + + sizeof(struct iwl_fw_error_dump_rb) + + (PAGE_SIZE << trans_pcie->rx_page_order)); +diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c +index 772084a9bd8d7c..3baf8ab01e22b0 100644 +--- a/drivers/net/wireless/intersil/p54/fwio.c ++++ b/drivers/net/wireless/intersil/p54/fwio.c +@@ -231,6 +231,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, + + mutex_lock(&priv->eeprom_mutex); + priv->eeprom = buf; ++ priv->eeprom_slice_size = len; + eeprom_hdr = skb_put(skb, eeprom_hdr_size + len); + + if (priv->fw_var < 0x509) { +@@ -253,6 +254,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, + ret = -EBUSY; + } + priv->eeprom = NULL; ++ priv->eeprom_slice_size = 0; + mutex_unlock(&priv->eeprom_mutex); + return ret; + } +diff --git a/drivers/net/wireless/intersil/p54/p54.h b/drivers/net/wireless/intersil/p54/p54.h +index 522656de415987..aeb5e40cc5ef3f 100644 +--- a/drivers/net/wireless/intersil/p54/p54.h ++++ b/drivers/net/wireless/intersil/p54/p54.h +@@ -258,6 +258,7 @@ struct p54_common { + + /* eeprom handling */ + void *eeprom; ++ size_t eeprom_slice_size; + struct completion eeprom_comp; + struct mutex eeprom_mutex; + }; +diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c +index 8414aa208655f6..2deb1bb54f24bd 100644 +--- a/drivers/net/wireless/intersil/p54/txrx.c ++++ b/drivers/net/wireless/intersil/p54/txrx.c +@@ -496,14 +496,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, + return ; + + if (priv->fw_var >= 0x509) { +- memcpy(priv->eeprom, eeprom->v2.data, +- le16_to_cpu(eeprom->v2.len)); ++ if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size) ++ return; ++ ++ memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size); + } else { +- memcpy(priv->eeprom, eeprom->v1.data, +- le16_to_cpu(eeprom->v1.len)); ++ if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size) ++ return; ++ ++ memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size); + } + + priv->eeprom = NULL; ++ priv->eeprom_slice_size = 0; + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); + dev_kfree_skb_any(tmp); + complete(&priv->eeprom_comp); +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +index 84ef80ab4afbfa..96cecc576a9867 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +@@ -17,6 +17,8 @@ static const struct usb_device_id mt76x2u_device_table[] = { + { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ + { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ + { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ ++ { USB_DEVICE(0x0471, 0x2126) }, /* LiteOn WN4516R module, nonstandard USB connector */ ++ { USB_DEVICE(0x0471, 0x7600) }, /* LiteOn WN4519R module, nonstandard USB connector */ + { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ + { USB_DEVICE(0x0846, 0x9014) }, /* Netgear WNDA3100v3 */ + { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +index 33a14365ec9b98..3b556281151158 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +@@ -191,6 +191,7 @@ int mt76x2u_register_device(struct mt76x02_dev *dev) + { + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_usb *usb = &dev->mt76.usb; ++ bool vht; + int err; + + INIT_DELAYED_WORK(&dev->cal_work, mt76x2u_phy_calibrate); +@@ -217,7 +218,17 @@ int mt76x2u_register_device(struct mt76x02_dev *dev) + + /* check hw sg support in order to enable AMSDU */ + hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_TX_SG_MAX_SIZE : 1; +- err = mt76_register_device(&dev->mt76, true, mt76x02_rates, ++ switch (dev->mt76.rev) { ++ case 0x76320044: ++ /* these ASIC revisions do not support VHT */ ++ vht = false; ++ break; ++ default: ++ vht = true; ++ break; ++ } ++ ++ err = mt76_register_device(&dev->mt76, vht, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); + if (err) + goto fail; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 826c48a2ee6964..1fffa43379b2b2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -83,6 +83,11 @@ mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; ++ ++ if (is_mt7922(phy->mt76->dev)) { ++ he_cap_elem->phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; ++ } + break; + case NL80211_IFTYPE_STATION: + he_cap_elem->mac_cap_info[1] |= +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c +index 79639be0d29aca..2a83ff59a968c9 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c +@@ -322,6 +322,12 @@ static void mt7925_init_work(struct work_struct *work) + return; + } + ++ ret = mt7925_mcu_set_thermal_protect(dev); ++ if (ret) { ++ dev_err(dev->mt76.dev, "thermal protection enable failed\n"); ++ return; ++ } ++ + /* we support chip reset now */ + dev->hw_init_done = true; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index dea5b9bcb3fdfb..7d96b88cff803a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -974,6 +974,23 @@ int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable) + } + EXPORT_SYMBOL_GPL(mt7925_mcu_set_deep_sleep); + ++int mt7925_mcu_set_thermal_protect(struct mt792x_dev *dev) ++{ ++ char cmd[64]; ++ int ret = 0; ++ ++ snprintf(cmd, sizeof(cmd), "ThermalProtGband %d %d %d %d %d %d %d %d %d %d", ++ 0, 100, 90, 80, 30, 1, 1, 115, 105, 5); ++ ret = mt7925_mcu_chip_config(dev, cmd); ++ ++ snprintf(cmd, sizeof(cmd), "ThermalProtAband %d %d %d %d %d %d %d %d %d %d", ++ 1, 100, 90, 80, 30, 1, 1, 115, 105, 5); ++ ret |= mt7925_mcu_chip_config(dev, cmd); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mt7925_mcu_set_thermal_protect); ++ + int mt7925_run_firmware(struct mt792x_dev *dev) + { + int err; +@@ -3306,7 +3323,8 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + else + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + +- if (cmd == MCU_UNI_CMD(HIF_CTRL)) ++ if (cmd == MCU_UNI_CMD(HIF_CTRL) || ++ cmd == MCU_UNI_CMD(CHIP_CONFIG)) + uni_txd->option &= ~MCU_CMD_ACK; + + goto exit; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +index 8ac43feb26d64f..a855a451350280 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +@@ -637,6 +637,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + int mt7925_mcu_set_timing(struct mt792x_phy *phy, + struct ieee80211_bss_conf *link_conf); + int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); ++int mt7925_mcu_set_thermal_protect(struct mt792x_dev *dev); + int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); + int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); + int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +index c7b5dc1dbb3495..2e20ecc712071c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +@@ -490,9 +490,6 @@ static int mt7925_pci_suspend(struct device *device) + + /* disable interrupt */ + mt76_wr(dev, dev->irq_map->host_irq_enable, 0); +- mt76_wr(dev, MT_WFDMA0_HOST_INT_DIS, +- dev->irq_map->tx.all_complete_mask | +- MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); + + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +index 985794a40c1a8e..547489092c2947 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +@@ -28,7 +28,7 @@ + #define MT_MDP_TO_HIF 0 + #define MT_MDP_TO_WM 1 + +-#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x228) ++#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x204) + #define MT_WFDMA0_HOST_INT_DIS MT_WFDMA0(0x22c) + #define HOST_RX_DONE_INT_ENA4 BIT(12) + #define HOST_RX_DONE_INT_ENA5 BIT(13) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index d89c06f47997fa..2108361543a0c0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -647,6 +647,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; + } + ++ /* IEEE 802.11 fragmentation can only be applied to unicast frames. ++ * Hence, drop fragments with multicast/broadcast RA. ++ * This check fixes vulnerabilities, like CVE-2020-26145. ++ */ ++ if ((ieee80211_has_morefrags(fc) || seq_ctrl & IEEE80211_SCTL_FRAG) && ++ FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) != MT_RXD3_NORMAL_U2M) ++ return -EINVAL; ++ + hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; + if (hdr_trans && ieee80211_has_morefrags(fc)) { + if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap)) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index a3295b22523a61..b11dd3dd5c46f0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -991,7 +991,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + unsigned int link_id; +- int err; ++ int err = 0; + + for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf; +@@ -1254,7 +1254,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, + static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) + { + struct mt7996_dev *dev = mt7996_hw_dev(hw); +- int i, ret; ++ int i, ret = 0; + + mutex_lock(&dev->mt76.mutex); + +diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c +index 10d2e2124ff81a..c2a1234b59db6c 100644 +--- a/drivers/net/wireless/purelifi/plfxlc/usb.c ++++ b/drivers/net/wireless/purelifi/plfxlc/usb.c +@@ -503,8 +503,10 @@ int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer, + (void *)buffer, buffer_len, complete_fn, context); + + r = usb_submit_urb(urb, GFP_ATOMIC); +- if (r) ++ if (r) { ++ usb_free_urb(urb); + dev_err(&udev->dev, "Async write submit failed (%d)\n", r); ++ } + + return r; + } +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 0eafc4d125f91d..898f597f70a96d 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -155,6 +155,16 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) + ((u8)init_aspm) == (PCI_EXP_LNKCTL_ASPM_L0S | + PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_CCC)) + ppsc->support_aspm = false; ++ ++ /* RTL8723BE found on some ASUSTek laptops, such as F441U and ++ * X555UQ with subsystem ID 11ad:1723 are known to output large ++ * amounts of PCIe AER errors during and after boot up, causing ++ * heavy lags, poor network throughput, and occasional lock-ups. ++ */ ++ if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8723BE && ++ (rtlpci->pdev->subsystem_vendor == 0x11ad && ++ rtlpci->pdev->subsystem_device == 0x1723)) ++ ppsc->support_aspm = false; + } + + static bool _rtl_pci_platform_switch_device_pci_aspm( +diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h +index 96aeda26014e20..d4bee9c3ecfeab 100644 +--- a/drivers/net/wireless/realtek/rtw88/hci.h ++++ b/drivers/net/wireless/realtek/rtw88/hci.h +@@ -19,6 +19,8 @@ struct rtw_hci_ops { + void (*link_ps)(struct rtw_dev *rtwdev, bool enter); + void (*interface_cfg)(struct rtw_dev *rtwdev); + void (*dynamic_rx_agg)(struct rtw_dev *rtwdev, bool enable); ++ void (*write_firmware_page)(struct rtw_dev *rtwdev, u32 page, ++ const u8 *data, u32 size); + + int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size); + int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size); +@@ -79,6 +81,12 @@ static inline void rtw_hci_dynamic_rx_agg(struct rtw_dev *rtwdev, bool enable) + rtwdev->hci.ops->dynamic_rx_agg(rtwdev, enable); + } + ++static inline void rtw_hci_write_firmware_page(struct rtw_dev *rtwdev, u32 page, ++ const u8 *data, u32 size) ++{ ++ rtwdev->hci.ops->write_firmware_page(rtwdev, page, data, size); ++} ++ + static inline int + rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) + { +diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c +index 0491f501c13839..f66d1b302dc509 100644 +--- a/drivers/net/wireless/realtek/rtw88/mac.c ++++ b/drivers/net/wireless/realtek/rtw88/mac.c +@@ -856,8 +856,8 @@ static void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en) + } + } + +-static void +-write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size) ++void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page, ++ const u8 *data, u32 size) + { + u32 val32; + u32 block_nr; +@@ -887,6 +887,7 @@ write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size) + rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data)); + } + } ++EXPORT_SYMBOL(rtw_write_firmware_page); + + static int + download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size) +@@ -904,11 +905,13 @@ download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size) + rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT); + + for (page = 0; page < total_page; page++) { +- write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY); ++ rtw_hci_write_firmware_page(rtwdev, page, data, ++ DLFW_PAGE_SIZE_LEGACY); + data += DLFW_PAGE_SIZE_LEGACY; + } + if (last_page_size) +- write_firmware_page(rtwdev, page, data, last_page_size); ++ rtw_hci_write_firmware_page(rtwdev, page, data, ++ last_page_size); + + if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) { + rtw_err(rtwdev, "failed to check download firmware report\n"); +diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h +index 6905e27473721a..e92b1483728d5f 100644 +--- a/drivers/net/wireless/realtek/rtw88/mac.h ++++ b/drivers/net/wireless/realtek/rtw88/mac.h +@@ -34,6 +34,8 @@ int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd * const *cmd_seq); + int rtw_mac_power_on(struct rtw_dev *rtwdev); + void rtw_mac_power_off(struct rtw_dev *rtwdev); ++void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page, ++ const u8 *data, u32 size); + int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); + int rtw_mac_init(struct rtw_dev *rtwdev); + void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); +diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c +index 026fbf4ad9cce9..77f9fbe1870c66 100644 +--- a/drivers/net/wireless/realtek/rtw88/mac80211.c ++++ b/drivers/net/wireless/realtek/rtw88/mac80211.c +@@ -396,6 +396,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, + if (rtw_bf_support) + rtw_bf_assoc(rtwdev, vif, conf); + ++ rtw_set_ampdu_factor(rtwdev, vif, conf); ++ + rtw_fw_beacon_filter_config(rtwdev, true, vif); + } else { + rtw_leave_lps(rtwdev); +diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c +index 959f56a3cc1ab4..bc2c1a5a30b379 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.c ++++ b/drivers/net/wireless/realtek/rtw88/main.c +@@ -2447,6 +2447,38 @@ void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) + } + } + ++void rtw_set_ampdu_factor(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *bss_conf) ++{ ++ const struct rtw_chip_ops *ops = rtwdev->chip->ops; ++ struct ieee80211_sta *sta; ++ u8 factor = 0xff; ++ ++ if (!ops->set_ampdu_factor) ++ return; ++ ++ rcu_read_lock(); ++ ++ sta = ieee80211_find_sta(vif, bss_conf->bssid); ++ if (!sta) { ++ rcu_read_unlock(); ++ rtw_warn(rtwdev, "%s: failed to find station %pM\n", ++ __func__, bss_conf->bssid); ++ return; ++ } ++ ++ if (sta->deflink.vht_cap.vht_supported) ++ factor = u32_get_bits(sta->deflink.vht_cap.cap, ++ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); ++ else if (sta->deflink.ht_cap.ht_supported) ++ factor = sta->deflink.ht_cap.ampdu_factor; ++ ++ rcu_read_unlock(); ++ ++ if (factor != 0xff) ++ ops->set_ampdu_factor(rtwdev, factor); ++} ++ + MODULE_AUTHOR("Realtek Corporation"); + MODULE_DESCRIPTION("Realtek 802.11ac wireless core module"); + MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h +index 02343e059fd977..f410c554da58a3 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.h ++++ b/drivers/net/wireless/realtek/rtw88/main.h +@@ -878,6 +878,7 @@ struct rtw_chip_ops { + u32 antenna_rx); + void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable); + void (*efuse_grant)(struct rtw_dev *rtwdev, bool enable); ++ void (*set_ampdu_factor)(struct rtw_dev *rtwdev, u8 factor); + void (*false_alarm_statistics)(struct rtw_dev *rtwdev); + void (*phy_calibration)(struct rtw_dev *rtwdev); + void (*dpk_track)(struct rtw_dev *rtwdev); +@@ -2272,4 +2273,6 @@ void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel, + void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif); + bool rtw_core_check_sta_active(struct rtw_dev *rtwdev); + void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable); ++void rtw_set_ampdu_factor(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *bss_conf); + #endif +diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c +index bb4c4ccb31d41a..7f2b6dc21f566b 100644 +--- a/drivers/net/wireless/realtek/rtw88/pci.c ++++ b/drivers/net/wireless/realtek/rtw88/pci.c +@@ -12,6 +12,7 @@ + #include "fw.h" + #include "ps.h" + #include "debug.h" ++#include "mac.h" + + static bool rtw_disable_msi; + static bool rtw_pci_disable_aspm; +@@ -1602,6 +1603,7 @@ static const struct rtw_hci_ops rtw_pci_ops = { + .link_ps = rtw_pci_link_ps, + .interface_cfg = rtw_pci_interface_cfg, + .dynamic_rx_agg = NULL, ++ .write_firmware_page = rtw_write_firmware_page, + + .read8 = rtw_pci_read8, + .read16 = rtw_pci_read16, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c +index 1d232adbdd7e31..5e59cfe4dfdf5d 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c +@@ -1904,6 +1904,7 @@ static const struct rtw_chip_ops rtw8703b_ops = { + .set_antenna = NULL, + .cfg_ldo25 = rtw8723x_cfg_ldo25, + .efuse_grant = rtw8723x_efuse_grant, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw8723x_false_alarm_statistics, + .phy_calibration = rtw8703b_phy_calibration, + .dpk_track = NULL, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c +index 87715bd54860a0..31876e708f9ef6 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c +@@ -1404,6 +1404,7 @@ static const struct rtw_chip_ops rtw8723d_ops = { + .set_antenna = NULL, + .cfg_ldo25 = rtw8723x_cfg_ldo25, + .efuse_grant = rtw8723x_efuse_grant, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw8723x_false_alarm_statistics, + .phy_calibration = rtw8723d_phy_calibration, + .cck_pd_set = rtw8723d_phy_cck_pd_set, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +index f9ba2aa2928a42..adbfb37105d051 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c +@@ -925,6 +925,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8812a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8812a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c +index cfd35d40d46e22..ce8d4e4c6c57bc 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c +@@ -1332,6 +1332,16 @@ static void rtw8814a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) + { + } + ++/* Without this RTL8814A sends too many frames and (some?) 11n AP ++ * can't handle it, resulting in low TX speed. Other chips seem fine. ++ */ ++static void rtw8814a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor) ++{ ++ factor = min_t(u8, factor, IEEE80211_VHT_MAX_AMPDU_256K); ++ ++ rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, (8192 << factor) - 1); ++} ++ + static void rtw8814a_false_alarm_statistics(struct rtw_dev *rtwdev) + { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; +@@ -2051,6 +2061,7 @@ static const struct rtw_chip_ops rtw8814a_ops = { + .set_antenna = NULL, + .cfg_ldo25 = rtw8814a_cfg_ldo25, + .efuse_grant = rtw8814a_efuse_grant, ++ .set_ampdu_factor = rtw8814a_set_ampdu_factor, + .false_alarm_statistics = rtw8814a_false_alarm_statistics, + .phy_calibration = rtw8814a_phy_calibration, + .cck_pd_set = rtw8814a_phy_cck_pd_set, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c +index f68239b073191d..4d81fb29c9fcd8 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c +@@ -871,6 +871,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8821a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8821a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c +index 0ade7f11cbd2eb..f68b0041dcc06c 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c +@@ -1668,6 +1668,7 @@ static const struct rtw_chip_ops rtw8821c_ops = { + .set_antenna = NULL, + .set_tx_power_index = rtw8821c_set_tx_power_index, + .cfg_ldo25 = rtw8821c_cfg_ldo25, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw8821c_false_alarm_statistics, + .phy_calibration = rtw8821c_phy_calibration, + .cck_pd_set = rtw8821c_phy_cck_pd_set, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +index b4934da88e33ad..0da212e27d55b3 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c +@@ -2158,6 +2158,7 @@ static const struct rtw_chip_ops rtw8822b_ops = { + .set_tx_power_index = rtw8822b_set_tx_power_index, + .set_antenna = rtw8822b_set_antenna, + .cfg_ldo25 = rtw8822b_cfg_ldo25, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw8822b_false_alarm_statistics, + .phy_calibration = rtw8822b_phy_calibration, + .pwr_track = rtw8822b_pwr_track, +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822bu.c b/drivers/net/wireless/realtek/rtw88/rtw8822bu.c +index 572d1f31832ee4..ab50b3c4056261 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822bu.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822bu.c +@@ -77,6 +77,8 @@ static const struct usb_device_id rtw_8822bu_id_table[] = { + .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Mercusys MA30N */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3322, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* D-Link DWA-T185 rev. A1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03d1, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* BUFFALO WI-U2-866DM */ + {}, + }; + MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table); +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c +index 8937a7b656edb1..a7dc79773f6249 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c +@@ -4969,6 +4969,7 @@ static const struct rtw_chip_ops rtw8822c_ops = { + .set_tx_power_index = rtw8822c_set_tx_power_index, + .set_antenna = rtw8822c_set_antenna, + .cfg_ldo25 = rtw8822c_cfg_ldo25, ++ .set_ampdu_factor = NULL, + .false_alarm_statistics = rtw8822c_false_alarm_statistics, + .dpk_track = rtw8822c_dpk_track, + .phy_calibration = rtw8822c_phy_calibration, +diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c +index 410f637b1add58..682d4d6e314eea 100644 +--- a/drivers/net/wireless/realtek/rtw88/sdio.c ++++ b/drivers/net/wireless/realtek/rtw88/sdio.c +@@ -10,6 +10,7 @@ + #include + #include + #include "main.h" ++#include "mac.h" + #include "debug.h" + #include "fw.h" + #include "ps.h" +@@ -1154,6 +1155,7 @@ static const struct rtw_hci_ops rtw_sdio_ops = { + .link_ps = rtw_sdio_link_ps, + .interface_cfg = rtw_sdio_interface_cfg, + .dynamic_rx_agg = NULL, ++ .write_firmware_page = rtw_write_firmware_page, + + .read8 = rtw_sdio_read8, + .read16 = rtw_sdio_read16, +diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c +index c8092fa0d9f13d..1c181431e71ca9 100644 +--- a/drivers/net/wireless/realtek/rtw88/usb.c ++++ b/drivers/net/wireless/realtek/rtw88/usb.c +@@ -139,7 +139,7 @@ static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, +- addr, 0, data, len, 30000); ++ addr, 0, data, len, 500); + if (ret < 0 && ret != -ENODEV && count++ < 4) + rtw_err(rtwdev, "write register 0x%x failed with %d\n", + addr, ret); +@@ -165,6 +165,60 @@ static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) + rtw_usb_write(rtwdev, addr, val, 4); + } + ++static void rtw_usb_write_firmware_page(struct rtw_dev *rtwdev, u32 page, ++ const u8 *data, u32 size) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_device *udev = rtwusb->udev; ++ u32 addr = FW_START_ADDR_LEGACY; ++ u8 *data_dup, *buf; ++ u32 n, block_size; ++ int ret; ++ ++ switch (rtwdev->chip->id) { ++ case RTW_CHIP_TYPE_8723D: ++ block_size = 254; ++ break; ++ default: ++ block_size = 196; ++ break; ++ } ++ ++ data_dup = kmemdup(data, size, GFP_KERNEL); ++ if (!data_dup) ++ return; ++ ++ buf = data_dup; ++ ++ rtw_write32_mask(rtwdev, REG_MCUFW_CTRL, BIT_ROM_PGE, page); ++ ++ while (size > 0) { ++ if (size >= block_size) ++ n = block_size; ++ else if (size >= 8) ++ n = 8; ++ else ++ n = 1; ++ ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, ++ addr, 0, buf, n, 500); ++ if (ret != n) { ++ if (ret != -ENODEV) ++ rtw_err(rtwdev, ++ "write 0x%x len %d failed: %d\n", ++ addr, n, ret); ++ break; ++ } ++ ++ addr += n; ++ buf += n; ++ size -= n; ++ } ++ ++ kfree(data_dup); ++} ++ + static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping) + { + switch (dma_mapping) { +@@ -891,6 +945,7 @@ static const struct rtw_hci_ops rtw_usb_ops = { + .link_ps = rtw_usb_link_ps, + .interface_cfg = rtw_usb_interface_cfg, + .dynamic_rx_agg = rtw_usb_dynamic_rx_agg, ++ .write_firmware_page = rtw_usb_write_firmware_page, + + .write8 = rtw_usb_write8, + .write16 = rtw_usb_write16, +diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c +index eca3d767ff6032..bc6f799e291e84 100644 +--- a/drivers/net/wireless/realtek/rtw89/cam.c ++++ b/drivers/net/wireless/realtek/rtw89/cam.c +@@ -6,6 +6,7 @@ + #include "debug.h" + #include "fw.h" + #include "mac.h" ++#include "ps.h" + + static struct sk_buff * + rtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev, +@@ -471,9 +472,11 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: ++ rtw89_leave_ips_by_hwflags(rtwdev); + hw_key_type = RTW89_SEC_KEY_TYPE_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: ++ rtw89_leave_ips_by_hwflags(rtwdev); + hw_key_type = RTW89_SEC_KEY_TYPE_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +index c4c93f836a2f5a..1659ea64ade119 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +@@ -77,11 +77,6 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + RR_CFGCH_BAND0 | RR_CFGCH_CH); + rf_reg[path][i] |= u32_encode_bits(central_ch, RR_CFGCH_CH); + +- if (band == RTW89_BAND_2G) +- rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x0); +- else +- rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x1); +- + switch (band) { + case RTW89_BAND_2G: + default: +diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c +index cf3e976471c614..6ca5d9d0fe532a 100644 +--- a/drivers/net/wireless/virtual/mac80211_hwsim.c ++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c +@@ -1229,6 +1229,11 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, + /* MLD not supported here */ + u32 bcn_int = data->link_data[0].beacon_int; + u64 delta = abs(tsf - now); ++ struct ieee80211_bss_conf *conf; ++ ++ conf = link_conf_dereference_protected(vif, data->link_data[0].link_id); ++ if (conf && !conf->enable_beacon) ++ return; + + /* adjust after beaconing with new timestamp at old TBTT */ + if (tsf > now) { +diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c +index f29107d95ff26d..13aab3ca34f61e 100644 +--- a/drivers/nvme/host/ioctl.c ++++ b/drivers/nvme/host/ioctl.c +@@ -429,21 +429,14 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req, + pdu->result = le64_to_cpu(nvme_req(req)->result.u64); + + /* +- * For iopoll, complete it directly. Note that using the uring_cmd +- * helper for this is safe only because we check blk_rq_is_poll(). +- * As that returns false if we're NOT on a polled queue, then it's +- * safe to use the polled completion helper. +- * +- * Otherwise, move the completion to task work. ++ * IOPOLL could potentially complete this request directly, but ++ * if multiple rings are polling on the same queue, then it's possible ++ * for one ring to find completions for another ring. Punting the ++ * completion via task_work will always direct it to the right ++ * location, rather than potentially complete requests for ringA ++ * under iopoll invocations from ringB. + */ +- if (blk_rq_is_poll(req)) { +- if (pdu->bio) +- blk_rq_unmap_user(pdu->bio); +- io_uring_cmd_iopoll_done(ioucmd, pdu->result, pdu->status); +- } else { +- io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb); +- } +- ++ io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb); + return RQ_END_IO_FREE; + } + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index aba365f97cf6b4..947fac9128b30d 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2392,7 +2392,7 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new) + nvme_tcp_teardown_admin_queue(ctrl, false); + ret = nvme_tcp_configure_admin_queue(ctrl, false); + if (ret) +- return ret; ++ goto destroy_admin; + } + + if (ctrl->icdoff) { +diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c +index 599ec4b1223e9d..112ae200b393a6 100644 +--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c ++++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c +@@ -292,13 +292,14 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, + struct cdns_pcie *pcie = &ep->pcie; + u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; + u32 val, reg; ++ u16 actual_interrupts = interrupts + 1; + + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); + + reg = cap + PCI_MSIX_FLAGS; + val = cdns_pcie_ep_fn_readw(pcie, fn, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; +- val |= interrupts; ++ val |= interrupts; /* 0's based value */ + cdns_pcie_ep_fn_writew(pcie, fn, reg, val); + + /* Set MSI-X BAR and offset */ +@@ -308,7 +309,7 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, + + /* Set PBA BAR and offset. BAR must match MSI-X BAR */ + reg = cap + PCI_MSIX_PBA; +- val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; ++ val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + cdns_pcie_ep_fn_writel(pcie, fn, reg, val); + + return 0; +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 1a0bf9341542ea..24026f3f34133b 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -585,6 +585,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; + u32 val, reg; ++ u16 actual_interrupts = interrupts + 1; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) +@@ -595,7 +596,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + reg = ep_func->msix_cap + PCI_MSIX_FLAGS; + val = dw_pcie_ep_readw_dbi(ep, func_no, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; +- val |= interrupts; ++ val |= interrupts; /* 0's based value */ + dw_pcie_writew_dbi(pci, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_TABLE; +@@ -603,7 +604,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + dw_pcie_ep_writel_dbi(ep, func_no, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_PBA; +- val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; ++ val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + dw_pcie_ep_writel_dbi(ep, func_no, reg, val); + + dw_pcie_dbi_ro_wr_dis(pci); +diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +index c624b7ebd118c0..bbe9d750316b99 100644 +--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c ++++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c +@@ -44,7 +44,6 @@ + #define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) + #define PCIE_RDLH_LINK_UP_CHGED BIT(1) + #define PCIE_LINK_REQ_RST_NOT_INT BIT(2) +-#define PCIE_L0S_ENTRY 0x11 + #define PCIE_CLIENT_GENERAL_CONTROL 0x0 + #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 + #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c +@@ -177,8 +176,7 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) + struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); + u32 val = rockchip_pcie_get_ltssm(rockchip); + +- if ((val & PCIE_LINKUP) == PCIE_LINKUP && +- (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY) ++ if ((val & PCIE_LINKUP) == PCIE_LINKUP) + return 1; + + return 0; +@@ -410,8 +408,8 @@ static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip) + + static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip) + { +- phy_exit(rockchip->phy); + phy_power_off(rockchip->phy); ++ phy_exit(rockchip->phy); + } + + static const struct dw_pcie_ops dw_pcie_ops = { +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index 3d778d8b018756..32f57b8a6ecbd5 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -754,7 +754,7 @@ static int apple_pcie_init(struct pci_config_window *cfg) + if (ret) + return ret; + +- for_each_child_of_node_scoped(dev->of_node, of_port) { ++ for_each_available_child_of_node_scoped(dev->of_node, of_port) { + ret = apple_pcie_setup_port(pcie, of_port); + if (ret) { + dev_err(pcie->dev, "Port %pOF setup fail: %d\n", of_port, ret); +diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c +index ebd342bda235d4..91d2d92717d981 100644 +--- a/drivers/pci/hotplug/pciehp_hpc.c ++++ b/drivers/pci/hotplug/pciehp_hpc.c +@@ -771,7 +771,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) + u16 ignored_events = PCI_EXP_SLTSTA_DLLSC; + + if (!ctrl->inband_presence_disabled) +- ignored_events |= events & PCI_EXP_SLTSTA_PDC; ++ ignored_events |= PCI_EXP_SLTSTA_PDC; + + events &= ~ignored_events; + pciehp_ignore_link_change(ctrl, pdev, irq, ignored_events); +diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c +index e9e9aaa91770ae..d9996516f49e67 100644 +--- a/drivers/pci/hotplug/s390_pci_hpc.c ++++ b/drivers/pci/hotplug/s390_pci_hpc.c +@@ -65,9 +65,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) + + rc = zpci_deconfigure_device(zdev); + out: +- mutex_unlock(&zdev->state_lock); + if (pdev) + pci_dev_put(pdev); ++ mutex_unlock(&zdev->state_lock); + return rc; + } + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 4d84ed41248442..027a71c9c06f13 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -5538,7 +5538,8 @@ static void pci_slot_unlock(struct pci_slot *slot) + continue; + if (dev->subordinate) + pci_bus_unlock(dev->subordinate); +- pci_dev_unlock(dev); ++ else ++ pci_dev_unlock(dev); + } + } + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 94daca15a096f7..d0f7b749b9a620 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -4995,6 +4995,18 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); + } + ++static int pci_quirk_loongson_acs(struct pci_dev *dev, u16 acs_flags) ++{ ++ /* ++ * Loongson PCIe Root Ports don't advertise an ACS capability, but ++ * they do not allow peer-to-peer transactions between Root Ports. ++ * Allow each Root Port to be in a separate IOMMU group by masking ++ * SV/RR/CR/UF bits. ++ */ ++ return pci_acs_ctrl_enabled(acs_flags, ++ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); ++} ++ + /* + * Wangxun 40G/25G/10G/1G NICs have no ACS capability, but on + * multi-function devices, the hardware isolates the functions by +@@ -5128,6 +5140,17 @@ static const struct pci_dev_acs_enabled { + { PCI_VENDOR_ID_BROADCOM, 0x1762, pci_quirk_mf_endpoint_acs }, + { PCI_VENDOR_ID_BROADCOM, 0x1763, pci_quirk_mf_endpoint_acs }, + { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs }, ++ /* Loongson PCIe Root Ports */ ++ { PCI_VENDOR_ID_LOONGSON, 0x3C09, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x3C19, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x3C29, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A09, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A19, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A29, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A39, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A49, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A59, pci_quirk_loongson_acs }, ++ { PCI_VENDOR_ID_LOONGSON, 0x7A69, pci_quirk_loongson_acs }, + /* Amazon Annapurna Labs */ + { PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs }, + /* Zhaoxin multi-function devices */ +diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +index a974ef94de9a08..9598a80739910c 100644 +--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c ++++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +@@ -317,12 +317,12 @@ static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp) + static u32 phy_tx_vboost_level_from_property(u32 microvolt) + { + switch (microvolt) { +- case 0 ... 960: +- return 0; +- case 961 ... 1160: +- return 2; +- default: ++ case 1156: ++ return 5; ++ case 844: + return 3; ++ default: ++ return 4; + } + } + +diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +index 79f9c08e5039c3..5c0177b4e4a37f 100644 +--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c ++++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +@@ -358,9 +358,7 @@ static int armada_37xx_pmx_set_by_name(struct pinctrl_dev *pctldev, + + val = grp->val[func]; + +- regmap_update_bits(info->regmap, reg, mask, val); +- +- return 0; ++ return regmap_update_bits(info->regmap, reg, mask, val); + } + + static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev, +@@ -402,10 +400,13 @@ static int armada_37xx_gpio_get_direction(struct gpio_chip *chip, + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = OUTPUT_EN; + unsigned int val, mask; ++ int ret; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); +- regmap_read(info->regmap, reg, &val); ++ ret = regmap_read(info->regmap, reg, &val); ++ if (ret) ++ return ret; + + if (val & mask) + return GPIO_LINE_DIRECTION_OUT; +@@ -442,11 +443,14 @@ static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset) + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = INPUT_VAL; + unsigned int val, mask; ++ int ret; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + +- regmap_read(info->regmap, reg, &val); ++ ret = regmap_read(info->regmap, reg, &val); ++ if (ret) ++ return ret; + + return (val & mask) != 0; + } +@@ -471,16 +475,17 @@ static int armada_37xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + { + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = range->gc; ++ int ret; + + dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", + offset, range->name, offset, input ? "input" : "output"); + + if (input) +- armada_37xx_gpio_direction_input(chip, offset); ++ ret = armada_37xx_gpio_direction_input(chip, offset); + else +- armada_37xx_gpio_direction_output(chip, offset, 0); ++ ret = armada_37xx_gpio_direction_output(chip, offset, 0); + +- return 0; ++ return ret; + } + + static int armada_37xx_gpio_request_enable(struct pinctrl_dev *pctldev, +diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c +index 4d1f41488017e4..c2f4b16f42d20b 100644 +--- a/drivers/pinctrl/pinctrl-mcp23s08.c ++++ b/drivers/pinctrl/pinctrl-mcp23s08.c +@@ -636,6 +636,14 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, + + mcp->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + ++ /* ++ * Reset the chip - we don't really know what state it's in, so reset ++ * all pins to input first to prevent surprises. ++ */ ++ ret = mcp_write(mcp, MCP_IODIR, mcp->chip.ngpio == 16 ? 0xFFFF : 0xFF); ++ if (ret < 0) ++ return ret; ++ + /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, + * and MCP_IOCON.HAEN = 1, so we work with all chips. + */ +diff --git a/drivers/platform/loongarch/loongson-laptop.c b/drivers/platform/loongarch/loongson-laptop.c +index 99203584949daa..61b18ac206c9ee 100644 +--- a/drivers/platform/loongarch/loongson-laptop.c ++++ b/drivers/platform/loongarch/loongson-laptop.c +@@ -56,8 +56,7 @@ static struct input_dev *generic_inputdev; + static acpi_handle hotkey_handle; + static struct key_entry hotkey_keycode_map[GENERIC_HOTKEY_MAP_MAX]; + +-int loongson_laptop_turn_on_backlight(void); +-int loongson_laptop_turn_off_backlight(void); ++static bool bl_powered; + static int loongson_laptop_backlight_update(struct backlight_device *bd); + + /* 2. ACPI Helpers and device model */ +@@ -354,16 +353,42 @@ static int ec_backlight_level(u8 level) + return level; + } + ++static int ec_backlight_set_power(bool state) ++{ ++ int status; ++ union acpi_object arg0 = { ACPI_TYPE_INTEGER }; ++ struct acpi_object_list args = { 1, &arg0 }; ++ ++ arg0.integer.value = state; ++ status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); ++ if (ACPI_FAILURE(status)) { ++ pr_info("Loongson lvds error: 0x%x\n", status); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ + static int loongson_laptop_backlight_update(struct backlight_device *bd) + { +- int lvl = ec_backlight_level(bd->props.brightness); ++ bool target_powered = !backlight_is_blank(bd); ++ int ret = 0, lvl = ec_backlight_level(bd->props.brightness); + + if (lvl < 0) + return -EIO; ++ + if (ec_set_brightness(lvl)) + return -EIO; + +- return 0; ++ if (target_powered != bl_powered) { ++ ret = ec_backlight_set_power(target_powered); ++ if (ret < 0) ++ return ret; ++ ++ bl_powered = target_powered; ++ } ++ ++ return ret; + } + + static int loongson_laptop_get_brightness(struct backlight_device *bd) +@@ -384,7 +409,7 @@ static const struct backlight_ops backlight_laptop_ops = { + + static int laptop_backlight_register(void) + { +- int status = 0; ++ int status = 0, ret; + struct backlight_properties props; + + memset(&props, 0, sizeof(props)); +@@ -392,44 +417,20 @@ static int laptop_backlight_register(void) + if (!acpi_evalf(hotkey_handle, &status, "ECLL", "d")) + return -EIO; + +- props.brightness = 1; ++ ret = ec_backlight_set_power(true); ++ if (ret) ++ return ret; ++ ++ bl_powered = true; ++ + props.max_brightness = status; ++ props.brightness = ec_get_brightness(); ++ props.power = BACKLIGHT_POWER_ON; + props.type = BACKLIGHT_PLATFORM; + + backlight_device_register("loongson_laptop", + NULL, NULL, &backlight_laptop_ops, &props); + +- return 0; +-} +- +-int loongson_laptop_turn_on_backlight(void) +-{ +- int status; +- union acpi_object arg0 = { ACPI_TYPE_INTEGER }; +- struct acpi_object_list args = { 1, &arg0 }; +- +- arg0.integer.value = 1; +- status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); +- if (ACPI_FAILURE(status)) { +- pr_info("Loongson lvds error: 0x%x\n", status); +- return -ENODEV; +- } +- +- return 0; +-} +- +-int loongson_laptop_turn_off_backlight(void) +-{ +- int status; +- union acpi_object arg0 = { ACPI_TYPE_INTEGER }; +- struct acpi_object_list args = { 1, &arg0 }; +- +- arg0.integer.value = 0; +- status = acpi_evaluate_object(NULL, "\\BLSW", &args, NULL); +- if (ACPI_FAILURE(status)) { +- pr_info("Loongson lvds error: 0x%x\n", status); +- return -ENODEV; +- } + + return 0; + } +@@ -611,11 +612,17 @@ static int __init generic_acpi_laptop_init(void) + + static void __exit generic_acpi_laptop_exit(void) + { ++ int i; ++ + if (generic_inputdev) { +- if (input_device_registered) +- input_unregister_device(generic_inputdev); +- else ++ if (!input_device_registered) { + input_free_device(generic_inputdev); ++ } else { ++ input_unregister_device(generic_inputdev); ++ ++ for (i = 0; i < ARRAY_SIZE(generic_sub_drivers); i++) ++ generic_subdriver_exit(&generic_sub_drivers[i]); ++ } + } + } + +diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c +index 0329fafe14ebcd..f45525bbd15495 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -157,6 +157,8 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) + return -ENOMEM; + } + ++ memset_io(dev->smu_virt_addr, 0, sizeof(struct smu_metrics)); ++ + /* Start the logging */ + amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_RESET, false); + amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, false); +diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c +index 96821101ec773c..395c011e837f1b 100644 +--- a/drivers/platform/x86/amd/pmf/core.c ++++ b/drivers/platform/x86/amd/pmf/core.c +@@ -280,7 +280,7 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer) + dev_err(dev->dev, "Invalid CPU id: 0x%x", dev->cpu_id); + } + +- dev->buf = kzalloc(dev->mtable_size, GFP_KERNEL); ++ dev->buf = devm_kzalloc(dev->dev, dev->mtable_size, GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + } +@@ -493,7 +493,6 @@ static void amd_pmf_remove(struct platform_device *pdev) + mutex_destroy(&dev->lock); + mutex_destroy(&dev->update_mutex); + mutex_destroy(&dev->cb_mutex); +- kfree(dev->buf); + } + + static const struct attribute_group *amd_pmf_driver_groups[] = { +diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c +index d3bd12ad036ae0..76efce48a45ce2 100644 +--- a/drivers/platform/x86/amd/pmf/tee-if.c ++++ b/drivers/platform/x86/amd/pmf/tee-if.c +@@ -358,30 +358,28 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf, + return -EINVAL; + + /* re-alloc to the new buffer length of the policy binary */ +- new_policy_buf = memdup_user(buf, length); +- if (IS_ERR(new_policy_buf)) +- return PTR_ERR(new_policy_buf); ++ new_policy_buf = devm_kzalloc(dev->dev, length, GFP_KERNEL); ++ if (!new_policy_buf) ++ return -ENOMEM; ++ ++ if (copy_from_user(new_policy_buf, buf, length)) { ++ devm_kfree(dev->dev, new_policy_buf); ++ return -EFAULT; ++ } + +- kfree(dev->policy_buf); ++ devm_kfree(dev->dev, dev->policy_buf); + dev->policy_buf = new_policy_buf; + dev->policy_sz = length; + +- if (!amd_pmf_pb_valid(dev)) { +- ret = -EINVAL; +- goto cleanup; +- } ++ if (!amd_pmf_pb_valid(dev)) ++ return -EINVAL; + + amd_pmf_hex_dump_pb(dev); + ret = amd_pmf_start_policy_engine(dev); + if (ret < 0) +- goto cleanup; ++ return ret; + + return length; +- +-cleanup: +- kfree(dev->policy_buf); +- dev->policy_buf = NULL; +- return ret; + } + + static const struct file_operations pb_fops = { +@@ -422,12 +420,12 @@ static int amd_pmf_ta_open_session(struct tee_context *ctx, u32 *id, const uuid_ + rc = tee_client_open_session(ctx, &sess_arg, NULL); + if (rc < 0 || sess_arg.ret != 0) { + pr_err("Failed to open TEE session err:%#x, rc:%d\n", sess_arg.ret, rc); +- return rc; ++ return rc ?: -EINVAL; + } + + *id = sess_arg.session; + +- return rc; ++ return 0; + } + + static int amd_pmf_register_input_device(struct amd_pmf_dev *dev) +@@ -462,7 +460,9 @@ static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + dev->tee_ctx = tee_client_open_context(NULL, amd_pmf_amdtee_ta_match, NULL, NULL); + if (IS_ERR(dev->tee_ctx)) { + dev_err(dev->dev, "Failed to open TEE context\n"); +- return PTR_ERR(dev->tee_ctx); ++ ret = PTR_ERR(dev->tee_ctx); ++ dev->tee_ctx = NULL; ++ return ret; + } + + ret = amd_pmf_ta_open_session(dev->tee_ctx, &dev->session_id, uuid); +@@ -502,9 +502,12 @@ static int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid) + + static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) + { ++ if (!dev->tee_ctx) ++ return; + tee_shm_free(dev->fw_shm_pool); + tee_client_close_session(dev->tee_ctx, dev->session_id); + tee_client_close_context(dev->tee_ctx); ++ dev->tee_ctx = NULL; + } + + int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) +@@ -532,13 +535,13 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) + dev->policy_base = devm_ioremap_resource(dev->dev, dev->res); + if (IS_ERR(dev->policy_base)) { + ret = PTR_ERR(dev->policy_base); +- goto err_free_dram_buf; ++ goto err_cancel_work; + } + +- dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL); ++ dev->policy_buf = devm_kzalloc(dev->dev, dev->policy_sz, GFP_KERNEL); + if (!dev->policy_buf) { + ret = -ENOMEM; +- goto err_free_dram_buf; ++ goto err_cancel_work; + } + + memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz); +@@ -546,21 +549,21 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) + if (!amd_pmf_pb_valid(dev)) { + dev_info(dev->dev, "No Smart PC policy present\n"); + ret = -EINVAL; +- goto err_free_policy; ++ goto err_cancel_work; + } + + amd_pmf_hex_dump_pb(dev); + +- dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL); ++ dev->prev_data = devm_kzalloc(dev->dev, sizeof(*dev->prev_data), GFP_KERNEL); + if (!dev->prev_data) { + ret = -ENOMEM; +- goto err_free_policy; ++ goto err_cancel_work; + } + + for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) { + ret = amd_pmf_tee_init(dev, &amd_pmf_ta_uuid[i]); + if (ret) +- goto err_free_prev_data; ++ goto err_cancel_work; + + ret = amd_pmf_start_policy_engine(dev); + switch (ret) { +@@ -575,7 +578,7 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) + default: + ret = -EINVAL; + amd_pmf_tee_deinit(dev); +- goto err_free_prev_data; ++ goto err_cancel_work; + } + + if (status) +@@ -584,7 +587,7 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) + + if (!status && !pb_side_load) { + ret = -EINVAL; +- goto err_free_prev_data; ++ goto err_cancel_work; + } + + if (pb_side_load) +@@ -600,12 +603,6 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) + if (pb_side_load && dev->esbin) + amd_pmf_remove_pb(dev); + amd_pmf_tee_deinit(dev); +-err_free_prev_data: +- kfree(dev->prev_data); +-err_free_policy: +- kfree(dev->policy_buf); +-err_free_dram_buf: +- kfree(dev->buf); + err_cancel_work: + cancel_delayed_work_sync(&dev->pb_work); + +@@ -621,11 +618,5 @@ void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev) + amd_pmf_remove_pb(dev); + + cancel_delayed_work_sync(&dev->pb_work); +- kfree(dev->prev_data); +- dev->prev_data = NULL; +- kfree(dev->policy_buf); +- dev->policy_buf = NULL; +- kfree(dev->buf); +- dev->buf = NULL; + amd_pmf_tee_deinit(dev); + } +diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c +index 08b82c151e0710..eb5cbe6ae9e907 100644 +--- a/drivers/platform/x86/dell/alienware-wmi-wmax.c ++++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c +@@ -91,7 +91,7 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), + }, +- .driver_data = &g_series_quirks, ++ .driver_data = &generic_quirks, + }, + { + .ident = "Alienware m16 R2", +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index e30ca325938cb6..8dea70b7f8c154 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -292,7 +292,7 @@ static int packet_read_list(char *data, size_t * pread_length) + remaining_bytes = *pread_length; + bytes_read = rbu_data.packet_read_count; + +- list_for_each_entry(newpacket, (&packet_data_head.list)->next, list) { ++ list_for_each_entry(newpacket, &packet_data_head.list, list) { + bytes_copied = do_packet_read(pdest, newpacket, + remaining_bytes, bytes_read, &temp_count); + remaining_bytes -= bytes_copied; +@@ -315,14 +315,14 @@ static void packet_empty_list(void) + { + struct packet_data *newpacket, *tmp; + +- list_for_each_entry_safe(newpacket, tmp, (&packet_data_head.list)->next, list) { ++ list_for_each_entry_safe(newpacket, tmp, &packet_data_head.list, list) { + list_del(&newpacket->list); + + /* + * zero out the RBU packet memory before freeing + * to make sure there are no stale RBU packets left in memory + */ +- memset(newpacket->data, 0, rbu_data.packetsize); ++ memset(newpacket->data, 0, newpacket->length); + set_memory_wb((unsigned long)newpacket->data, + 1 << newpacket->ordernum); + free_pages((unsigned long) newpacket->data, +diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c +index ede483573fe0dd..b5e4da6a67798a 100644 +--- a/drivers/platform/x86/ideapad-laptop.c ++++ b/drivers/platform/x86/ideapad-laptop.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -267,6 +268,20 @@ static void ideapad_shared_exit(struct ideapad_private *priv) + */ + #define IDEAPAD_EC_TIMEOUT 200 /* in ms */ + ++/* ++ * Some models (e.g., ThinkBook since 2024) have a low tolerance for being ++ * polled too frequently. Doing so may break the state machine in the EC, ++ * resulting in a hard shutdown. ++ * ++ * It is also observed that frequent polls may disturb the ongoing operation ++ * and notably delay the availability of EC response. ++ * ++ * These values are used as the delay before the first poll and the interval ++ * between subsequent polls to solve the above issues. ++ */ ++#define IDEAPAD_EC_POLL_MIN_US 150 ++#define IDEAPAD_EC_POLL_MAX_US 300 ++ + static int eval_int(acpi_handle handle, const char *name, unsigned long *res) + { + unsigned long long result; +@@ -383,7 +398,7 @@ static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *da + end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; + + while (time_before(jiffies, end_jiffies)) { +- schedule(); ++ usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US); + + err = eval_vpcr(handle, 1, &val); + if (err) +@@ -414,7 +429,7 @@ static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long dat + end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; + + while (time_before(jiffies, end_jiffies)) { +- schedule(); ++ usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US); + + err = eval_vpcr(handle, 1, &val); + if (err) +diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +index 4aa6c227ec8202..b67bf85532aec0 100644 +--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c ++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +@@ -467,10 +467,13 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ + + /* Get the package ID from the TPMI core */ + plat_info = tpmi_get_platform_data(auxdev); +- if (plat_info) +- pkg = plat_info->package_id; +- else ++ if (unlikely(!plat_info)) { + dev_info(&auxdev->dev, "Platform information is NULL\n"); ++ ret = -ENODEV; ++ goto err_rem_common; ++ } ++ ++ pkg = plat_info->package_id; + + for (i = 0; i < num_resources; ++i) { + struct tpmi_uncore_power_domain_info *pd_info; +diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c +index d6c1ddb807b208..7a3bad106e175d 100644 +--- a/drivers/pmdomain/core.c ++++ b/drivers/pmdomain/core.c +@@ -2229,8 +2229,10 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) + return 0; + put: + put_device(&genpd->dev); +- if (genpd->free_states == genpd_free_default_power_state) ++ if (genpd->free_states == genpd_free_default_power_state) { + kfree(genpd->states); ++ genpd->states = NULL; ++ } + free: + if (genpd_is_cpu_domain(genpd)) + free_cpumask_var(genpd->cpus); +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index 2f31d750a4c1e3..93dcebbe114175 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -2131,7 +2131,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, + mutex_unlock(&di->lock); + + if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) +- return -ENODEV; ++ return di->cache.flags; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: +diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c +index ba0d22d9042950..868e95f0887e11 100644 +--- a/drivers/power/supply/bq27xxx_battery_i2c.c ++++ b/drivers/power/supply/bq27xxx_battery_i2c.c +@@ -6,6 +6,7 @@ + * Andrew F. Davis + */ + ++#include + #include + #include + #include +@@ -31,6 +32,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg, + struct i2c_msg msg[2]; + u8 data[2]; + int ret; ++ int retry = 0; + + if (!client->adapter) + return -ENODEV; +@@ -47,7 +49,16 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg, + else + msg[1].len = 2; + +- ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); ++ do { ++ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); ++ if (ret == -EBUSY && ++retry < 3) { ++ /* sleep 10 milliseconds when busy */ ++ usleep_range(10000, 11000); ++ continue; ++ } ++ break; ++ } while (1); ++ + if (ret < 0) + return ret; + +diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c +index 68390bd1004f04..3daf7befc0bf64 100644 +--- a/drivers/power/supply/collie_battery.c ++++ b/drivers/power/supply/collie_battery.c +@@ -440,6 +440,7 @@ static int collie_bat_probe(struct ucb1x00_dev *dev) + + static void collie_bat_remove(struct ucb1x00_dev *dev) + { ++ device_init_wakeup(&ucb->dev, 0); + free_irq(gpiod_to_irq(collie_bat_main.gpio_full), &collie_bat_main); + power_supply_unregister(collie_bat_bu.psy); + power_supply_unregister(collie_bat_main.psy); +diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c +index 1dfd5b0cb30d8e..1b2da9b5fb6541 100644 +--- a/drivers/power/supply/gpio-charger.c ++++ b/drivers/power/supply/gpio-charger.c +@@ -366,7 +366,9 @@ static int gpio_charger_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, gpio_charger); + +- device_init_wakeup(dev, 1); ++ ret = devm_device_init_wakeup(dev); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to init wakeup\n"); + + return 0; + } +diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c +index 51310f6e4803b9..c1640bc6accd27 100644 +--- a/drivers/power/supply/max17040_battery.c ++++ b/drivers/power/supply/max17040_battery.c +@@ -410,8 +410,9 @@ static int max17040_get_property(struct power_supply *psy, + if (!chip->channel_temp) + return -ENODATA; + +- iio_read_channel_processed_scale(chip->channel_temp, +- &val->intval, 10); ++ iio_read_channel_processed(chip->channel_temp, &val->intval); ++ val->intval /= 100; /* Convert from milli- to deci-degree */ ++ + break; + default: + return -EINVAL; +diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c +index 35a5994bf64f63..36f57d7b4a6671 100644 +--- a/drivers/ptp/ptp_clock.c ++++ b/drivers/ptp/ptp_clock.c +@@ -121,7 +121,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) + struct ptp_clock_info *ops; + int err = -EOPNOTSUPP; + +- if (ptp_clock_freerun(ptp)) { ++ if (tx->modes & (ADJ_SETOFFSET | ADJ_FREQUENCY | ADJ_OFFSET) && ++ ptp_clock_freerun(ptp)) { + pr_err("ptp: physical clock is free running\n"); + return -EBUSY; + } +diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h +index 528d86a33f37de..a6aad743c282f4 100644 +--- a/drivers/ptp/ptp_private.h ++++ b/drivers/ptp/ptp_private.h +@@ -98,7 +98,27 @@ static inline int queue_cnt(const struct timestamp_event_queue *q) + /* Check if ptp virtual clock is in use */ + static inline bool ptp_vclock_in_use(struct ptp_clock *ptp) + { +- return !ptp->is_virtual_clock; ++ bool in_use = false; ++ ++ /* Virtual clocks can't be stacked on top of virtual clocks. ++ * Avoid acquiring the n_vclocks_mux on virtual clocks, to allow this ++ * function to be called from code paths where the n_vclocks_mux of the ++ * parent physical clock is already held. Functionally that's not an ++ * issue, but lockdep would complain, because they have the same lock ++ * class. ++ */ ++ if (ptp->is_virtual_clock) ++ return false; ++ ++ if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) ++ return true; ++ ++ if (ptp->n_vclocks) ++ in_use = true; ++ ++ mutex_unlock(&ptp->n_vclocks_mux); ++ ++ return in_use; + } + + /* Check if ptp clock shall be free running */ +diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c +index 4337c8f5acf055..60dcd354237316 100644 +--- a/drivers/pwm/pwm-axi-pwmgen.c ++++ b/drivers/pwm/pwm-axi-pwmgen.c +@@ -257,7 +257,7 @@ static int axi_pwmgen_probe(struct platform_device *pdev) + struct regmap *regmap; + struct pwm_chip *chip; + struct axi_pwmgen_ddata *ddata; +- struct clk *clk; ++ struct clk *axi_clk, *clk; + void __iomem *io_base; + int ret; + +@@ -280,9 +280,26 @@ static int axi_pwmgen_probe(struct platform_device *pdev) + ddata = pwmchip_get_drvdata(chip); + ddata->regmap = regmap; + +- clk = devm_clk_get_enabled(dev, NULL); ++ /* ++ * Using NULL here instead of "axi" for backwards compatibility. There ++ * are some dtbs that don't give clock-names and have the "ext" clock ++ * as the one and only clock (due to mistake in the original bindings). ++ */ ++ axi_clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(axi_clk)) ++ return dev_err_probe(dev, PTR_ERR(axi_clk), "failed to get axi clock\n"); ++ ++ clk = devm_clk_get_optional_enabled(dev, "ext"); + if (IS_ERR(clk)) +- return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); ++ return dev_err_probe(dev, PTR_ERR(clk), "failed to get ext clock\n"); ++ ++ /* ++ * If there is no "ext" clock, it means the HDL was compiled with ++ * ASYNC_CLK_EN=0. In this case, the AXI clock is also used for the ++ * PWM output clock. ++ */ ++ if (!clk) ++ clk = axi_clk; + + ret = devm_clk_rate_exclusive_get(dev, clk); + if (ret) +diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c +index 9135227301c8d6..e548edf64eca04 100644 +--- a/drivers/rapidio/rio_cm.c ++++ b/drivers/rapidio/rio_cm.c +@@ -789,6 +789,9 @@ static int riocm_ch_send(u16 ch_id, void *buf, int len) + if (buf == NULL || ch_id == 0 || len == 0 || len > RIO_MAX_MSG_SIZE) + return -EINVAL; + ++ if (len < sizeof(struct rio_ch_chan_hdr)) ++ return -EINVAL; /* insufficient data from user */ ++ + ch = riocm_get_channel(ch_id); + if (!ch) { + riocm_error("%s(%d) ch_%d not found", current->comm, +diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c +index 5e7171b9065ae7..41fd15adfd1fdd 100644 +--- a/drivers/regulator/max14577-regulator.c ++++ b/drivers/regulator/max14577-regulator.c +@@ -40,11 +40,14 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev) + struct max14577 *max14577 = rdev_get_drvdata(rdev); + const struct maxim_charger_current *limits = + &maxim_charger_currents[max14577->dev_type]; ++ int ret; + + if (rdev_get_id(rdev) != MAX14577_CHARGER) + return -EINVAL; + +- max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); ++ ret = max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); ++ if (ret < 0) ++ return ret; + + if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) + return limits->min; +diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c +index 3d333b61fb18c8..fcdd2d0317a573 100644 +--- a/drivers/regulator/max20086-regulator.c ++++ b/drivers/regulator/max20086-regulator.c +@@ -29,7 +29,7 @@ + #define MAX20086_REG_ADC4 0x09 + + /* DEVICE IDs */ +-#define MAX20086_DEVICE_ID_MAX20086 0x40 ++#define MAX20086_DEVICE_ID_MAX20086 0x30 + #define MAX20086_DEVICE_ID_MAX20087 0x20 + #define MAX20086_DEVICE_ID_MAX20088 0x10 + #define MAX20086_DEVICE_ID_MAX20089 0x00 +@@ -264,7 +264,7 @@ static int max20086_i2c_probe(struct i2c_client *i2c) + * shutdown. + */ + flags = boot_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; +- chip->ena_gpiod = devm_gpiod_get(chip->dev, "enable", flags); ++ chip->ena_gpiod = devm_gpiod_get_optional(chip->dev, "enable", flags); + if (IS_ERR(chip->ena_gpiod)) { + ret = PTR_ERR(chip->ena_gpiod); + dev_err(chip->dev, "Failed to get enable GPIO: %d\n", ret); +diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c +index b21eedefff877a..48d146e1fa5603 100644 +--- a/drivers/remoteproc/remoteproc_core.c ++++ b/drivers/remoteproc/remoteproc_core.c +@@ -1617,7 +1617,7 @@ static int rproc_attach(struct rproc *rproc) + ret = rproc_set_rsc_table(rproc); + if (ret) { + dev_err(dev, "can't load resource table: %d\n", ret); +- goto unprepare_device; ++ goto clean_up_resources; + } + + /* reset max_notifyid */ +@@ -1634,7 +1634,7 @@ static int rproc_attach(struct rproc *rproc) + ret = rproc_handle_resources(rproc, rproc_loading_handlers); + if (ret) { + dev_err(dev, "Failed to process resources: %d\n", ret); +- goto unprepare_device; ++ goto clean_up_resources; + } + + /* Allocate carveout resources associated to rproc */ +@@ -1653,9 +1653,9 @@ static int rproc_attach(struct rproc *rproc) + + clean_up_resources: + rproc_resource_cleanup(rproc); +-unprepare_device: + /* release HW resources if needed */ + rproc_unprepare_device(rproc); ++ kfree(rproc->clean_table); + disable_iommu: + rproc_disable_iommu(rproc); + return ret; +diff --git a/drivers/remoteproc/ti_k3_m4_remoteproc.c b/drivers/remoteproc/ti_k3_m4_remoteproc.c +index a16fb165fcedd4..6cd50b16a8e82a 100644 +--- a/drivers/remoteproc/ti_k3_m4_remoteproc.c ++++ b/drivers/remoteproc/ti_k3_m4_remoteproc.c +@@ -228,7 +228,7 @@ static int k3_m4_rproc_unprepare(struct rproc *rproc) + int ret; + + /* If the core is going to be detached do not assert the module reset */ +- if (rproc->state == RPROC_ATTACHED) ++ if (rproc->state == RPROC_DETACHED) + return 0; + + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, +diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c +index 41e36af35488eb..90a84ae98b971c 100644 +--- a/drivers/s390/scsi/zfcp_sysfs.c ++++ b/drivers/s390/scsi/zfcp_sysfs.c +@@ -449,6 +449,8 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, + if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun)) + return -EINVAL; + ++ flush_work(&port->rport_work); ++ + retval = zfcp_unit_add(port, fcp_lun); + if (retval) + return retval; +diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c +index 5a5525054d71c8..5b079b8b7a082b 100644 +--- a/drivers/scsi/elx/efct/efct_hw.c ++++ b/drivers/scsi/elx/efct/efct_hw.c +@@ -1120,7 +1120,7 @@ int + efct_hw_parse_filter(struct efct_hw *hw, void *value) + { + int rc = 0; +- char *p = NULL; ++ char *p = NULL, *pp = NULL; + char *token; + u32 idx = 0; + +@@ -1132,6 +1132,7 @@ efct_hw_parse_filter(struct efct_hw *hw, void *value) + efc_log_err(hw->os, "p is NULL\n"); + return -ENOMEM; + } ++ pp = p; + + idx = 0; + while ((token = strsep(&p, ",")) && *token) { +@@ -1144,7 +1145,7 @@ efct_hw_parse_filter(struct efct_hw *hw, void *value) + if (idx == ARRAY_SIZE(hw->config.filter_def)) + break; + } +- kfree(p); ++ kfree(pp); + + return rc; + } +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index c2ec4db6728697..c256c3edd66392 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -5055,7 +5055,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, + case CMD_GEN_REQUEST64_CR: + if (iocb->ndlp == ndlp) + return 1; +- fallthrough; ++ break; + case CMD_ELS_REQUEST64_CR: + if (remote_id == ndlp->nlp_DID) + return 1; +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 6574f9e744766d..a335d34070d3c5 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -6003,9 +6003,9 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) + phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); + phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); + +- memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); +- strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, ++ memcpy(phba->BIOSVersion, cntl_attr->bios_ver_str, + sizeof(phba->BIOSVersion)); ++ phba->BIOSVersion[sizeof(phba->BIOSVersion) - 1] = '\0'; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " +diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c +index 6c9dec7e3128fd..66c9d1a2c94de2 100644 +--- a/drivers/scsi/smartpqi/smartpqi_init.c ++++ b/drivers/scsi/smartpqi/smartpqi_init.c +@@ -9709,6 +9709,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0089) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x1bd4, 0x00a3) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x00a1) +@@ -10045,6 +10049,30 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x14f0) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4044) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4054) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4084) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4094) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4140) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x207d, 0x4240) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADVANTECH, 0x8312) +@@ -10261,6 +10289,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1cc4, 0x0201) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x1018, 0x8238) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x1f3f, 0x0610) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0220) +@@ -10269,10 +10305,30 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0221) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0222) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0223) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0224) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0225) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0520) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0521) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0522) +@@ -10293,6 +10349,26 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_LENOVO, 0x0623) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0624) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0625) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0626) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0627) ++ }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ PCI_VENDOR_ID_LENOVO, 0x0628) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1014, 0x0718) +@@ -10321,6 +10397,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1137, 0x0300) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x1ded, 0x3301) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0045) +@@ -10469,6 +10549,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1f51, 0x100a) + }, ++ { ++ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, ++ 0x1f51, 0x100b) ++ }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1f51, 0x100e) +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 2e6b2412d2c946..d9e59204a9c369 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -362,7 +362,7 @@ MODULE_PARM_DESC(ring_avail_percent_lowater, + /* + * Timeout in seconds for all devices managed by this driver. + */ +-static int storvsc_timeout = 180; ++static const int storvsc_timeout = 180; + + #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) + static struct scsi_transport_template *fc_transport_template; +@@ -768,7 +768,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) + return; + } + +- t = wait_for_completion_timeout(&request->wait_event, 10*HZ); ++ t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); + if (t == 0) { + dev_err(dev, "Failed to create sub-channel: timed out\n"); + return; +@@ -833,7 +833,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device, + if (ret != 0) + return ret; + +- t = wait_for_completion_timeout(&request->wait_event, 5*HZ); ++ t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); + if (t == 0) + return -ETIMEDOUT; + +@@ -1350,6 +1350,8 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size, + return ret; + + ret = storvsc_channel_init(device, is_fc); ++ if (ret) ++ vmbus_close(device->channel); + + return ret; + } +@@ -1668,7 +1670,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) + if (ret != 0) + return FAILED; + +- t = wait_for_completion_timeout(&request->wait_event, 5*HZ); ++ t = wait_for_completion_timeout(&request->wait_event, storvsc_timeout * HZ); + if (t == 0) + return TIMEOUT_ERROR; + +diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c +index bd06ce16180411..7f11acd33323b7 100644 +--- a/drivers/soc/qcom/pmic_glink_altmode.c ++++ b/drivers/soc/qcom/pmic_glink_altmode.c +@@ -218,21 +218,29 @@ static void pmic_glink_altmode_worker(struct work_struct *work) + { + struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work); + struct pmic_glink_altmode *altmode = alt_port->altmode; ++ enum drm_connector_status conn_status; + + typec_switch_set(alt_port->typec_switch, alt_port->orientation); + +- if (alt_port->svid == USB_TYPEC_DP_SID && alt_port->mode == 0xff) +- pmic_glink_altmode_safe(altmode, alt_port); +- else if (alt_port->svid == USB_TYPEC_DP_SID) +- pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode, +- alt_port->hpd_state, alt_port->hpd_irq); +- else +- pmic_glink_altmode_enable_usb(altmode, alt_port); ++ if (alt_port->svid == USB_TYPEC_DP_SID) { ++ if (alt_port->mode == 0xff) { ++ pmic_glink_altmode_safe(altmode, alt_port); ++ } else { ++ pmic_glink_altmode_enable_dp(altmode, alt_port, ++ alt_port->mode, ++ alt_port->hpd_state, ++ alt_port->hpd_irq); ++ } + +- drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, +- alt_port->hpd_state ? +- connector_status_connected : +- connector_status_disconnected); ++ if (alt_port->hpd_state) ++ conn_status = connector_status_connected; ++ else ++ conn_status = connector_status_disconnected; ++ ++ drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status); ++ } else { ++ pmic_glink_altmode_enable_usb(altmode, alt_port); ++ } + + pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index); + } +diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c +index 44a8f58e46fe12..d3a4e091dca4ee 100644 +--- a/drivers/spi/spi-qpic-snand.c ++++ b/drivers/spi/spi-qpic-snand.c +@@ -1636,6 +1636,7 @@ static void qcom_spi_remove(struct platform_device *pdev) + + static const struct qcom_nandc_props ipq9574_snandc_props = { + .dev_cmd_reg_start = 0x7000, ++ .bam_offset = 0x30000, + .supports_bam = true, + }; + +diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c +index d5544fc2fe989b..f8fcc10ea81509 100644 +--- a/drivers/staging/iio/impedance-analyzer/ad5933.c ++++ b/drivers/staging/iio/impedance-analyzer/ad5933.c +@@ -411,7 +411,7 @@ static ssize_t ad5933_store(struct device *dev, + ret = ad5933_cmd(st, 0); + break; + case AD5933_OUT_SETTLING_CYCLES: +- val = clamp(val, (u16)0, (u16)0x7FF); ++ val = clamp(val, (u16)0, (u16)0x7FC); + st->settling_cycles = val; + + /* 2x, 4x handling, see datasheet */ +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index a9bfd5305410c2..65befffc356966 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -825,24 +825,24 @@ static int rkvdec_open(struct file *filp) + rkvdec_reset_decoded_fmt(ctx); + v4l2_fh_init(&ctx->fh, video_devdata(filp)); + +- ret = rkvdec_init_ctrls(ctx); +- if (ret) +- goto err_free_ctx; +- + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rkvdec->m2m_dev, ctx, + rkvdec_queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); +- goto err_cleanup_ctrls; ++ goto err_free_ctx; + } + ++ ret = rkvdec_init_ctrls(ctx); ++ if (ret) ++ goto err_cleanup_m2m_ctx; ++ + filp->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + return 0; + +-err_cleanup_ctrls: +- v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++err_cleanup_m2m_ctx: ++ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + err_free_ctx: + kfree(ctx); +diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c +index d113679b1e2d7a..acc7998758ad84 100644 +--- a/drivers/tee/tee_core.c ++++ b/drivers/tee/tee_core.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -19,7 +20,7 @@ + + #define TEE_NUM_DEVICES 32 + +-#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) ++#define TEE_IOCTL_PARAM_SIZE(x) (size_mul(sizeof(struct tee_param), (x))) + + #define TEE_UUID_NS_NAME_SIZE 128 + +@@ -487,7 +488,7 @@ static int tee_ioctl_open_session(struct tee_context *ctx, + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + +- if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) ++ if (size_add(sizeof(arg), TEE_IOCTL_PARAM_SIZE(arg.num_params)) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { +@@ -565,7 +566,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx, + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + +- if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) ++ if (size_add(sizeof(arg), TEE_IOCTL_PARAM_SIZE(arg.num_params)) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { +@@ -699,7 +700,7 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx, + if (get_user(num_params, &uarg->num_params)) + return -EFAULT; + +- if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) ++ if (size_add(sizeof(*uarg), TEE_IOCTL_PARAM_SIZE(num_params)) != buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); +@@ -798,7 +799,7 @@ static int tee_ioctl_supp_send(struct tee_context *ctx, + get_user(num_params, &uarg->num_params)) + return -EFAULT; + +- if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) ++ if (size_add(sizeof(*uarg), TEE_IOCTL_PARAM_SIZE(num_params)) > buf.buf_len) + return -EINVAL; + + params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); +diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c +index 69c1df0f4ca541..aac67a4413cea9 100644 +--- a/drivers/uio/uio_hv_generic.c ++++ b/drivers/uio/uio_hv_generic.c +@@ -243,6 +243,9 @@ hv_uio_probe(struct hv_device *dev, + if (!ring_size) + ring_size = SZ_2M; + ++ /* Adjust ring size if necessary to have it page aligned */ ++ ring_size = VMBUS_RING_SIZE(ring_size); ++ + pdata = devm_kzalloc(&dev->device, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; +@@ -274,13 +277,13 @@ hv_uio_probe(struct hv_device *dev, + pdata->info.mem[INT_PAGE_MAP].name = "int_page"; + pdata->info.mem[INT_PAGE_MAP].addr + = (uintptr_t)vmbus_connection.int_page; +- pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; ++ pdata->info.mem[INT_PAGE_MAP].size = HV_HYP_PAGE_SIZE; + pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + pdata->info.mem[MON_PAGE_MAP].name = "monitor_page"; + pdata->info.mem[MON_PAGE_MAP].addr + = (uintptr_t)vmbus_connection.monitor_pages[1]; +- pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; ++ pdata->info.mem[MON_PAGE_MAP].size = HV_HYP_PAGE_SIZE; + pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + if (channel->device_id == HV_NIC) { +diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c +index 139049368fdcf8..7d02470f19b932 100644 +--- a/drivers/video/console/dummycon.c ++++ b/drivers/video/console/dummycon.c +@@ -85,6 +85,15 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + /* Redraw, so that we get putc(s) for output done while blanked */ + return true; + } ++ ++static bool dummycon_switch(struct vc_data *vc) ++{ ++ /* ++ * Redraw, so that we get putc(s) for output done while switched ++ * away. Informs deferred consoles to take over the display. ++ */ ++ return true; ++} + #else + static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y, + unsigned int x) { } +@@ -95,6 +104,10 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank, + { + return false; + } ++static bool dummycon_switch(struct vc_data *vc) ++{ ++ return false; ++} + #endif + + static const char *dummycon_startup(void) +@@ -124,11 +137,6 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top, + return false; + } + +-static bool dummycon_switch(struct vc_data *vc) +-{ +- return false; +-} +- + /* + * The console `switch' structure for the dummy console + * +diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c +index 37bd18730fe0df..f9cdbf8c53e34b 100644 +--- a/drivers/video/console/vgacon.c ++++ b/drivers/video/console/vgacon.c +@@ -1168,7 +1168,7 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, + c->vc_screenbuf_size - delta); + c->vc_origin = vga_vram_end - c->vc_screenbuf_size; + vga_rolled_over = 0; +- } else ++ } else if (oldo - delta >= (unsigned long)c->vc_screenbuf) + c->vc_origin -= delta; + c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; + scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index ac3c99ed92d1aa..2df48037688d1d 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -117,9 +117,14 @@ static signed char con2fb_map_boot[MAX_NR_CONSOLES]; + + static struct fb_info *fbcon_info_from_console(int console) + { ++ signed char fb; + WARN_CONSOLE_UNLOCKED(); + +- return fbcon_registered_fb[con2fb_map[console]]; ++ fb = con2fb_map[console]; ++ if (fb < 0 || fb >= ARRAY_SIZE(fbcon_registered_fb)) ++ return NULL; ++ ++ return fbcon_registered_fb[fb]; + } + + static int logo_lines; +diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c +index 3c568cff2913e4..eca2498f243685 100644 +--- a/drivers/video/fbdev/core/fbmem.c ++++ b/drivers/video/fbdev/core/fbmem.c +@@ -328,8 +328,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) + !list_empty(&info->modelist)) + ret = fb_add_videomode(&mode, &info->modelist); + +- if (ret) ++ if (ret) { ++ info->var = old_var; + return ret; ++ } + + event.info = info; + event.data = &mode; +@@ -388,7 +390,7 @@ static int fb_check_foreignness(struct fb_info *fi) + + static int do_register_framebuffer(struct fb_info *fb_info) + { +- int i; ++ int i, err = 0; + struct fb_videomode mode; + + if (fb_check_foreignness(fb_info)) +@@ -397,10 +399,18 @@ static int do_register_framebuffer(struct fb_info *fb_info) + if (num_registered_fb == FB_MAX) + return -ENXIO; + +- num_registered_fb++; + for (i = 0 ; i < FB_MAX; i++) + if (!registered_fb[i]) + break; ++ ++ if (!fb_info->modelist.prev || !fb_info->modelist.next) ++ INIT_LIST_HEAD(&fb_info->modelist); ++ ++ fb_var_to_videomode(&mode, &fb_info->var); ++ err = fb_add_videomode(&mode, &fb_info->modelist); ++ if (err < 0) ++ return err; ++ + fb_info->node = i; + refcount_set(&fb_info->count, 1); + mutex_init(&fb_info->lock); +@@ -426,16 +436,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) + if (bitmap_empty(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT)) + bitmap_fill(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT); + +- if (!fb_info->modelist.prev || !fb_info->modelist.next) +- INIT_LIST_HEAD(&fb_info->modelist); +- + if (fb_info->skip_vt_switch) + pm_vt_switch_required(fb_info->device, false); + else + pm_vt_switch_required(fb_info->device, true); + +- fb_var_to_videomode(&mode, &fb_info->var); +- fb_add_videomode(&mode, &fb_info->modelist); ++ num_registered_fb++; + registered_fb[i] = fb_info; + + #ifdef CONFIG_GUMSTIX_AM200EPD +diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c +index 6c583351714100..66bfc1d0a6dc82 100644 +--- a/drivers/video/screen_info_pci.c ++++ b/drivers/video/screen_info_pci.c +@@ -7,8 +7,8 @@ + + static struct pci_dev *screen_info_lfb_pdev; + static size_t screen_info_lfb_bar; +-static resource_size_t screen_info_lfb_offset; +-static struct resource screen_info_lfb_res = DEFINE_RES_MEM(0, 0); ++static resource_size_t screen_info_lfb_res_start; // original start of resource ++static resource_size_t screen_info_lfb_offset; // framebuffer offset within resource + + static bool __screen_info_relocation_is_valid(const struct screen_info *si, struct resource *pr) + { +@@ -31,7 +31,7 @@ void screen_info_apply_fixups(void) + if (screen_info_lfb_pdev) { + struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar]; + +- if (pr->start != screen_info_lfb_res.start) { ++ if (pr->start != screen_info_lfb_res_start) { + if (__screen_info_relocation_is_valid(si, pr)) { + /* + * Only update base if we have an actual +@@ -47,46 +47,67 @@ void screen_info_apply_fixups(void) + } + } + ++static int __screen_info_lfb_pci_bus_region(const struct screen_info *si, unsigned int type, ++ struct pci_bus_region *r) ++{ ++ u64 base, size; ++ ++ base = __screen_info_lfb_base(si); ++ if (!base) ++ return -EINVAL; ++ ++ size = __screen_info_lfb_size(si, type); ++ if (!size) ++ return -EINVAL; ++ ++ r->start = base; ++ r->end = base + size - 1; ++ ++ return 0; ++} ++ + static void screen_info_fixup_lfb(struct pci_dev *pdev) + { + unsigned int type; +- struct resource res[SCREEN_INFO_MAX_RESOURCES]; +- size_t i, numres; ++ struct pci_bus_region bus_region; + int ret; ++ struct resource r = { ++ .flags = IORESOURCE_MEM, ++ }; ++ const struct resource *pr; + const struct screen_info *si = &screen_info; + + if (screen_info_lfb_pdev) + return; // already found + + type = screen_info_video_type(si); +- if (type != VIDEO_TYPE_EFI) +- return; // only applies to EFI ++ if (!__screen_info_has_lfb(type)) ++ return; // only applies to EFI; maybe VESA + +- ret = screen_info_resources(si, res, ARRAY_SIZE(res)); ++ ret = __screen_info_lfb_pci_bus_region(si, type, &bus_region); + if (ret < 0) + return; +- numres = ret; + +- for (i = 0; i < numres; ++i) { +- struct resource *r = &res[i]; +- const struct resource *pr; +- +- if (!(r->flags & IORESOURCE_MEM)) +- continue; +- pr = pci_find_resource(pdev, r); +- if (!pr) +- continue; +- +- /* +- * We've found a PCI device with the framebuffer +- * resource. Store away the parameters to track +- * relocation of the framebuffer aperture. +- */ +- screen_info_lfb_pdev = pdev; +- screen_info_lfb_bar = pr - pdev->resource; +- screen_info_lfb_offset = r->start - pr->start; +- memcpy(&screen_info_lfb_res, r, sizeof(screen_info_lfb_res)); +- } ++ /* ++ * Translate the PCI bus address to resource. Account ++ * for an offset if the framebuffer is behind a PCI host ++ * bridge. ++ */ ++ pcibios_bus_to_resource(pdev->bus, &r, &bus_region); ++ ++ pr = pci_find_resource(pdev, &r); ++ if (!pr) ++ return; ++ ++ /* ++ * We've found a PCI device with the framebuffer ++ * resource. Store away the parameters to track ++ * relocation of the framebuffer aperture. ++ */ ++ screen_info_lfb_pdev = pdev; ++ screen_info_lfb_bar = pr - pdev->resource; ++ screen_info_lfb_offset = r.start - pr->start; ++ screen_info_lfb_res_start = bus_region.start; + } + DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16, + screen_info_fixup_lfb); +diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c +index 9432d4e303f16b..8a638bc34d4a9e 100644 +--- a/drivers/virt/coco/tsm.c ++++ b/drivers/virt/coco/tsm.c +@@ -15,6 +15,7 @@ + static struct tsm_provider { + const struct tsm_ops *ops; + void *data; ++ atomic_t count; + } provider; + static DECLARE_RWSEM(tsm_rwsem); + +@@ -92,6 +93,10 @@ static ssize_t tsm_report_privlevel_store(struct config_item *cfg, + if (rc) + return rc; + ++ guard(rwsem_write)(&tsm_rwsem); ++ if (!provider.ops) ++ return -ENXIO; ++ + /* + * The valid privilege levels that a TSM might accept, if it accepts a + * privilege level setting at all, are a max of TSM_PRIVLEVEL_MAX (see +@@ -101,7 +106,6 @@ static ssize_t tsm_report_privlevel_store(struct config_item *cfg, + if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX) + return -EINVAL; + +- guard(rwsem_write)(&tsm_rwsem); + rc = try_advance_write_generation(report); + if (rc) + return rc; +@@ -115,6 +119,10 @@ static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg, + char *buf) + { + guard(rwsem_read)(&tsm_rwsem); ++ ++ if (!provider.ops) ++ return -ENXIO; ++ + return sysfs_emit(buf, "%u\n", provider.ops->privlevel_floor); + } + CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor); +@@ -217,6 +225,9 @@ CONFIGFS_ATTR_RO(tsm_report_, generation); + static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf) + { + guard(rwsem_read)(&tsm_rwsem); ++ if (!provider.ops) ++ return -ENXIO; ++ + return sysfs_emit(buf, "%s\n", provider.ops->name); + } + CONFIGFS_ATTR_RO(tsm_report_, provider); +@@ -284,7 +295,7 @@ static ssize_t tsm_report_read(struct tsm_report *report, void *buf, + guard(rwsem_write)(&tsm_rwsem); + ops = provider.ops; + if (!ops) +- return -ENOTTY; ++ return -ENXIO; + if (!report->desc.inblob_len) + return -EINVAL; + +@@ -421,12 +432,20 @@ static struct config_item *tsm_report_make_item(struct config_group *group, + if (!state) + return ERR_PTR(-ENOMEM); + ++ atomic_inc(&provider.count); + config_item_init_type_name(&state->cfg, name, &tsm_report_type); + return &state->cfg; + } + ++static void tsm_report_drop_item(struct config_group *group, struct config_item *item) ++{ ++ config_item_put(item); ++ atomic_dec(&provider.count); ++} ++ + static struct configfs_group_operations tsm_report_group_ops = { + .make_item = tsm_report_make_item, ++ .drop_item = tsm_report_drop_item, + }; + + static const struct config_item_type tsm_reports_type = { +@@ -459,6 +478,11 @@ int tsm_register(const struct tsm_ops *ops, void *priv) + return -EBUSY; + } + ++ if (atomic_read(&provider.count)) { ++ pr_err("configfs/tsm/report not empty\n"); ++ return -EBUSY; ++ } ++ + provider.ops = ops; + provider.data = priv; + return 0; +@@ -470,6 +494,9 @@ int tsm_unregister(const struct tsm_ops *ops) + guard(rwsem_write)(&tsm_rwsem); + if (ops != provider.ops) + return -EBUSY; ++ if (atomic_read(&provider.count)) ++ pr_warn("\"%s\" unregistered with items present in configfs/tsm/report\n", ++ provider.ops->name); + provider.ops = NULL; + provider.data = NULL; + return 0; +diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c +index 77039f2f0be542..bc0946233ced00 100644 +--- a/drivers/watchdog/da9052_wdt.c ++++ b/drivers/watchdog/da9052_wdt.c +@@ -168,6 +168,7 @@ static int da9052_wdt_probe(struct platform_device *pdev) + da9052_wdt = &driver_data->wdt; + + da9052_wdt->timeout = DA9052_DEF_TIMEOUT; ++ da9052_wdt->min_hw_heartbeat_ms = DA9052_TWDMIN; + da9052_wdt->info = &da9052_wdt_info; + da9052_wdt->ops = &da9052_wdt_ops; + da9052_wdt->parent = dev; +diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c +index 8ad06b54c5adc6..b356a272ff9a0a 100644 +--- a/drivers/watchdog/stm32_iwdg.c ++++ b/drivers/watchdog/stm32_iwdg.c +@@ -291,7 +291,7 @@ static int stm32_iwdg_irq_init(struct platform_device *pdev, + return 0; + + if (of_property_read_bool(np, "wakeup-source")) { +- ret = device_init_wakeup(dev, true); ++ ret = devm_device_init_wakeup(dev); + if (ret) + return ret; + +diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c +index 583ac81669c249..e51e7d88980a22 100644 +--- a/fs/anon_inodes.c ++++ b/fs/anon_inodes.c +@@ -24,9 +24,50 @@ + + #include + ++#include "internal.h" ++ + static struct vfsmount *anon_inode_mnt __ro_after_init; + static struct inode *anon_inode_inode __ro_after_init; + ++/* ++ * User space expects anonymous inodes to have no file type in st_mode. ++ * ++ * In particular, 'lsof' has this legacy logic: ++ * ++ * type = s->st_mode & S_IFMT; ++ * switch (type) { ++ * ... ++ * case 0: ++ * if (!strcmp(p, "anon_inode")) ++ * Lf->ntype = Ntype = N_ANON_INODE; ++ * ++ * to detect our old anon_inode logic. ++ * ++ * Rather than mess with our internal sane inode data, just fix it ++ * up here in getattr() by masking off the format bits. ++ */ ++int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path, ++ struct kstat *stat, u32 request_mask, ++ unsigned int query_flags) ++{ ++ struct inode *inode = d_inode(path->dentry); ++ ++ generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); ++ stat->mode &= ~S_IFMT; ++ return 0; ++} ++ ++int anon_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, ++ struct iattr *attr) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static const struct inode_operations anon_inode_operations = { ++ .getattr = anon_inode_getattr, ++ .setattr = anon_inode_setattr, ++}; ++ + /* + * anon_inodefs_dname() is called from d_path(). + */ +@@ -45,6 +86,8 @@ static int anon_inodefs_init_fs_context(struct fs_context *fc) + struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC); + if (!ctx) + return -ENOMEM; ++ fc->s_iflags |= SB_I_NOEXEC; ++ fc->s_iflags |= SB_I_NODEV; + ctx->dops = &anon_inodefs_dentry_operations; + return 0; + } +@@ -66,6 +109,7 @@ static struct inode *anon_inode_make_secure_inode( + if (IS_ERR(inode)) + return inode; + inode->i_flags &= ~S_PRIVATE; ++ inode->i_op = &anon_inode_operations; + error = security_inode_init_security_anon(inode, &QSTR(name), + context_inode); + if (error) { +@@ -313,6 +357,7 @@ static int __init anon_inode_init(void) + anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb); + if (IS_ERR(anon_inode_inode)) + panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode)); ++ anon_inode_inode->i_op = &anon_inode_operations; + + return 0; + } +diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c +index b95c4cb21c13f0..60a621b00c656d 100644 +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -409,6 +409,15 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) + struct page **pages; + size_t page_off; + ++ /* ++ * FIXME: io_iter.count needs to be corrected to aligned ++ * length. Otherwise, iov_iter_get_pages_alloc2() operates ++ * with the initial unaligned length value. As a result, ++ * ceph_msg_data_cursor_init() triggers BUG_ON() in the case ++ * if msg->sparse_read_total > msg->data_length. ++ */ ++ subreq->io_iter.count = len; ++ + err = iov_iter_get_pages_alloc2(&subreq->io_iter, &pages, len, &page_off); + if (err < 0) { + doutc(cl, "%llx.%llx failed to allocate pages, %d\n", +diff --git a/fs/ceph/super.c b/fs/ceph/super.c +index f3951253e393a6..fc4cab8b7b7781 100644 +--- a/fs/ceph/super.c ++++ b/fs/ceph/super.c +@@ -1227,6 +1227,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc) + s->s_time_min = 0; + s->s_time_max = U32_MAX; + s->s_flags |= SB_NODIRATIME | SB_NOATIME; ++ s->s_magic = CEPH_SUPER_MAGIC; + + ceph_fscrypt_set_ops(s); + +diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c +index 5568cb74b32243..f43be44bff6243 100644 +--- a/fs/configfs/dir.c ++++ b/fs/configfs/dir.c +@@ -619,7 +619,7 @@ static int populate_attrs(struct config_item *item) + break; + } + } +- if (t->ct_bin_attrs) { ++ if (!error && t->ct_bin_attrs) { + for (i = 0; (bin_attr = t->ct_bin_attrs[i]) != NULL; i++) { + if (ops && ops->is_bin_visible && !ops->is_bin_visible(item, bin_attr, i)) + continue; +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 70abd4da17a63a..90abcd07f8898d 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -160,6 +160,7 @@ struct dlm_proto_ops { + bool try_new_addr; + const char *name; + int proto; ++ int how; + + void (*sockopts)(struct socket *sock); + int (*bind)(struct socket *sock); +@@ -810,7 +811,7 @@ static void shutdown_connection(struct connection *con, bool and_other) + return; + } + +- ret = kernel_sock_shutdown(con->sock, SHUT_WR); ++ ret = kernel_sock_shutdown(con->sock, dlm_proto_ops->how); + up_read(&con->sock_lock); + if (ret) { + log_print("Connection %p failed to shutdown: %d will force close", +@@ -1858,6 +1859,7 @@ static int dlm_tcp_listen_bind(struct socket *sock) + static const struct dlm_proto_ops dlm_tcp_ops = { + .name = "TCP", + .proto = IPPROTO_TCP, ++ .how = SHUT_WR, + .sockopts = dlm_tcp_sockopts, + .bind = dlm_tcp_bind, + .listen_validate = dlm_tcp_listen_validate, +@@ -1896,6 +1898,7 @@ static void dlm_sctp_sockopts(struct socket *sock) + static const struct dlm_proto_ops dlm_sctp_ops = { + .name = "SCTP", + .proto = IPPROTO_SCTP, ++ .how = SHUT_RDWR, + .try_new_addr = true, + .sockopts = dlm_sctp_sockopts, + .bind = dlm_sctp_bind, +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index 14ea47f954f552..0bebc6e3a4d7dd 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -597,6 +597,10 @@ static int z_erofs_map_blocks_ext(struct inode *inode, + + if (la > map->m_la) { + r = mid; ++ if (la > lend) { ++ DBG_BUGON(1); ++ return -EFSCORRUPTED; ++ } + lend = la; + } else { + l = mid + 1; +@@ -635,12 +639,6 @@ static int z_erofs_map_blocks_ext(struct inode *inode, + } + } + map->m_llen = lend - map->m_la; +- if (!last && map->m_llen < sb->s_blocksize) { +- erofs_err(sb, "extent too small %llu @ offset %llu of nid %llu", +- map->m_llen, map->m_la, vi->nid); +- DBG_BUGON(1); +- return -EFSCORRUPTED; +- } + return 0; + } + +diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c +index d47896a895965b..1729bf42eb5169 100644 +--- a/fs/exfat/nls.c ++++ b/fs/exfat/nls.c +@@ -801,4 +801,5 @@ int exfat_create_upcase_table(struct super_block *sb) + void exfat_free_upcase_table(struct exfat_sb_info *sbi) + { + kvfree(sbi->vol_utbl); ++ sbi->vol_utbl = NULL; + } +diff --git a/fs/exfat/super.c b/fs/exfat/super.c +index 8465033a6cf0c0..7ed858937d45d2 100644 +--- a/fs/exfat/super.c ++++ b/fs/exfat/super.c +@@ -36,31 +36,12 @@ static void exfat_put_super(struct super_block *sb) + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + mutex_lock(&sbi->s_lock); ++ exfat_clear_volume_dirty(sb); + exfat_free_bitmap(sbi); + brelse(sbi->boot_bh); + mutex_unlock(&sbi->s_lock); + } + +-static int exfat_sync_fs(struct super_block *sb, int wait) +-{ +- struct exfat_sb_info *sbi = EXFAT_SB(sb); +- int err = 0; +- +- if (unlikely(exfat_forced_shutdown(sb))) +- return 0; +- +- if (!wait) +- return 0; +- +- /* If there are some dirty buffers in the bdev inode */ +- mutex_lock(&sbi->s_lock); +- sync_blockdev(sb->s_bdev); +- if (exfat_clear_volume_dirty(sb)) +- err = -EIO; +- mutex_unlock(&sbi->s_lock); +- return err; +-} +- + static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) + { + struct super_block *sb = dentry->d_sb; +@@ -219,7 +200,6 @@ static const struct super_operations exfat_sops = { + .write_inode = exfat_write_inode, + .evict_inode = exfat_evict_inode, + .put_super = exfat_put_super, +- .sync_fs = exfat_sync_fs, + .statfs = exfat_statfs, + .show_options = exfat_show_options, + .shutdown = exfat_shutdown, +@@ -751,10 +731,14 @@ static void exfat_free(struct fs_context *fc) + + static int exfat_reconfigure(struct fs_context *fc) + { ++ struct super_block *sb = fc->root->d_sb; + fc->sb_flags |= SB_NODIRATIME; + +- /* volume flag will be updated in exfat_sync_fs */ +- sync_filesystem(fc->root->d_sb); ++ sync_filesystem(sb); ++ mutex_lock(&EXFAT_SB(sb)->s_lock); ++ exfat_clear_volume_dirty(sb); ++ mutex_unlock(&EXFAT_SB(sb)->s_lock); ++ + return 0; + } + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 5a20e9cd718491..8664bb5367c53b 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -3378,6 +3378,13 @@ static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi) + return 1 << sbi->s_log_groups_per_flex; + } + ++static inline loff_t ext4_get_maxbytes(struct inode *inode) ++{ ++ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) ++ return inode->i_sb->s_maxbytes; ++ return EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; ++} ++ + #define ext4_std_error(sb, errno) \ + do { \ + if ((errno)) \ +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index c616a16a9f36d3..828a78a9600a81 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -1530,7 +1530,7 @@ static int ext4_ext_search_left(struct inode *inode, + static int ext4_ext_search_right(struct inode *inode, + struct ext4_ext_path *path, + ext4_lblk_t *logical, ext4_fsblk_t *phys, +- struct ext4_extent *ret_ex) ++ struct ext4_extent *ret_ex, int flags) + { + struct buffer_head *bh = NULL; + struct ext4_extent_header *eh; +@@ -1604,7 +1604,8 @@ static int ext4_ext_search_right(struct inode *inode, + ix++; + while (++depth < path->p_depth) { + /* subtract from p_depth to get proper eh_depth */ +- bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0); ++ bh = read_extent_tree_block(inode, ix, path->p_depth - depth, ++ flags); + if (IS_ERR(bh)) + return PTR_ERR(bh); + eh = ext_block_hdr(bh); +@@ -1612,7 +1613,7 @@ static int ext4_ext_search_right(struct inode *inode, + put_bh(bh); + } + +- bh = read_extent_tree_block(inode, ix, path->p_depth - depth, 0); ++ bh = read_extent_tree_block(inode, ix, path->p_depth - depth, flags); + if (IS_ERR(bh)) + return PTR_ERR(bh); + eh = ext_block_hdr(bh); +@@ -2396,18 +2397,19 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks, + int ext4_ext_index_trans_blocks(struct inode *inode, int extents) + { + int index; +- int depth; + + /* If we are converting the inline data, only one is needed here. */ + if (ext4_has_inline_data(inode)) + return 1; + +- depth = ext_depth(inode); +- ++ /* ++ * Extent tree can change between the time we estimate credits and ++ * the time we actually modify the tree. Assume the worst case. ++ */ + if (extents <= 1) +- index = depth * 2; ++ index = EXT4_MAX_EXTENT_DEPTH * 2; + else +- index = depth * 3; ++ index = EXT4_MAX_EXTENT_DEPTH * 3; + + return index; + } +@@ -2821,6 +2823,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + struct partial_cluster partial; + handle_t *handle; + int i = 0, err = 0; ++ int flags = EXT4_EX_NOCACHE | EXT4_EX_NOFAIL; + + partial.pclu = 0; + partial.lblk = 0; +@@ -2851,8 +2854,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + ext4_fsblk_t pblk; + + /* find extent for or closest extent to this block */ +- path = ext4_find_extent(inode, end, NULL, +- EXT4_EX_NOCACHE | EXT4_EX_NOFAIL); ++ path = ext4_find_extent(inode, end, NULL, flags); + if (IS_ERR(path)) { + ext4_journal_stop(handle); + return PTR_ERR(path); +@@ -2918,7 +2920,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + */ + lblk = ex_end + 1; + err = ext4_ext_search_right(inode, path, &lblk, &pblk, +- NULL); ++ NULL, flags); + if (err < 0) + goto out; + if (pblk) { +@@ -2994,8 +2996,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, + i + 1, ext4_idx_pblock(path[i].p_idx)); + memset(path + i + 1, 0, sizeof(*path)); + bh = read_extent_tree_block(inode, path[i].p_idx, +- depth - i - 1, +- EXT4_EX_NOCACHE); ++ depth - i - 1, flags); + if (IS_ERR(bh)) { + /* should we reset i_size? */ + err = PTR_ERR(bh); +@@ -4314,7 +4315,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, + if (err) + goto out; + ar.lright = map->m_lblk; +- err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2); ++ err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, ++ &ex2, 0); + if (err < 0) + goto out; + +@@ -4931,12 +4933,7 @@ static const struct iomap_ops ext4_iomap_xattr_ops = { + + static int ext4_fiemap_check_ranges(struct inode *inode, u64 start, u64 *len) + { +- u64 maxbytes; +- +- if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) +- maxbytes = inode->i_sb->s_maxbytes; +- else +- maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; ++ u64 maxbytes = ext4_get_maxbytes(inode); + + if (*len == 0) + return -EINVAL; +@@ -4999,7 +4996,9 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, + } + + if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) { ++ inode_lock_shared(inode); + error = ext4_ext_precache(inode); ++ inode_unlock_shared(inode); + if (error) + return error; + fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE; +diff --git a/fs/ext4/file.c b/fs/ext4/file.c +index beb078ee4811d6..b845a25f7932c6 100644 +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -929,12 +929,7 @@ static int ext4_file_open(struct inode *inode, struct file *filp) + loff_t ext4_llseek(struct file *file, loff_t offset, int whence) + { + struct inode *inode = file->f_mapping->host; +- loff_t maxbytes; +- +- if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) +- maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; +- else +- maxbytes = inode->i_sb->s_maxbytes; ++ loff_t maxbytes = ext4_get_maxbytes(inode); + + switch (whence) { + default: +diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c +index 2c9b762925c72f..e5e6bf0d338b96 100644 +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -397,7 +397,7 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode, + } + + static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, +- unsigned int len) ++ loff_t len) + { + int ret, size, no_expand; + struct ext4_inode_info *ei = EXT4_I(inode); +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 94c7d2d828a64e..7fcdc01a0220a7 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1009,7 +1009,12 @@ int ext4_walk_page_buffers(handle_t *handle, struct inode *inode, + */ + static int ext4_dirty_journalled_data(handle_t *handle, struct buffer_head *bh) + { +- folio_mark_dirty(bh->b_folio); ++ struct folio *folio = bh->b_folio; ++ struct inode *inode = folio->mapping->host; ++ ++ /* only regular files have a_ops */ ++ if (S_ISREG(inode->i_mode)) ++ folio_mark_dirty(folio); + return ext4_handle_dirty_metadata(handle, NULL, bh); + } + +@@ -4006,7 +4011,7 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + ext4_lblk_t start_lblk, end_lblk; +- loff_t max_end = EXT4_SB(sb)->s_bitmap_maxbytes - sb->s_blocksize; ++ loff_t max_end = sb->s_maxbytes; + loff_t end = offset + length; + handle_t *handle; + unsigned int credits; +@@ -4015,14 +4020,20 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + trace_ext4_punch_hole(inode, offset, length, 0); + WARN_ON_ONCE(!inode_is_locked(inode)); + ++ /* ++ * For indirect-block based inodes, make sure that the hole within ++ * one block before last range. ++ */ ++ if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) ++ max_end = EXT4_SB(sb)->s_bitmap_maxbytes - sb->s_blocksize; ++ + /* No need to punch hole beyond i_size */ +- if (offset >= inode->i_size) ++ if (offset >= inode->i_size || offset >= max_end) + return 0; + + /* + * If the hole extends beyond i_size, set the hole to end after +- * the page that contains i_size, and also make sure that the hole +- * within one block before last range. ++ * the page that contains i_size. + */ + if (end > inode->i_size) + end = round_up(inode->i_size, PAGE_SIZE); +@@ -4916,7 +4927,8 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + ei->i_file_acl |= + ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; + inode->i_size = ext4_isize(sb, raw_inode); +- if ((size = i_size_read(inode)) < 0) { ++ size = i_size_read(inode); ++ if (size < 0 || size > ext4_get_maxbytes(inode)) { + ext4_error_inode(inode, function, line, 0, + "iget: bad i_size value: %lld", size); + ret = -EFSCORRUPTED; +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index d17207386ead13..0e240013c84d21 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -1505,8 +1505,14 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + return 0; + } + case EXT4_IOC_PRECACHE_EXTENTS: +- return ext4_ext_precache(inode); ++ { ++ int ret; + ++ inode_lock_shared(inode); ++ ret = ext4_ext_precache(inode); ++ inode_unlock_shared(inode); ++ return ret; ++ } + case FS_IOC_SET_ENCRYPTION_POLICY: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; +diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c +index 9b94810675c193..5a9b6d5f3ae0a8 100644 +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -178,8 +178,7 @@ void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct folio *folio) + #ifdef CONFIG_F2FS_FS_LZO + static int lzo_init_compress_ctx(struct compress_ctx *cc) + { +- cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), +- LZO1X_MEM_COMPRESS, GFP_NOFS); ++ cc->private = f2fs_vmalloc(LZO1X_MEM_COMPRESS); + if (!cc->private) + return -ENOMEM; + +@@ -189,7 +188,7 @@ static int lzo_init_compress_ctx(struct compress_ctx *cc) + + static void lzo_destroy_compress_ctx(struct compress_ctx *cc) + { +- kvfree(cc->private); ++ vfree(cc->private); + cc->private = NULL; + } + +@@ -246,7 +245,7 @@ static int lz4_init_compress_ctx(struct compress_ctx *cc) + size = LZ4HC_MEM_COMPRESS; + #endif + +- cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), size, GFP_NOFS); ++ cc->private = f2fs_vmalloc(size); + if (!cc->private) + return -ENOMEM; + +@@ -261,7 +260,7 @@ static int lz4_init_compress_ctx(struct compress_ctx *cc) + + static void lz4_destroy_compress_ctx(struct compress_ctx *cc) + { +- kvfree(cc->private); ++ vfree(cc->private); + cc->private = NULL; + } + +@@ -342,8 +341,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc) + params = zstd_get_params(level, cc->rlen); + workspace_size = zstd_cstream_workspace_bound(¶ms.cParams); + +- workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode), +- workspace_size, GFP_NOFS); ++ workspace = f2fs_vmalloc(workspace_size); + if (!workspace) + return -ENOMEM; + +@@ -351,7 +349,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc) + if (!stream) { + f2fs_err_ratelimited(F2FS_I_SB(cc->inode), + "%s zstd_init_cstream failed", __func__); +- kvfree(workspace); ++ vfree(workspace); + return -EIO; + } + +@@ -364,7 +362,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc) + + static void zstd_destroy_compress_ctx(struct compress_ctx *cc) + { +- kvfree(cc->private); ++ vfree(cc->private); + cc->private = NULL; + cc->private2 = NULL; + } +@@ -423,8 +421,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + + workspace_size = zstd_dstream_workspace_bound(max_window_size); + +- workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), +- workspace_size, GFP_NOFS); ++ workspace = f2fs_vmalloc(workspace_size); + if (!workspace) + return -ENOMEM; + +@@ -432,7 +429,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + if (!stream) { + f2fs_err_ratelimited(F2FS_I_SB(dic->inode), + "%s zstd_init_dstream failed", __func__); +- kvfree(workspace); ++ vfree(workspace); + return -EIO; + } + +@@ -444,7 +441,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + + static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic) + { +- kvfree(dic->private); ++ vfree(dic->private); + dic->private = NULL; + dic->private2 = NULL; + } +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 4f34a7d9760a10..34e4ae2a5f5ba3 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -3527,6 +3527,11 @@ static inline void *f2fs_kvzalloc(struct f2fs_sb_info *sbi, + return f2fs_kvmalloc(sbi, size, flags | __GFP_ZERO); + } + ++static inline void *f2fs_vmalloc(size_t size) ++{ ++ return vmalloc(size); ++} ++ + static inline int get_extra_isize(struct inode *inode) + { + return F2FS_I(inode)->i_extra_isize / sizeof(__le32); +diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c +index 83f862578fc80c..f5991e8751b9bb 100644 +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -34,7 +34,9 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) + if (f2fs_inode_dirtied(inode, sync)) + return; + +- if (f2fs_is_atomic_file(inode)) ++ /* only atomic file w/ FI_ATOMIC_COMMITTED can be set vfs dirty */ ++ if (f2fs_is_atomic_file(inode) && ++ !is_inode_flag_set(inode, FI_ATOMIC_COMMITTED)) + return; + + mark_inode_dirty_sync(inode); +@@ -286,6 +288,12 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page) + return false; + } + ++ if (ino_of_node(node_page) == fi->i_xattr_nid) { ++ f2fs_warn(sbi, "%s: corrupted inode i_ino=%lx, xnid=%x, run fsck to fix.", ++ __func__, inode->i_ino, fi->i_xattr_nid); ++ return false; ++ } ++ + if (f2fs_has_extra_attr(inode)) { + if (!f2fs_sb_has_extra_attr(sbi)) { + f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off", +diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c +index 28137d499f8f65..f775dc62511c24 100644 +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -569,6 +569,15 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) + goto fail; + } + ++ if (unlikely(inode->i_nlink == 0)) { ++ f2fs_warn(F2FS_I_SB(inode), "%s: inode (ino=%lx) has zero i_nlink", ++ __func__, inode->i_ino); ++ err = -EFSCORRUPTED; ++ set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); ++ f2fs_put_page(page, 0); ++ goto fail; ++ } ++ + f2fs_balance_fs(sbi, true); + + f2fs_lock_op(sbi); +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index 5f15c224bf782e..f476c2e7b09629 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -2107,10 +2107,14 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi, + + ret = __write_node_page(&folio->page, false, &submitted, + wbc, do_balance, io_type, NULL); +- if (ret) ++ if (ret) { + folio_unlock(folio); +- else if (submitted) ++ folio_batch_release(&fbatch); ++ ret = -EIO; ++ goto out; ++ } else if (submitted) { + nwritten++; ++ } + + if (--wbc->nr_to_write == 0) + break; +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 41ca73622c8d46..876e97ec5f5703 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -376,7 +376,13 @@ static int __f2fs_commit_atomic_write(struct inode *inode) + } else { + sbi->committed_atomic_block += fi->atomic_write_cnt; + set_inode_flag(inode, FI_ATOMIC_COMMITTED); ++ ++ /* ++ * inode may has no FI_ATOMIC_DIRTIED flag due to no write ++ * before commit. ++ */ + if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) { ++ /* clear atomic dirty status and set vfs dirty status */ + clear_inode_flag(inode, FI_ATOMIC_DIRTIED); + f2fs_mark_inode_dirty_sync(inode, true); + } +@@ -2836,7 +2842,11 @@ static int get_new_segment(struct f2fs_sb_info *sbi, + } + got_it: + /* set it as dirty segment in free segmap */ +- f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); ++ if (test_bit(segno, free_i->free_segmap)) { ++ ret = -EFSCORRUPTED; ++ f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_CORRUPTED_FREE_BITMAP); ++ goto out_unlock; ++ } + + /* no free section in conventional device or conventional zone */ + if (new_sec && pinning && +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 386326f7a440eb..bc510c91f3eba4 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1531,7 +1531,9 @@ int f2fs_inode_dirtied(struct inode *inode, bool sync) + } + spin_unlock(&sbi->inode_lock[DIRTY_META]); + +- if (!ret && f2fs_is_atomic_file(inode)) ++ /* if atomic write is not committed, set inode w/ atomic dirty */ ++ if (!ret && f2fs_is_atomic_file(inode) && ++ !is_inode_flag_set(inode, FI_ATOMIC_COMMITTED)) + set_inode_flag(inode, FI_ATOMIC_DIRTIED); + + return ret; +@@ -3717,6 +3719,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) + block_t user_block_count, valid_user_blocks; + block_t avail_node_count, valid_node_count; + unsigned int nat_blocks, nat_bits_bytes, nat_bits_blocks; ++ unsigned int sit_blk_cnt; + int i, j; + + total = le32_to_cpu(raw_super->segment_count); +@@ -3828,6 +3831,13 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) + return 1; + } + ++ sit_blk_cnt = DIV_ROUND_UP(main_segs, SIT_ENTRY_PER_BLOCK); ++ if (sit_bitmap_size * 8 < sit_blk_cnt) { ++ f2fs_err(sbi, "Wrong bitmap size: sit: %u, sit_blk_cnt:%u", ++ sit_bitmap_size, sit_blk_cnt); ++ return 1; ++ } ++ + cp_pack_start_sum = __start_sum_addr(sbi); + cp_payload = __cp_payload(sbi); + if (cp_pack_start_sum < cp_payload + 1 || +diff --git a/fs/file.c b/fs/file.c +index 3a3146664cf371..b6db031545e650 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -1198,8 +1198,12 @@ bool file_seek_cur_needs_f_lock(struct file *file) + if (!(file->f_mode & FMODE_ATOMIC_POS) && !file->f_op->iterate_shared) + return false; + +- VFS_WARN_ON_ONCE((file_count(file) > 1) && +- !mutex_is_locked(&file->f_pos_lock)); ++ /* ++ * Note that we are not guaranteed to be called after fdget_pos() on ++ * this file obj, in which case the caller is expected to provide the ++ * appropriate locking. ++ */ ++ + return true; + } + +diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c +index 58aeeae7ed8cd0..2c9172dd41e7ee 100644 +--- a/fs/gfs2/lock_dlm.c ++++ b/fs/gfs2/lock_dlm.c +@@ -996,14 +996,15 @@ static int control_mount(struct gfs2_sbd *sdp) + if (sdp->sd_args.ar_spectator) { + fs_info(sdp, "Recovery is required. Waiting for a " + "non-spectator to mount.\n"); ++ spin_unlock(&ls->ls_recover_spin); + msleep_interruptible(1000); + } else { + fs_info(sdp, "control_mount wait1 block %u start %u " + "mount %u lvb %u flags %lx\n", block_gen, + start_gen, mount_gen, lvb_gen, + ls->ls_recover_flags); ++ spin_unlock(&ls->ls_recover_spin); + } +- spin_unlock(&ls->ls_recover_spin); + goto restart; + } + +diff --git a/fs/internal.h b/fs/internal.h +index b9b3e29a73fd8c..f545400ce607f9 100644 +--- a/fs/internal.h ++++ b/fs/internal.h +@@ -343,3 +343,8 @@ static inline bool path_mounted(const struct path *path) + void file_f_owner_release(struct file *file); + bool file_seek_cur_needs_f_lock(struct file *file); + int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_map); ++int anon_inode_getattr(struct mnt_idmap *idmap, const struct path *path, ++ struct kstat *stat, u32 request_mask, ++ unsigned int query_flags); ++int anon_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, ++ struct iattr *attr); +diff --git a/fs/ioctl.c b/fs/ioctl.c +index c91fd2b46a77f6..03d9a11f22475b 100644 +--- a/fs/ioctl.c ++++ b/fs/ioctl.c +@@ -821,7 +821,8 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, + return ioctl_fioasync(fd, filp, argp); + + case FIOQSIZE: +- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) || ++ if (S_ISDIR(inode->i_mode) || ++ (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode)) || + S_ISLNK(inode->i_mode)) { + loff_t res = inode_get_bytes(inode); + return copy_to_user(argp, &res, sizeof(res)) ? +@@ -856,7 +857,7 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, + return ioctl_file_dedupe_range(filp, argp); + + case FIONREAD: +- if (!S_ISREG(inode->i_mode)) ++ if (!S_ISREG(inode->i_mode) || IS_ANON_FILE(inode)) + return vfs_ioctl(filp, cmd, arg); + + return put_user(i_size_read(inode) - filp->f_pos, +@@ -881,7 +882,7 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, + return ioctl_get_fs_sysfs_path(filp, argp); + + default: +- if (S_ISREG(inode->i_mode)) ++ if (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode)) + return file_ioctl(filp, cmd, argp); + break; + } +diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c +index 47038e6608123c..d5da9817df9b36 100644 +--- a/fs/isofs/inode.c ++++ b/fs/isofs/inode.c +@@ -1275,6 +1275,7 @@ static int isofs_read_inode(struct inode *inode, int relocated) + unsigned long offset; + struct iso_inode_info *ei = ISOFS_I(inode); + int ret = -EIO; ++ struct timespec64 ts; + + block = ei->i_iget5_block; + bh = sb_bread(inode->i_sb, block); +@@ -1387,8 +1388,10 @@ static int isofs_read_inode(struct inode *inode, int relocated) + inode->i_ino, de->flags[-high_sierra]); + } + #endif +- inode_set_mtime_to_ts(inode, +- inode_set_atime_to_ts(inode, inode_set_ctime(inode, iso_date(de->date, high_sierra), 0))); ++ ts = iso_date(de->date, high_sierra ? ISO_DATE_HIGH_SIERRA : 0); ++ inode_set_ctime_to_ts(inode, ts); ++ inode_set_atime_to_ts(inode, ts); ++ inode_set_mtime_to_ts(inode, ts); + + ei->i_first_extent = (isonum_733(de->extent) + + isonum_711(de->ext_attr_length)); +diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h +index 2d55207c9a9902..50655583753334 100644 +--- a/fs/isofs/isofs.h ++++ b/fs/isofs/isofs.h +@@ -106,7 +106,9 @@ static inline unsigned int isonum_733(u8 *p) + /* Ignore bigendian datum due to broken mastering programs */ + return get_unaligned_le32(p); + } +-extern int iso_date(u8 *, int); ++#define ISO_DATE_HIGH_SIERRA (1 << 0) ++#define ISO_DATE_LONG_FORM (1 << 1) ++struct timespec64 iso_date(u8 *p, int flags); + + struct inode; /* To make gcc happy */ + +diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c +index dbf911126e610e..576498245b9d7c 100644 +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -412,7 +412,12 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, + } + } + break; +- case SIG('T', 'F'): ++ case SIG('T', 'F'): { ++ int flags, size, slen; ++ ++ flags = rr->u.TF.flags & TF_LONG_FORM ? ISO_DATE_LONG_FORM : 0; ++ size = rr->u.TF.flags & TF_LONG_FORM ? 17 : 7; ++ slen = rr->len - 5; + /* + * Some RRIP writers incorrectly place ctime in the + * TF_CREATE field. Try to handle this correctly for +@@ -420,27 +425,28 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, + */ + /* Rock ridge never appears on a High Sierra disk */ + cnt = 0; +- if (rr->u.TF.flags & TF_CREATE) { +- inode_set_ctime(inode, +- iso_date(rr->u.TF.times[cnt++].time, 0), +- 0); ++ if ((rr->u.TF.flags & TF_CREATE) && size <= slen) { ++ inode_set_ctime_to_ts(inode, ++ iso_date(rr->u.TF.data + size * cnt++, flags)); ++ slen -= size; + } +- if (rr->u.TF.flags & TF_MODIFY) { +- inode_set_mtime(inode, +- iso_date(rr->u.TF.times[cnt++].time, 0), +- 0); ++ if ((rr->u.TF.flags & TF_MODIFY) && size <= slen) { ++ inode_set_mtime_to_ts(inode, ++ iso_date(rr->u.TF.data + size * cnt++, flags)); ++ slen -= size; + } +- if (rr->u.TF.flags & TF_ACCESS) { +- inode_set_atime(inode, +- iso_date(rr->u.TF.times[cnt++].time, 0), +- 0); ++ if ((rr->u.TF.flags & TF_ACCESS) && size <= slen) { ++ inode_set_atime_to_ts(inode, ++ iso_date(rr->u.TF.data + size * cnt++, flags)); ++ slen -= size; + } +- if (rr->u.TF.flags & TF_ATTRIBUTES) { +- inode_set_ctime(inode, +- iso_date(rr->u.TF.times[cnt++].time, 0), +- 0); ++ if ((rr->u.TF.flags & TF_ATTRIBUTES) && size <= slen) { ++ inode_set_ctime_to_ts(inode, ++ iso_date(rr->u.TF.data + size * cnt++, flags)); ++ slen -= size; + } + break; ++ } + case SIG('S', 'L'): + { + int slen; +diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h +index 7755e587f77850..c0856fa9bb6a4e 100644 +--- a/fs/isofs/rock.h ++++ b/fs/isofs/rock.h +@@ -65,13 +65,9 @@ struct RR_PL_s { + __u8 location[8]; + }; + +-struct stamp { +- __u8 time[7]; /* actually 6 unsigned, 1 signed */ +-} __attribute__ ((packed)); +- + struct RR_TF_s { + __u8 flags; +- struct stamp times[]; /* Variable number of these beasts */ ++ __u8 data[]; + } __attribute__ ((packed)); + + /* Linux-specific extension for transparent decompression */ +diff --git a/fs/isofs/util.c b/fs/isofs/util.c +index e88dba72166187..42f479da0b282c 100644 +--- a/fs/isofs/util.c ++++ b/fs/isofs/util.c +@@ -16,29 +16,44 @@ + * to GMT. Thus we should always be correct. + */ + +-int iso_date(u8 *p, int flag) ++struct timespec64 iso_date(u8 *p, int flags) + { + int year, month, day, hour, minute, second, tz; +- int crtime; ++ struct timespec64 ts; ++ ++ if (flags & ISO_DATE_LONG_FORM) { ++ year = (p[0] - '0') * 1000 + ++ (p[1] - '0') * 100 + ++ (p[2] - '0') * 10 + ++ (p[3] - '0') - 1900; ++ month = ((p[4] - '0') * 10 + (p[5] - '0')); ++ day = ((p[6] - '0') * 10 + (p[7] - '0')); ++ hour = ((p[8] - '0') * 10 + (p[9] - '0')); ++ minute = ((p[10] - '0') * 10 + (p[11] - '0')); ++ second = ((p[12] - '0') * 10 + (p[13] - '0')); ++ ts.tv_nsec = ((p[14] - '0') * 10 + (p[15] - '0')) * 10000000; ++ tz = p[16]; ++ } else { ++ year = p[0]; ++ month = p[1]; ++ day = p[2]; ++ hour = p[3]; ++ minute = p[4]; ++ second = p[5]; ++ ts.tv_nsec = 0; ++ /* High sierra has no time zone */ ++ tz = flags & ISO_DATE_HIGH_SIERRA ? 0 : p[6]; ++ } + +- year = p[0]; +- month = p[1]; +- day = p[2]; +- hour = p[3]; +- minute = p[4]; +- second = p[5]; +- if (flag == 0) tz = p[6]; /* High sierra has no time zone */ +- else tz = 0; +- + if (year < 0) { +- crtime = 0; ++ ts.tv_sec = 0; + } else { +- crtime = mktime64(year+1900, month, day, hour, minute, second); ++ ts.tv_sec = mktime64(year+1900, month, day, hour, minute, second); + + /* sign extend */ + if (tz & 0x80) + tz |= (-1 << 8); +- ++ + /* + * The timezone offset is unreliable on some disks, + * so we make a sanity check. In no case is it ever +@@ -65,7 +80,7 @@ int iso_date(u8 *p, int flag) + * for pointing out the sign error. + */ + if (-52 <= tz && tz <= 52) +- crtime -= tz * 15 * 60; ++ ts.tv_sec -= tz * 15 * 60; + } +- return crtime; +-} ++ return ts; ++} +diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c +index cbc4785462f537..c7867139af69dd 100644 +--- a/fs/jbd2/transaction.c ++++ b/fs/jbd2/transaction.c +@@ -1509,7 +1509,7 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) + jh->b_next_transaction == transaction); + spin_unlock(&jh->b_state_lock); + } +- if (jh->b_modified == 1) { ++ if (data_race(jh->b_modified == 1)) { + /* If it's in our transaction it must be in BJ_Metadata list. */ + if (data_race(jh->b_transaction == transaction && + jh->b_jlist != BJ_Metadata)) { +@@ -1528,7 +1528,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) + goto out; + } + +- journal = transaction->t_journal; + spin_lock(&jh->b_state_lock); + + if (is_handle_aborted(handle)) { +@@ -1543,6 +1542,8 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) + goto out_unlock_bh; + } + ++ journal = transaction->t_journal; ++ + if (jh->b_modified == 0) { + /* + * This buffer's got modified and becoming part +diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c +index ef3a1e1b6cb065..fda9f4d6093f94 100644 +--- a/fs/jffs2/erase.c ++++ b/fs/jffs2/erase.c +@@ -425,7 +425,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb + .totlen = cpu_to_je32(c->cleanmarker_size) + }; + +- jffs2_prealloc_raw_node_refs(c, jeb, 1); ++ ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); ++ if (ret) ++ goto filebad; + + marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); + +diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c +index 29671e33a1714c..62879c218d4b11 100644 +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -256,7 +256,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) + + jffs2_dbg(1, "%s(): Skipping %d bytes in nextblock to ensure page alignment\n", + __func__, skip); +- jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); ++ ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); ++ if (ret) ++ goto out; + jffs2_scan_dirty_space(c, c->nextblock, skip); + } + #endif +diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c +index 4fe64519870f1a..d83372d3e1a07b 100644 +--- a/fs/jffs2/summary.c ++++ b/fs/jffs2/summary.c +@@ -858,7 +858,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) + spin_unlock(&c->erase_completion_lock); + + jeb = c->nextblock; +- jffs2_prealloc_raw_node_refs(c, jeb, 1); ++ ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); ++ ++ if (ret) ++ goto out; + + if (!c->summary->sum_num || !c->summary->sum_list_head) { + JFFS2_WARNING("Empty summary info!!!\n"); +@@ -872,6 +875,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) + datasize += padsize; + + ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); ++ ++out: + spin_lock(&c->erase_completion_lock); + return ret; + } +diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c +index 5f4b305030ad5e..4b660296caf39c 100644 +--- a/fs/jfs/jfs_discard.c ++++ b/fs/jfs/jfs_discard.c +@@ -86,7 +86,8 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range) + down_read(&sb->s_umount); + bmp = JFS_SBI(ip->i_sb)->bmap; + +- if (minlen > bmp->db_agsize || ++ if (bmp == NULL || ++ minlen > bmp->db_agsize || + start >= bmp->db_mapsize || + range->len < sb->s_blocksize) { + up_read(&sb->s_umount); +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index 26e89d0c69b61e..35e063c9f3a42e 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -194,7 +194,11 @@ int dbMount(struct inode *ipbmap) + !bmp->db_numag || (bmp->db_numag > MAXAG) || + (bmp->db_maxag >= MAXAG) || (bmp->db_maxag < 0) || + (bmp->db_agpref >= MAXAG) || (bmp->db_agpref < 0) || +- !bmp->db_agwidth || ++ (bmp->db_agheight < 0) || (bmp->db_agheight > (L2LPERCTL >> 1)) || ++ (bmp->db_agwidth < 1) || (bmp->db_agwidth > (LPERCTL / MAXAG)) || ++ (bmp->db_agwidth > (1 << (L2LPERCTL - (bmp->db_agheight << 1)))) || ++ (bmp->db_agstart < 0) || ++ (bmp->db_agstart > (CTLTREESIZE - 1 - bmp->db_agwidth * (MAXAG - 1))) || + (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) || + (bmp->db_agl2size < 0) || + ((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) { +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 93db6eec446556..ab11849cf9cc3c 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -2613,7 +2613,7 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot) + * fsck.jfs should really fix this, but it currently does not. + * Called from jfs_readdir when bad index is detected. + */ +-static void add_missing_indices(struct inode *inode, s64 bn) ++static int add_missing_indices(struct inode *inode, s64 bn) + { + struct ldtentry *d; + struct dt_lock *dtlck; +@@ -2622,7 +2622,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) + struct lv *lv; + struct metapage *mp; + dtpage_t *p; +- int rc; ++ int rc = 0; + s8 *stbl; + tid_t tid; + struct tlock *tlck; +@@ -2647,6 +2647,16 @@ static void add_missing_indices(struct inode *inode, s64 bn) + + stbl = DT_GETSTBL(p); + for (i = 0; i < p->header.nextindex; i++) { ++ if (stbl[i] < 0) { ++ jfs_err("jfs: add_missing_indices: Invalid stbl[%d] = %d for inode %ld, block = %lld", ++ i, stbl[i], (long)inode->i_ino, (long long)bn); ++ rc = -EIO; ++ ++ DT_PUTPAGE(mp); ++ txAbort(tid, 0); ++ goto end; ++ } ++ + d = (struct ldtentry *) &p->slot[stbl[i]]; + index = le32_to_cpu(d->index); + if ((index < 2) || (index >= JFS_IP(inode)->next_index)) { +@@ -2664,6 +2674,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) + (void) txCommit(tid, 1, &inode, 0); + end: + txEnd(tid); ++ return rc; + } + + /* +@@ -3017,7 +3028,8 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) + } + + if (fix_page) { +- add_missing_indices(ip, bn); ++ if ((rc = add_missing_indices(ip, bn))) ++ goto out; + page_fixed = 1; + } + +diff --git a/fs/libfs.c b/fs/libfs.c +index 6393d7c49ee6e6..e28da9574a652b 100644 +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -1647,10 +1647,16 @@ struct inode *alloc_anon_inode(struct super_block *s) + * that it already _is_ on the dirty list. + */ + inode->i_state = I_DIRTY; +- inode->i_mode = S_IRUSR | S_IWUSR; ++ /* ++ * Historically anonymous inodes didn't have a type at all and ++ * userspace has come to rely on this. Internally they're just ++ * regular files but S_IFREG is masked off when reporting ++ * information to userspace. ++ */ ++ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); +- inode->i_flags |= S_PRIVATE; ++ inode->i_flags |= S_PRIVATE | S_ANON_INODE; + simple_inode_init_ts(inode); + return inode; + } +diff --git a/fs/nfs/client.c b/fs/nfs/client.c +index 6d63b958c4bb13..d8fe7c0e7e052d 100644 +--- a/fs/nfs/client.c ++++ b/fs/nfs/client.c +@@ -439,7 +439,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) + spin_unlock(&nn->nfs_client_lock); + new = rpc_ops->init_client(new, cl_init); + if (!IS_ERR(new)) +- nfs_local_probe(new); ++ nfs_local_probe_async(new); + return new; + } + +diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +index 4a304cf17c4b07..656d5c50bbce1c 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c ++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +@@ -400,7 +400,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, + * keep ds_clp even if DS is local, so that if local IO cannot + * proceed somehow, we can fall back to NFS whenever we want. + */ +- nfs_local_probe(ds->ds_clp); ++ nfs_local_probe_async(ds->ds_clp); + max_payload = + nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient), + NULL); +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index 6655e5f32ec63c..69c2c10ee658c9 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -455,7 +455,6 @@ extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode); + + #if IS_ENABLED(CONFIG_NFS_LOCALIO) + /* localio.c */ +-extern void nfs_local_probe(struct nfs_client *); + extern void nfs_local_probe_async(struct nfs_client *); + extern void nfs_local_probe_async_work(struct work_struct *); + extern struct nfsd_file *nfs_local_open_fh(struct nfs_client *, +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index e6d36b3d3fc059..510d0a16cfe917 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -171,7 +171,7 @@ static bool nfs_server_uuid_is_local(struct nfs_client *clp) + * - called after alloc_client and init_client (so cl_rpcclient exists) + * - this function is idempotent, it can be called for old or new clients + */ +-void nfs_local_probe(struct nfs_client *clp) ++static void nfs_local_probe(struct nfs_client *clp) + { + /* Disallow localio if disabled via sysfs or AUTH_SYS isn't used */ + if (!localio_enabled || +@@ -191,14 +191,16 @@ void nfs_local_probe(struct nfs_client *clp) + nfs_localio_enable_client(clp); + nfs_uuid_end(&clp->cl_uuid); + } +-EXPORT_SYMBOL_GPL(nfs_local_probe); + + void nfs_local_probe_async_work(struct work_struct *work) + { + struct nfs_client *clp = + container_of(work, struct nfs_client, cl_local_probe_work); + ++ if (!refcount_inc_not_zero(&clp->cl_count)) ++ return; + nfs_local_probe(clp); ++ nfs_put_client(clp); + } + + void nfs_local_probe_async(struct nfs_client *clp) +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 4b123bca65e12d..9db317e7dea177 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3976,8 +3976,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f + FATTR4_WORD0_CASE_INSENSITIVE | + FATTR4_WORD0_CASE_PRESERVING; + if (minorversion) +- bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT | +- FATTR4_WORD2_OPEN_ARGUMENTS; ++ bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT; ++ if (minorversion > 1) ++ bitmask[2] |= FATTR4_WORD2_OPEN_ARGUMENTS; + + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + if (status == 0) { +diff --git a/fs/nfs/read.c b/fs/nfs/read.c +index 81bd1b9aba176f..3c1fa320b3f1bd 100644 +--- a/fs/nfs/read.c ++++ b/fs/nfs/read.c +@@ -56,7 +56,8 @@ static int nfs_return_empty_folio(struct folio *folio) + { + folio_zero_segment(folio, 0, folio_size(folio)); + folio_mark_uptodate(folio); +- folio_unlock(folio); ++ if (nfs_netfs_folio_unlock(folio)) ++ folio_unlock(folio); + return 0; + } + +diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c +index 0363720280d4cb..88ae410b411333 100644 +--- a/fs/nfsd/export.c ++++ b/fs/nfsd/export.c +@@ -1124,7 +1124,8 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, + test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) + goto ok; + } +- goto denied; ++ if (!may_bypass_gss) ++ goto denied; + + ok: + /* legacy gss-only clients are always OK: */ +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index b397246dae7b7e..d0358c801c428a 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3766,7 +3766,8 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) + struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow; + u32 opiter; + +- if (!cstate->minorversion) ++ if (rqstp->rq_procinfo != &nfsd_version4.vs_proc[NFSPROC4_COMPOUND] || ++ cstate->minorversion == 0) + return false; + + if (cstate->spo_must_allowed) +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index e67420729ecd60..9eb8e570462251 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3391,6 +3391,23 @@ static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr, + return nfsd4_encode_bitmap4(xdr, supp[0], supp[1], supp[2]); + } + ++/* ++ * Copied from generic_remap_checks/generic_remap_file_range_prep. ++ * ++ * These generic functions use the file system's s_blocksize, but ++ * individual file systems aren't required to use ++ * generic_remap_file_range_prep. Until there is a mechanism for ++ * determining a particular file system's (or file's) clone block ++ * size, this is the best NFSD can do. ++ */ ++static __be32 nfsd4_encode_fattr4_clone_blksize(struct xdr_stream *xdr, ++ const struct nfsd4_fattr_args *args) ++{ ++ struct inode *inode = d_inode(args->dentry); ++ ++ return nfsd4_encode_uint32_t(xdr, inode->i_sb->s_blocksize); ++} ++ + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + static __be32 nfsd4_encode_fattr4_sec_label(struct xdr_stream *xdr, + const struct nfsd4_fattr_args *args) +@@ -3545,7 +3562,7 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = { + [FATTR4_MODE_SET_MASKED] = nfsd4_encode_fattr4__noop, + [FATTR4_SUPPATTR_EXCLCREAT] = nfsd4_encode_fattr4_suppattr_exclcreat, + [FATTR4_FS_CHARSET_CAP] = nfsd4_encode_fattr4__noop, +- [FATTR4_CLONE_BLKSIZE] = nfsd4_encode_fattr4__noop, ++ [FATTR4_CLONE_BLKSIZE] = nfsd4_encode_fattr4_clone_blksize, + [FATTR4_SPACE_FREED] = nfsd4_encode_fattr4__noop, + [FATTR4_CHANGE_ATTR_TYPE] = nfsd4_encode_fattr4__noop, + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index ac265d6fde35df..332bfb508c20bc 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1611,7 +1611,7 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, + */ + int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info) + { +- int *nthreads, count = 0, nrpools, i, ret = -EOPNOTSUPP, rem; ++ int *nthreads, nrpools = 0, i, ret = -EOPNOTSUPP, rem; + struct net *net = genl_info_net(info); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + const struct nlattr *attr; +@@ -1623,12 +1623,11 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info) + /* count number of SERVER_THREADS values */ + nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) { + if (nla_type(attr) == NFSD_A_SERVER_THREADS) +- count++; ++ nrpools++; + } + + mutex_lock(&nfsd_mutex); + +- nrpools = max(count, nfsd_nrpools(net)); + nthreads = kcalloc(nrpools, sizeof(int), GFP_KERNEL); + if (!nthreads) { + ret = -ENOMEM; +@@ -2291,12 +2290,9 @@ static int __init init_nfsd(void) + if (retval) + goto out_free_pnfs; + nfsd_lockd_init(); /* lockd->nfsd callbacks */ +- retval = create_proc_exports_entry(); +- if (retval) +- goto out_free_lockd; + retval = register_pernet_subsys(&nfsd_net_ops); + if (retval < 0) +- goto out_free_exports; ++ goto out_free_lockd; + retval = register_cld_notifier(); + if (retval) + goto out_free_subsys; +@@ -2305,22 +2301,26 @@ static int __init init_nfsd(void) + goto out_free_cld; + retval = register_filesystem(&nfsd_fs_type); + if (retval) +- goto out_free_all; ++ goto out_free_nfsd4; + retval = genl_register_family(&nfsd_nl_family); ++ if (retval) ++ goto out_free_filesystem; ++ retval = create_proc_exports_entry(); + if (retval) + goto out_free_all; + nfsd_localio_ops_init(); + + return 0; + out_free_all: ++ genl_unregister_family(&nfsd_nl_family); ++out_free_filesystem: ++ unregister_filesystem(&nfsd_fs_type); ++out_free_nfsd4: + nfsd4_destroy_laundry_wq(); + out_free_cld: + unregister_cld_notifier(); + out_free_subsys: + unregister_pernet_subsys(&nfsd_net_ops); +-out_free_exports: +- remove_proc_entry("fs/nfs/exports", NULL); +- remove_proc_entry("fs/nfs", NULL); + out_free_lockd: + nfsd_lockd_shutdown(); + nfsd_drc_slab_free(); +@@ -2333,14 +2333,14 @@ static int __init init_nfsd(void) + + static void __exit exit_nfsd(void) + { ++ remove_proc_entry("fs/nfs/exports", NULL); ++ remove_proc_entry("fs/nfs", NULL); + genl_unregister_family(&nfsd_nl_family); + unregister_filesystem(&nfsd_fs_type); + nfsd4_destroy_laundry_wq(); + unregister_cld_notifier(); + unregister_pernet_subsys(&nfsd_net_ops); + nfsd_drc_slab_free(); +- remove_proc_entry("fs/nfs/exports", NULL); +- remove_proc_entry("fs/nfs", NULL); + nfsd_lockd_shutdown(); + nfsd4_free_slabs(); + nfsd4_exit_pnfs(); +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 9b3d6cff0e1e24..8ed143ef8b4115 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -396,13 +396,13 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred) + if (ret) + goto out_filecache; + ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++ nfsd4_ssc_init_umount_work(nn); ++#endif + ret = nfs4_state_start_net(net); + if (ret) + goto out_reply_cache; + +-#ifdef CONFIG_NFSD_V4_2_INTER_SSC +- nfsd4_ssc_init_umount_work(nn); +-#endif + nn->nfsd_net_up = true; + return 0; + +diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c +index 969b458100fe5e..dfea7bd800cb4b 100644 +--- a/fs/overlayfs/file.c ++++ b/fs/overlayfs/file.c +@@ -48,8 +48,8 @@ static struct file *ovl_open_realfile(const struct file *file, + if (!inode_owner_or_capable(real_idmap, realinode)) + flags &= ~O_NOATIME; + +- realfile = backing_file_open(&file->f_path, flags, realpath, +- current_cred()); ++ realfile = backing_file_open(file_user_path((struct file *) file), ++ flags, realpath, current_cred()); + } + ovl_revert_creds(old_cred); + +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index aef942a758cea5..c69c34e11c74dc 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -246,9 +246,11 @@ static inline struct dentry *ovl_do_mkdir(struct ovl_fs *ofs, + struct dentry *dentry, + umode_t mode) + { +- dentry = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); +- pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(dentry)); +- return dentry; ++ struct dentry *ret; ++ ++ ret = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); ++ pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(ret)); ++ return ret; + } + + static inline int ovl_do_mknod(struct ovl_fs *ofs, +diff --git a/fs/pidfs.c b/fs/pidfs.c +index 87a53d2ae4bb78..005976025ce9fd 100644 +--- a/fs/pidfs.c ++++ b/fs/pidfs.c +@@ -826,7 +826,7 @@ static int pidfs_init_inode(struct inode *inode, void *data) + const struct pid *pid = data; + + inode->i_private = data; +- inode->i_flags |= S_PRIVATE; ++ inode->i_flags |= S_PRIVATE | S_ANON_INODE; + inode->i_mode |= S_IRWXU; + inode->i_op = &pidfs_inode_operations; + inode->i_fop = &pidfs_file_operations; +diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c +index 240d82c6f90806..9831eac7b948a8 100644 +--- a/fs/smb/client/cached_dir.c ++++ b/fs/smb/client/cached_dir.c +@@ -486,8 +486,17 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC); +- if (tmp_list == NULL) +- break; ++ if (tmp_list == NULL) { ++ /* ++ * If the malloc() fails, we won't drop all ++ * dentries, and unmounting is likely to trigger ++ * a 'Dentry still in use' error. ++ */ ++ cifs_tcon_dbg(VFS, "Out of memory while dropping dentries\n"); ++ spin_unlock(&cfids->cfid_list_lock); ++ spin_unlock(&cifs_sb->tlink_tree_lock); ++ goto done; ++ } + spin_lock(&cfid->fid_lock); + tmp_list->dentry = cfid->dentry; + cfid->dentry = NULL; +@@ -499,6 +508,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) + } + spin_unlock(&cifs_sb->tlink_tree_lock); + ++done: + list_for_each_entry_safe(tmp_list, q, &entry, entry) { + list_del(&tmp_list->entry); + dput(tmp_list->dentry); +diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h +index 1dfe79d947a62f..bc8a812ff95f8b 100644 +--- a/fs/smb/client/cached_dir.h ++++ b/fs/smb/client/cached_dir.h +@@ -21,10 +21,10 @@ struct cached_dirent { + struct cached_dirents { + bool is_valid:1; + bool is_failed:1; +- struct dir_context *ctx; /* +- * Only used to make sure we only take entries +- * from a single context. Never dereferenced. +- */ ++ struct file *file; /* ++ * Used to associate the cache with a single ++ * open file instance. ++ */ + struct mutex de_mutex; + int pos; /* Expected ctx->pos */ + struct list_head entries; +diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h +index 3b32116b0b4964..0c80ca352f3fae 100644 +--- a/fs/smb/client/cifsglob.h ++++ b/fs/smb/client/cifsglob.h +@@ -1084,6 +1084,7 @@ struct cifs_chan { + }; + + #define CIFS_SES_FLAG_SCALE_CHANNELS (0x1) ++#define CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES (0x2) + + /* + * Session structure. One of these for each uid session with a particular host +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 6bf04d9a549138..f9aef60f1901ac 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -116,13 +116,9 @@ static void smb2_query_server_interfaces(struct work_struct *work) + rc = server->ops->query_server_interfaces(xid, tcon, false); + free_xid(xid); + +- if (rc) { +- if (rc == -EOPNOTSUPP) +- return; +- ++ if (rc) + cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", + __func__, rc); +- } + + queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, + (SMB_INTERFACE_POLL_INTERVAL * HZ)); +@@ -377,6 +373,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server, + if (!cifs_tcp_ses_needs_reconnect(server, 1)) + return 0; + ++ /* ++ * if smb session has been marked for reconnect, also reconnect all ++ * connections. This way, the other connections do not end up bad. ++ */ ++ if (mark_smb_session) ++ cifs_signal_cifsd_for_reconnect(server, mark_smb_session); ++ + cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session); + + cifs_abort_connection(server); +@@ -385,7 +388,8 @@ static int __cifs_reconnect(struct TCP_Server_Info *server, + try_to_freeze(); + cifs_server_lock(server); + +- if (!cifs_swn_set_server_dstaddr(server)) { ++ if (!cifs_swn_set_server_dstaddr(server) && ++ !SERVER_IS_CHAN(server)) { + /* resolve the hostname again to make sure that IP address is up-to-date */ + rc = reconn_set_ipaddr_from_hostname(server); + cifs_dbg(FYI, "%s: reconn_set_ipaddr_from_hostname: rc=%d\n", __func__, rc); +@@ -4189,6 +4193,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, + return 0; + } + ++ server->lstrp = jiffies; + server->tcpStatus = CifsInNegotiate; + spin_unlock(&server->srv_lock); + +diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c +index e3f9213131c467..a6655807c0865a 100644 +--- a/fs/smb/client/namespace.c ++++ b/fs/smb/client/namespace.c +@@ -146,6 +146,9 @@ static char *automount_fullpath(struct dentry *dentry, void *page) + } + spin_unlock(&tcon->tc_lock); + ++ if (unlikely(!page)) ++ return ERR_PTR(-ENOMEM); ++ + s = dentry_path_raw(dentry, page, PATH_MAX); + if (IS_ERR(s)) + return s; +diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c +index 787d6bcb5d1dc4..c3feb26fcfd03a 100644 +--- a/fs/smb/client/readdir.c ++++ b/fs/smb/client/readdir.c +@@ -850,9 +850,9 @@ static bool emit_cached_dirents(struct cached_dirents *cde, + } + + static void update_cached_dirents_count(struct cached_dirents *cde, +- struct dir_context *ctx) ++ struct file *file) + { +- if (cde->ctx != ctx) ++ if (cde->file != file) + return; + if (cde->is_valid || cde->is_failed) + return; +@@ -861,9 +861,9 @@ static void update_cached_dirents_count(struct cached_dirents *cde, + } + + static void finished_cached_dirents_count(struct cached_dirents *cde, +- struct dir_context *ctx) ++ struct dir_context *ctx, struct file *file) + { +- if (cde->ctx != ctx) ++ if (cde->file != file) + return; + if (cde->is_valid || cde->is_failed) + return; +@@ -876,11 +876,12 @@ static void finished_cached_dirents_count(struct cached_dirents *cde, + static void add_cached_dirent(struct cached_dirents *cde, + struct dir_context *ctx, + const char *name, int namelen, +- struct cifs_fattr *fattr) ++ struct cifs_fattr *fattr, ++ struct file *file) + { + struct cached_dirent *de; + +- if (cde->ctx != ctx) ++ if (cde->file != file) + return; + if (cde->is_valid || cde->is_failed) + return; +@@ -910,7 +911,8 @@ static void add_cached_dirent(struct cached_dirents *cde, + static bool cifs_dir_emit(struct dir_context *ctx, + const char *name, int namelen, + struct cifs_fattr *fattr, +- struct cached_fid *cfid) ++ struct cached_fid *cfid, ++ struct file *file) + { + bool rc; + ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); +@@ -922,7 +924,7 @@ static bool cifs_dir_emit(struct dir_context *ctx, + if (cfid) { + mutex_lock(&cfid->dirents.de_mutex); + add_cached_dirent(&cfid->dirents, ctx, name, namelen, +- fattr); ++ fattr, file); + mutex_unlock(&cfid->dirents.de_mutex); + } + +@@ -1022,7 +1024,7 @@ static int cifs_filldir(char *find_entry, struct file *file, + cifs_prime_dcache(file_dentry(file), &name, &fattr); + + return !cifs_dir_emit(ctx, name.name, name.len, +- &fattr, cfid); ++ &fattr, cfid, file); + } + + +@@ -1073,8 +1075,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) + * we need to initialize scanning and storing the + * directory content. + */ +- if (ctx->pos == 0 && cfid->dirents.ctx == NULL) { +- cfid->dirents.ctx = ctx; ++ if (ctx->pos == 0 && cfid->dirents.file == NULL) { ++ cfid->dirents.file = file; + cfid->dirents.pos = 2; + } + /* +@@ -1142,7 +1144,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) + } else { + if (cfid) { + mutex_lock(&cfid->dirents.de_mutex); +- finished_cached_dirents_count(&cfid->dirents, ctx); ++ finished_cached_dirents_count(&cfid->dirents, ctx, file); + mutex_unlock(&cfid->dirents.de_mutex); + } + cifs_dbg(FYI, "Could not find entry\n"); +@@ -1183,7 +1185,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) + ctx->pos++; + if (cfid) { + mutex_lock(&cfid->dirents.de_mutex); +- update_cached_dirents_count(&cfid->dirents, ctx); ++ update_cached_dirents_count(&cfid->dirents, file); + mutex_unlock(&cfid->dirents.de_mutex); + } + +diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c +index bb25e77c5540c2..511611206dab48 100644 +--- a/fs/smb/client/reparse.c ++++ b/fs/smb/client/reparse.c +@@ -1172,7 +1172,6 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data, + if (!have_xattr_dev && (tag == IO_REPARSE_TAG_LX_CHR || tag == IO_REPARSE_TAG_LX_BLK)) + return false; + +- fattr->cf_dtype = S_DT(fattr->cf_mode); + return true; + } + +diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c +index b3fa9ee2691272..12c99fb4023dc2 100644 +--- a/fs/smb/client/sess.c ++++ b/fs/smb/client/sess.c +@@ -445,6 +445,10 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) + + ses->chans[chan_index].iface = iface; + spin_unlock(&ses->chan_lock); ++ ++ spin_lock(&server->srv_lock); ++ memcpy(&server->dstaddr, &iface->sockaddr, sizeof(server->dstaddr)); ++ spin_unlock(&server->srv_lock); + } + + static int +@@ -494,8 +498,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, + ctx->domainauto = ses->domainAuto; + ctx->domainname = ses->domainName; + +- /* no hostname for extra channels */ +- ctx->server_hostname = ""; ++ ctx->server_hostname = ses->server->hostname; + + ctx->username = ses->user_name; + ctx->password = ses->password; +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 399185ca7cacb0..72903265b17069 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -411,14 +411,23 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, + if (!rc && + (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) && + server->ops->query_server_interfaces) { +- mutex_unlock(&ses->session_mutex); +- + /* +- * query server network interfaces, in case they change ++ * query server network interfaces, in case they change. ++ * Also mark the session as pending this update while the query ++ * is in progress. This will be used to avoid calling ++ * smb2_reconnect recursively. + */ ++ ses->flags |= CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES; + xid = get_xid(); + rc = server->ops->query_server_interfaces(xid, tcon, false); + free_xid(xid); ++ ses->flags &= ~CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES; ++ ++ /* regardless of rc value, setup polling */ ++ queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, ++ (SMB_INTERFACE_POLL_INTERVAL * HZ)); ++ ++ mutex_unlock(&ses->session_mutex); + + if (rc == -EOPNOTSUPP && ses->chan_count > 1) { + /* +@@ -438,11 +447,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, + if (ses->chan_max > ses->chan_count && + ses->iface_count && + !SERVER_IS_CHAN(server)) { +- if (ses->chan_count == 1) { ++ if (ses->chan_count == 1) + cifs_server_dbg(VFS, "supports multichannel now\n"); +- queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, +- (SMB_INTERFACE_POLL_INTERVAL * HZ)); +- } + + cifs_try_adding_channels(ses); + } +@@ -560,11 +566,18 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon, + struct TCP_Server_Info *server, + void **request_buf, unsigned int *total_len) + { +- /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */ +- if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) { ++ /* ++ * Skip reconnect in one of the following cases: ++ * 1. For FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs ++ * 2. For FSCTL_QUERY_NETWORK_INTERFACE_INFO IOCTL when called from ++ * smb2_reconnect (indicated by CIFS_SES_FLAG_SCALE_CHANNELS ses flag) ++ */ ++ if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO || ++ (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO && ++ (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES))) + return __smb2_plain_req_init(SMB2_IOCTL, tcon, server, + request_buf, total_len); +- } ++ + return smb2_plain_req_init(SMB2_IOCTL, tcon, server, + request_buf, total_len); + } +diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c +index b0b7254661e926..9d8be034f103f2 100644 +--- a/fs/smb/client/smbdirect.c ++++ b/fs/smb/client/smbdirect.c +@@ -2552,13 +2552,14 @@ static ssize_t smb_extract_folioq_to_rdma(struct iov_iter *iter, + size_t fsize = folioq_folio_size(folioq, slot); + + if (offset < fsize) { +- size_t part = umin(maxsize - ret, fsize - offset); ++ size_t part = umin(maxsize, fsize - offset); + + if (!smb_set_sge(rdma, folio_page(folio, 0), offset, part)) + return -EIO; + + offset += part; + ret += part; ++ maxsize -= part; + } + + if (offset >= fsize) { +@@ -2573,7 +2574,7 @@ static ssize_t smb_extract_folioq_to_rdma(struct iov_iter *iter, + slot = 0; + } + } +- } while (rdma->nr_sge < rdma->max_sge || maxsize > 0); ++ } while (rdma->nr_sge < rdma->max_sge && maxsize > 0); + + iter->folioq = folioq; + iter->folioq_slot = slot; +diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c +index 266af17aa7d99a..191783f553ce88 100644 +--- a/fs/smb/client/transport.c ++++ b/fs/smb/client/transport.c +@@ -1018,14 +1018,16 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) + uint index = 0; + unsigned int min_in_flight = UINT_MAX, max_in_flight = 0; + struct TCP_Server_Info *server = NULL; +- int i; ++ int i, start, cur; + + if (!ses) + return NULL; + + spin_lock(&ses->chan_lock); ++ start = atomic_inc_return(&ses->chan_seq); + for (i = 0; i < ses->chan_count; i++) { +- server = ses->chans[i].server; ++ cur = (start + i) % ses->chan_count; ++ server = ses->chans[cur].server; + if (!server || server->terminate) + continue; + +@@ -1042,17 +1044,15 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) + */ + if (server->in_flight < min_in_flight) { + min_in_flight = server->in_flight; +- index = i; ++ index = cur; + } + if (server->in_flight > max_in_flight) + max_in_flight = server->in_flight; + } + + /* if all channels are equally loaded, fall back to round-robin */ +- if (min_in_flight == max_in_flight) { +- index = (uint)atomic_inc_return(&ses->chan_seq); +- index %= ses->chan_count; +- } ++ if (min_in_flight == max_in_flight) ++ index = (uint)start % ses->chan_count; + + server = ses->chans[index].server; + spin_unlock(&ses->chan_lock); +diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c +index 83764c230e9d4c..3f04a2977ba86c 100644 +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -40,7 +40,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) + kvfree(conn->request_buf); + kfree(conn->preauth_info); + if (atomic_dec_and_test(&conn->refcnt)) { +- ksmbd_free_transport(conn->transport); ++ conn->transport->ops->free_transport(conn->transport); + kfree(conn); + } + } +diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h +index 14620e147dda57..572102098c1080 100644 +--- a/fs/smb/server/connection.h ++++ b/fs/smb/server/connection.h +@@ -132,6 +132,7 @@ struct ksmbd_transport_ops { + void *buf, unsigned int len, + struct smb2_buffer_desc_v1 *desc, + unsigned int desc_len); ++ void (*free_transport)(struct ksmbd_transport *kt); + }; + + struct ksmbd_transport { +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index f2a2be8467c669..c6b990c93bfa75 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1607,17 +1607,18 @@ static int krb5_authenticate(struct ksmbd_work *work, + out_len = work->response_sz - + (le16_to_cpu(rsp->SecurityBufferOffset) + 4); + +- /* Check previous session */ +- prev_sess_id = le64_to_cpu(req->PreviousSessionId); +- if (prev_sess_id && prev_sess_id != sess->id) +- destroy_previous_session(conn, sess->user, prev_sess_id); +- + retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, + out_blob, &out_len); + if (retval) { + ksmbd_debug(SMB, "krb5 authentication failed\n"); + return -EINVAL; + } ++ ++ /* Check previous session */ ++ prev_sess_id = le64_to_cpu(req->PreviousSessionId); ++ if (prev_sess_id && prev_sess_id != sess->id) ++ destroy_previous_session(conn, sess->user, prev_sess_id); ++ + rsp->SecurityBufferLength = cpu_to_le16(out_len); + + if ((conn->sign || server_conf.enforced_signing) || +diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c +index 4998df04ab95ae..64a428a06ace0c 100644 +--- a/fs/smb/server/transport_rdma.c ++++ b/fs/smb/server/transport_rdma.c +@@ -159,7 +159,8 @@ struct smb_direct_transport { + }; + + #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) +- ++#define SMBD_TRANS(t) ((struct smb_direct_transport *)container_of(t, \ ++ struct smb_direct_transport, transport)) + enum { + SMB_DIRECT_MSG_NEGOTIATE_REQ = 0, + SMB_DIRECT_MSG_DATA_TRANSFER +@@ -410,6 +411,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) + return NULL; + } + ++static void smb_direct_free_transport(struct ksmbd_transport *kt) ++{ ++ kfree(SMBD_TRANS(kt)); ++} ++ + static void free_transport(struct smb_direct_transport *t) + { + struct smb_direct_recvmsg *recvmsg; +@@ -455,7 +461,6 @@ static void free_transport(struct smb_direct_transport *t) + + smb_direct_destroy_pools(t); + ksmbd_conn_free(KSMBD_TRANS(t)->conn); +- kfree(t); + } + + static struct smb_direct_sendmsg +@@ -2281,4 +2286,5 @@ static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = { + .read = smb_direct_read, + .rdma_read = smb_direct_rdma_read, + .rdma_write = smb_direct_rdma_write, ++ .free_transport = smb_direct_free_transport, + }; +diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c +index abedf510899a74..4e9f98db9ff409 100644 +--- a/fs/smb/server/transport_tcp.c ++++ b/fs/smb/server/transport_tcp.c +@@ -93,7 +93,7 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk) + return t; + } + +-void ksmbd_free_transport(struct ksmbd_transport *kt) ++static void ksmbd_tcp_free_transport(struct ksmbd_transport *kt) + { + struct tcp_transport *t = TCP_TRANS(kt); + +@@ -656,4 +656,5 @@ static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops = { + .read = ksmbd_tcp_read, + .writev = ksmbd_tcp_writev, + .disconnect = ksmbd_tcp_disconnect, ++ .free_transport = ksmbd_tcp_free_transport, + }; +diff --git a/fs/xattr.c b/fs/xattr.c +index 8ec5b0204bfdc5..600ae97969cf24 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -1479,6 +1479,7 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, + buffer += err; + } + remaining_size -= err; ++ err = 0; + + read_lock(&xattrs->lock); + for (rbp = rb_first(&xattrs->rb_root); rbp; rbp = rb_next(rbp)) { +diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h +index f7b3c4a4b7e7c3..5b9f9a6125484f 100644 +--- a/include/acpi/actypes.h ++++ b/include/acpi/actypes.h +@@ -527,7 +527,7 @@ typedef u64 acpi_integer; + + /* Support for the special RSDP signature (8 characters) */ + +-#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) ++#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, (sizeof(a) < 8) ? ACPI_NAMESEG_SIZE : 8)) + #define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) + + /* Support for OEMx signature (x can be any character) */ +diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h +index 5ae4241959f24e..736dbfdd6321de 100644 +--- a/include/drm/display/drm_dp_helper.h ++++ b/include/drm/display/drm_dp_helper.h +@@ -518,6 +518,11 @@ struct drm_dp_aux { + * @powered_down: If true then the remote endpoint is powered down. + */ + bool powered_down; ++ ++ /** ++ * @no_zero_sized: If the hw can't use zero sized transfers (NVIDIA) ++ */ ++ bool no_zero_sized; + }; + + int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset); +diff --git a/include/linux/acpi.h b/include/linux/acpi.h +index 3f2e93ed973016..fc372bbaa54769 100644 +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -1125,13 +1125,13 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, + + acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b); +-#if defined(CONFIG_SUSPEND) && defined(CONFIG_X86) + struct acpi_s2idle_dev_ops { + struct list_head list_node; + void (*prepare)(void); + void (*check)(void); + void (*restore)(void); + }; ++#if defined(CONFIG_SUSPEND) && defined(CONFIG_X86) + int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg); + void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg); + int acpi_get_lps0_constraint(struct acpi_device *adev); +@@ -1140,6 +1140,13 @@ static inline int acpi_get_lps0_constraint(struct device *dev) + { + return ACPI_STATE_UNKNOWN; + } ++static inline int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg) ++{ ++ return -ENODEV; ++} ++static inline void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg) ++{ ++} + #endif /* CONFIG_SUSPEND && CONFIG_X86 */ + void arch_reserve_mem_area(acpi_physical_address addr, size_t size); + #else +diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h +index 9b02961d65ee66..45f2f278b50a8a 100644 +--- a/include/linux/atmdev.h ++++ b/include/linux/atmdev.h +@@ -249,6 +249,12 @@ static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb) + ATM_SKB(skb)->atm_options = vcc->atm_options; + } + ++static inline void atm_return_tx(struct atm_vcc *vcc, struct sk_buff *skb) ++{ ++ WARN_ON_ONCE(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, ++ &sk_atm(vcc)->sk_wmem_alloc)); ++} ++ + static inline void atm_force_charge(struct atm_vcc *vcc,int truesize) + { + atomic_add(truesize, &sk_atm(vcc)->sk_rmem_alloc); +diff --git a/include/linux/bus/stm32_firewall_device.h b/include/linux/bus/stm32_firewall_device.h +index 5178b72bc92098..eaa7a3f5445072 100644 +--- a/include/linux/bus/stm32_firewall_device.h ++++ b/include/linux/bus/stm32_firewall_device.h +@@ -114,27 +114,30 @@ void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 su + + #else /* CONFIG_STM32_FIREWALL */ + +-int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall, +- unsigned int nb_firewall) ++static inline int stm32_firewall_get_firewall(struct device_node *np, ++ struct stm32_firewall *firewall, ++ unsigned int nb_firewall) + { + return -ENODEV; + } + +-int stm32_firewall_grant_access(struct stm32_firewall *firewall) ++static inline int stm32_firewall_grant_access(struct stm32_firewall *firewall) + { + return -ENODEV; + } + +-void stm32_firewall_release_access(struct stm32_firewall *firewall) ++static inline void stm32_firewall_release_access(struct stm32_firewall *firewall) + { + } + +-int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id) ++static inline int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, ++ u32 subsystem_id) + { + return -ENODEV; + } + +-void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id) ++static inline void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, ++ u32 subsystem_id) + { + } + +diff --git a/include/linux/codetag.h b/include/linux/codetag.h +index 0ee4c21c6dbc7c..5f2b9a1f722c76 100644 +--- a/include/linux/codetag.h ++++ b/include/linux/codetag.h +@@ -36,8 +36,8 @@ union codetag_ref { + struct codetag_type_desc { + const char *section; + size_t tag_size; +- void (*module_load)(struct module *mod, +- struct codetag *start, struct codetag *end); ++ int (*module_load)(struct module *mod, ++ struct codetag *start, struct codetag *end); + void (*module_unload)(struct module *mod, + struct codetag *start, struct codetag *end); + #ifdef CONFIG_MODULES +@@ -89,7 +89,7 @@ void *codetag_alloc_module_section(struct module *mod, const char *name, + unsigned long align); + void codetag_free_module_sections(struct module *mod); + void codetag_module_replaced(struct module *mod, struct module *new_mod); +-void codetag_load_module(struct module *mod); ++int codetag_load_module(struct module *mod); + void codetag_unload_module(struct module *mod); + + #else /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */ +@@ -103,7 +103,7 @@ codetag_alloc_module_section(struct module *mod, const char *name, + unsigned long align) { return NULL; } + static inline void codetag_free_module_sections(struct module *mod) {} + static inline void codetag_module_replaced(struct module *mod, struct module *new_mod) {} +-static inline void codetag_load_module(struct module *mod) {} ++static inline int codetag_load_module(struct module *mod) { return 0; } + static inline void codetag_unload_module(struct module *mod) {} + + #endif /* defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) */ +diff --git a/include/linux/execmem.h b/include/linux/execmem.h +index ca42d5e46ccc6b..3be35680a54fd1 100644 +--- a/include/linux/execmem.h ++++ b/include/linux/execmem.h +@@ -54,7 +54,7 @@ enum execmem_range_flags { + EXECMEM_ROX_CACHE = (1 << 1), + }; + +-#if defined(CONFIG_ARCH_HAS_EXECMEM_ROX) && defined(CONFIG_EXECMEM) ++#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX + /** + * execmem_fill_trapping_insns - set memory to contain instructions that + * will trap +@@ -94,15 +94,9 @@ int execmem_make_temp_rw(void *ptr, size_t size); + * Return: 0 on success or negative error code on failure. + */ + int execmem_restore_rox(void *ptr, size_t size); +- +-/* +- * Called from mark_readonly(), where the system transitions to ROX. +- */ +-void execmem_cache_make_ro(void); + #else + static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; } + static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; } +-static inline void execmem_cache_make_ro(void) { } + #endif + + /** +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +index c24f8bc01045df..5206d63b33860b 100644 +--- a/include/linux/f2fs_fs.h ++++ b/include/linux/f2fs_fs.h +@@ -78,6 +78,7 @@ enum stop_cp_reason { + STOP_CP_REASON_UPDATE_INODE, + STOP_CP_REASON_FLUSH_FAIL, + STOP_CP_REASON_NO_SEGMENT, ++ STOP_CP_REASON_CORRUPTED_FREE_BITMAP, + STOP_CP_REASON_MAX, + }; + +diff --git a/include/linux/fs.h b/include/linux/fs.h +index a4fd649e2c3fcd..ef41a8213a6fa0 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2344,6 +2344,7 @@ struct super_operations { + #define S_CASEFOLD (1 << 15) /* Casefolded file */ + #define S_VERITY (1 << 16) /* Verity file (using fs/verity/) */ + #define S_KERNEL_FILE (1 << 17) /* File is in use by the kernel (eg. fs/cachefiles) */ ++#define S_ANON_INODE (1 << 19) /* Inode is an anonymous inode */ + + /* + * Note that nosuid etc flags are inode-specific: setting some file-system +@@ -2400,6 +2401,7 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags + + #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ + (inode)->i_rdev == WHITEOUT_DEV) ++#define IS_ANON_FILE(inode) ((inode)->i_flags & S_ANON_INODE) + + static inline bool HAS_UNMAPPED_ID(struct mnt_idmap *idmap, + struct inode *inode) +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index 4861a7e304bbf4..9a93e6dbb95e34 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -276,6 +276,7 @@ bool is_hugetlb_entry_migration(pte_t pte); + bool is_hugetlb_entry_hwpoisoned(pte_t pte); + void hugetlb_unshare_all_pmds(struct vm_area_struct *vma); + void fixup_hugetlb_reservations(struct vm_area_struct *vma); ++void hugetlb_split(struct vm_area_struct *vma, unsigned long addr); + + #else /* !CONFIG_HUGETLB_PAGE */ + +@@ -473,6 +474,8 @@ static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma) + { + } + ++static inline void hugetlb_split(struct vm_area_struct *vma, unsigned long addr) {} ++ + #endif /* !CONFIG_HUGETLB_PAGE */ + + #ifndef pgd_write +diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h +index 526fce58165754..ddcdf23d731c47 100644 +--- a/include/linux/mmc/card.h ++++ b/include/linux/mmc/card.h +@@ -329,6 +329,7 @@ struct mmc_card { + #define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */ + #define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */ + #define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */ ++#define MMC_QUIRK_NO_UHS_DDR50_TUNING (1<<18) /* Disable DDR50 tuning */ + + bool written_flag; /* Indicates eMMC has been written since power on */ + bool reenable_cmdq; /* Re-enable Command Queue */ +diff --git a/include/linux/module.h b/include/linux/module.h +index 8050f77c3b64f8..b3329110d6686f 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -586,11 +586,6 @@ struct module { + atomic_t refcnt; + #endif + +-#ifdef CONFIG_MITIGATION_ITS +- int its_num_pages; +- void **its_page_array; +-#endif +- + #ifdef CONFIG_CONSTRUCTORS + /* Constructor functions. */ + ctor_fn_t *ctors; +diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h +index cd7172e6c1bbff..e8462deda6dbf6 100644 +--- a/include/linux/mtd/nand-qpic-common.h ++++ b/include/linux/mtd/nand-qpic-common.h +@@ -199,9 +199,6 @@ + */ + #define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) + +-/* Returns the NAND register physical address */ +-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) +- + /* Returns the dma address for reg read buffer */ + #define reg_buf_dma_addr(chip, vaddr) \ + ((chip)->reg_read_dma + \ +@@ -454,6 +451,7 @@ struct qcom_nand_controller { + struct qcom_nandc_props { + u32 ecc_modes; + u32 dev_cmd_reg_start; ++ u32 bam_offset; + bool supports_bam; + bool nandc_part_of_qpic; + bool qpic_version2; +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 311f145eb4e843..aba653207c0f72 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -62,108 +62,110 @@ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_NO_DATA) + +-#define SPINAND_PAGE_READ_FROM_CACHE_OP(addr, ndummy, buf, len, ...) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, ...) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ + SPI_MEM_OP_ADDR(2, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1), \ + SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(addr, ndummy, buf, len) \ +- SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ ++#define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len) \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ + SPI_MEM_OP_ADDR(2, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \ + SPI_MEM_OP_ADDR(3, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_FAST_OP_3A(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ + SPI_MEM_OP_ADDR(3, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_DTR_OP(addr, ndummy, buf, len, freq) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \ + SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ + SPI_MEM_OP_ADDR(2, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ + SPI_MEM_OP_ADDR(3, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X2_DTR_OP(addr, ndummy, buf, len, freq) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \ + SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, ...) \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ ++ SPI_MEM_OP_ADDR(2, addr, 2), \ ++ SPI_MEM_OP_DUMMY(ndummy, 2), \ ++ SPI_MEM_OP_DATA_IN(len, buf, 2), \ ++ SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0)) ++ ++#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len) \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ ++ SPI_MEM_OP_ADDR(3, addr, 2), \ ++ SPI_MEM_OP_DUMMY(ndummy, 2), \ ++ SPI_MEM_OP_DATA_IN(len, buf, 2)) ++ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ ++ SPI_MEM_DTR_OP_ADDR(2, addr, 2), \ ++ SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \ ++ SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ ++ SPI_MEM_OP_MAX_FREQ(freq)) ++ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ + SPI_MEM_OP_ADDR(2, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ + SPI_MEM_OP_ADDR(3, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_X4_DTR_OP(addr, ndummy, buf, len, freq) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \ + SPI_MEM_DTR_OP_ADDR(2, addr, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \ +- SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ +- SPI_MEM_OP_ADDR(2, addr, 2), \ +- SPI_MEM_OP_DUMMY(ndummy, 2), \ +- SPI_MEM_OP_DATA_IN(len, buf, 2)) +- +-#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \ +- SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ +- SPI_MEM_OP_ADDR(3, addr, 2), \ +- SPI_MEM_OP_DUMMY(ndummy, 2), \ +- SPI_MEM_OP_DATA_IN(len, buf, 2)) +- +-#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_DTR_OP(addr, ndummy, buf, len, freq) \ +- SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ +- SPI_MEM_DTR_OP_ADDR(2, addr, 2), \ +- SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \ +- SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ +- SPI_MEM_OP_MAX_FREQ(freq)) +- +-#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, ...) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ + SPI_MEM_OP_ADDR(2, addr, 4), \ + SPI_MEM_OP_DUMMY(ndummy, 4), \ +- SPI_MEM_OP_DATA_IN(len, buf, 4)) ++ SPI_MEM_OP_DATA_IN(len, buf, 4), \ ++ SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ + SPI_MEM_OP_ADDR(3, addr, 4), \ + SPI_MEM_OP_DUMMY(ndummy, 4), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +-#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_DTR_OP(addr, ndummy, buf, len, freq) \ ++#define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \ + SPI_MEM_DTR_OP_ADDR(2, addr, 4), \ + SPI_MEM_DTR_OP_DUMMY(ndummy, 4), \ +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index 1669d95bb0f9aa..5c7c5038d47b51 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -340,7 +340,7 @@ struct tcp_sock { + } rcv_rtt_est; + /* Receiver queue space */ + struct { +- u32 space; ++ int space; + u32 seq; + u64 time; + } rcvq_space; +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index c498f685d01f3c..5349df59615711 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -5346,22 +5346,6 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, + struct ieee80211_tx_rate *dest, + int max_rates); + +-/** +- * ieee80211_sta_set_expected_throughput - set the expected tpt for a station +- * +- * Call this function to notify mac80211 about a change in expected throughput +- * to a station. A driver for a device that does rate control in firmware can +- * call this function when the expected throughput estimate towards a station +- * changes. The information is used to tune the CoDel AQM applied to traffic +- * going towards that station (which can otherwise be too aggressive and cause +- * slow stations to starve). +- * +- * @pubsta: the station to set throughput for. +- * @thr: the current expected throughput in kbps. +- */ +-void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, +- u32 thr); +- + /** + * ieee80211_tx_rate_update - transmit rate update callback + * +diff --git a/include/trace/events/erofs.h b/include/trace/events/erofs.h +index c69c7b1e41d137..a71b19ed5d0cf6 100644 +--- a/include/trace/events/erofs.h ++++ b/include/trace/events/erofs.h +@@ -211,24 +211,6 @@ TRACE_EVENT(erofs_map_blocks_exit, + show_mflags(__entry->mflags), __entry->ret) + ); + +-TRACE_EVENT(erofs_destroy_inode, +- TP_PROTO(struct inode *inode), +- +- TP_ARGS(inode), +- +- TP_STRUCT__entry( +- __field( dev_t, dev ) +- __field( erofs_nid_t, nid ) +- ), +- +- TP_fast_assign( +- __entry->dev = inode->i_sb->s_dev; +- __entry->nid = EROFS_I(inode)->nid; +- ), +- +- TP_printk("dev = (%d,%d), nid = %llu", show_dev_nid(__entry)) +-); +- + #endif /* _TRACE_EROFS_H */ + + /* This part must be outside protection */ +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index c8cb2796130f8d..af86ece741e94d 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -153,10 +153,18 @@ enum v4l2_buf_type { + V4L2_BUF_TYPE_SDR_OUTPUT = 12, + V4L2_BUF_TYPE_META_CAPTURE = 13, + V4L2_BUF_TYPE_META_OUTPUT = 14, ++ /* ++ * Note: V4L2_TYPE_IS_VALID and V4L2_TYPE_IS_OUTPUT must ++ * be updated if a new type is added. ++ */ + /* Deprecated, do not use */ + V4L2_BUF_TYPE_PRIVATE = 0x80, + }; + ++#define V4L2_TYPE_IS_VALID(type) \ ++ ((type) >= V4L2_BUF_TYPE_VIDEO_CAPTURE &&\ ++ (type) <= V4L2_BUF_TYPE_META_OUTPUT) ++ + #define V4L2_TYPE_IS_MULTIPLANAR(type) \ + ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \ + || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) +@@ -164,14 +172,14 @@ enum v4l2_buf_type { + #define V4L2_TYPE_IS_OUTPUT(type) \ + ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \ + || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \ +- || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \ + || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \ + || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \ + || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT \ + || (type) == V4L2_BUF_TYPE_SDR_OUTPUT \ + || (type) == V4L2_BUF_TYPE_META_OUTPUT) + +-#define V4L2_TYPE_IS_CAPTURE(type) (!V4L2_TYPE_IS_OUTPUT(type)) ++#define V4L2_TYPE_IS_CAPTURE(type) \ ++ (V4L2_TYPE_IS_VALID(type) && !V4L2_TYPE_IS_OUTPUT(type)) + + enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, +diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c +index 04a75d66619510..0825c1b30f8fc5 100644 +--- a/io_uring/io-wq.c ++++ b/io_uring/io-wq.c +@@ -1236,8 +1236,10 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data) + atomic_set(&wq->worker_refs, 1); + init_completion(&wq->worker_done); + ret = cpuhp_state_add_instance_nocalls(io_wq_online, &wq->cpuhp_node); +- if (ret) ++ if (ret) { ++ put_task_struct(wq->task); + goto err; ++ } + + return wq; + err: +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index e5466f65682699..74218c7b760483 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -1689,7 +1689,7 @@ static __cold void io_drain_req(struct io_kiocb *req) + spin_unlock(&ctx->completion_lock); + + io_prep_async_link(req); +- de = kmalloc(sizeof(*de), GFP_KERNEL); ++ de = kmalloc(sizeof(*de), GFP_KERNEL_ACCOUNT); + if (!de) { + ret = -ENOMEM; + io_req_defer_failed(req, ret); +diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c +index 953d5e74256916..a8467f6aba54d7 100644 +--- a/io_uring/kbuf.c ++++ b/io_uring/kbuf.c +@@ -270,8 +270,11 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, + /* truncate end piece, if needed, for non partial buffers */ + if (len > arg->max_len) { + len = arg->max_len; +- if (!(bl->flags & IOBL_INC)) ++ if (!(bl->flags & IOBL_INC)) { ++ if (iov != arg->iovs) ++ break; + buf->len = len; ++ } + } + + iov->iov_base = u64_to_user_ptr(buf->addr); +@@ -624,7 +627,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) + io_destroy_bl(ctx, bl); + } + +- free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL); ++ free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL_ACCOUNT); + if (!bl) + return -ENOMEM; + +diff --git a/io_uring/net.c b/io_uring/net.c +index 27f37fa2ef7936..3feceb2b5b97ec 100644 +--- a/io_uring/net.c ++++ b/io_uring/net.c +@@ -829,7 +829,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret, + if (sr->flags & IORING_RECVSEND_BUNDLE) { + size_t this_ret = *ret - sr->done_io; + +- cflags |= io_put_kbufs(req, *ret, io_bundle_nbufs(kmsg, this_ret), ++ cflags |= io_put_kbufs(req, this_ret, io_bundle_nbufs(kmsg, this_ret), + issue_flags); + if (sr->retry) + cflags = req->cqe.flags | (cflags & CQE_F_MASK); +@@ -840,7 +840,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret, + * If more is available AND it was a full transfer, retry and + * append to this one + */ +- if (!sr->retry && kmsg->msg.msg_inq > 0 && this_ret > 0 && ++ if (!sr->retry && kmsg->msg.msg_inq > 1 && this_ret > 0 && + !iov_iter_count(&kmsg->msg.msg_iter)) { + req->cqe.flags = cflags & ~CQE_F_MASK; + sr->len = kmsg->msg.msg_inq; +@@ -1077,7 +1077,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg + arg.mode |= KBUF_MODE_FREE; + } + +- if (kmsg->msg.msg_inq > 0) ++ if (kmsg->msg.msg_inq > 1) + arg.max_len = min_not_zero(sr->len, kmsg->msg.msg_inq); + + ret = io_buffers_peek(req, &arg); +diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c +index f80a77c4973f30..794d4ae6f0bc8d 100644 +--- a/io_uring/rsrc.c ++++ b/io_uring/rsrc.c +@@ -810,10 +810,8 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx, + + imu->nr_bvecs = nr_pages; + ret = io_buffer_account_pin(ctx, pages, nr_pages, imu, last_hpage); +- if (ret) { +- unpin_user_pages(pages, nr_pages); ++ if (ret) + goto done; +- } + + size = iov->iov_len; + /* store original address for later verification */ +@@ -843,6 +841,8 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx, + if (ret) { + if (imu) + io_free_imu(ctx, imu); ++ if (pages) ++ unpin_user_pages(pages, nr_pages); + io_cache_free(&ctx->node_cache, node); + node = ERR_PTR(ret); + } +@@ -1174,6 +1174,8 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx + return -EINVAL; + if (check_add_overflow(arg->nr, arg->dst_off, &nbufs)) + return -EOVERFLOW; ++ if (nbufs > IORING_MAX_REG_BUFFERS) ++ return -EINVAL; + + ret = io_rsrc_data_alloc(&data, max(nbufs, ctx->buf_table.nr)); + if (ret) +diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c +index 268d2fbe6160c2..d3a94cd0f5e656 100644 +--- a/io_uring/sqpoll.c ++++ b/io_uring/sqpoll.c +@@ -419,7 +419,6 @@ void io_sqpoll_wait_sq(struct io_ring_ctx *ctx) + __cold int io_sq_offload_create(struct io_ring_ctx *ctx, + struct io_uring_params *p) + { +- struct task_struct *task_to_put = NULL; + int ret; + + /* Retain compatibility with failing for an invalid attach attempt */ +@@ -498,7 +497,7 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx, + rcu_assign_pointer(sqd->thread, tsk); + mutex_unlock(&sqd->lock); + +- task_to_put = get_task_struct(tsk); ++ get_task_struct(tsk); + ret = io_uring_alloc_task_context(tsk, ctx); + wake_up_new_task(tsk); + if (ret) +@@ -513,8 +512,6 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx, + complete(&ctx->sq_data->exited); + err: + io_sq_thread_finish(ctx); +- if (task_to_put) +- put_task_struct(task_to_put); + return ret; + } + +diff --git a/ipc/shm.c b/ipc/shm.c +index 99564c87008408..492fcc6999857a 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -431,8 +431,11 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data) + void shm_destroy_orphaned(struct ipc_namespace *ns) + { + down_write(&shm_ids(ns).rwsem); +- if (shm_ids(ns).in_use) ++ if (shm_ids(ns).in_use) { ++ rcu_read_lock(); + idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns); ++ rcu_read_unlock(); ++ } + up_write(&shm_ids(ns).rwsem); + } + +diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c +index db13ee70d94d5c..96113633e391a1 100644 +--- a/kernel/bpf/bpf_struct_ops.c ++++ b/kernel/bpf/bpf_struct_ops.c +@@ -601,7 +601,7 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, + if (model->ret_size > 0) + flags |= BPF_TRAMP_F_RET_FENTRY_RET; + +- size = arch_bpf_trampoline_size(model, flags, tlinks, NULL); ++ size = arch_bpf_trampoline_size(model, flags, tlinks, stub_func); + if (size <= 0) + return size ? : -EFAULT; + +diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c +index 16ba36f34dfab7..656ee11aff6762 100644 +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -6829,10 +6829,10 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, + /* Is this a func with potential NULL args? */ + if (strcmp(tname, raw_tp_null_args[i].func)) + continue; +- if (raw_tp_null_args[i].mask & (0x1 << (arg * 4))) ++ if (raw_tp_null_args[i].mask & (0x1ULL << (arg * 4))) + info->reg_type |= PTR_MAYBE_NULL; + /* Is the current arg IS_ERR? */ +- if (raw_tp_null_args[i].mask & (0x2 << (arg * 4))) ++ if (raw_tp_null_args[i].mask & (0x2ULL << (arg * 4))) + ptr_err_raw_tp = true; + break; + } +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index e3a2662f4e3365..a71aa4cb85fae6 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -129,7 +129,8 @@ const struct bpf_func_proto bpf_map_peek_elem_proto = { + + BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu) + { +- WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_trace_held() && ++ !rcu_read_lock_bh_held()); + return (unsigned long) map->ops->map_lookup_percpu_elem(map, key, cpu); + } + +diff --git a/kernel/cgroup/legacy_freezer.c b/kernel/cgroup/legacy_freezer.c +index 039d1eb2f215bb..507b8f19a262e0 100644 +--- a/kernel/cgroup/legacy_freezer.c ++++ b/kernel/cgroup/legacy_freezer.c +@@ -188,13 +188,12 @@ static void freezer_attach(struct cgroup_taskset *tset) + if (!(freezer->state & CGROUP_FREEZING)) { + __thaw_task(task); + } else { +- freeze_task(task); +- + /* clear FROZEN and propagate upwards */ + while (freezer && (freezer->state & CGROUP_FROZEN)) { + freezer->state &= ~CGROUP_FROZEN; + freezer = parent_freezer(freezer); + } ++ freeze_task(task); + } + } + +diff --git a/kernel/events/core.c b/kernel/events/core.c +index e97bc9220fd1a8..2d1131e2cfc02c 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -207,6 +207,19 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, + __perf_ctx_unlock(&cpuctx->ctx); + } + ++typedef struct { ++ struct perf_cpu_context *cpuctx; ++ struct perf_event_context *ctx; ++} class_perf_ctx_lock_t; ++ ++static inline void class_perf_ctx_lock_destructor(class_perf_ctx_lock_t *_T) ++{ perf_ctx_unlock(_T->cpuctx, _T->ctx); } ++ ++static inline class_perf_ctx_lock_t ++class_perf_ctx_lock_constructor(struct perf_cpu_context *cpuctx, ++ struct perf_event_context *ctx) ++{ perf_ctx_lock(cpuctx, ctx); return (class_perf_ctx_lock_t){ cpuctx, ctx }; } ++ + #define TASK_TOMBSTONE ((void *)-1L) + + static bool is_kernel_event(struct perf_event *event) +@@ -944,7 +957,13 @@ static void perf_cgroup_switch(struct task_struct *task) + if (READ_ONCE(cpuctx->cgrp) == cgrp) + return; + +- perf_ctx_lock(cpuctx, cpuctx->task_ctx); ++ guard(perf_ctx_lock)(cpuctx, cpuctx->task_ctx); ++ /* ++ * Re-check, could've raced vs perf_remove_from_context(). ++ */ ++ if (READ_ONCE(cpuctx->cgrp) == NULL) ++ return; ++ + perf_ctx_disable(&cpuctx->ctx, true); + + ctx_sched_out(&cpuctx->ctx, NULL, EVENT_ALL|EVENT_CGROUP); +@@ -962,7 +981,6 @@ static void perf_cgroup_switch(struct task_struct *task) + ctx_sched_in(&cpuctx->ctx, NULL, EVENT_ALL|EVENT_CGROUP); + + perf_ctx_enable(&cpuctx->ctx, true); +- perf_ctx_unlock(cpuctx, cpuctx->task_ctx); + } + + static int perf_cgroup_ensure_storage(struct perf_event *event, +@@ -2145,8 +2163,9 @@ perf_aux_output_match(struct perf_event *event, struct perf_event *aux_event) + } + + static void put_event(struct perf_event *event); +-static void event_sched_out(struct perf_event *event, +- struct perf_event_context *ctx); ++static void __event_disable(struct perf_event *event, ++ struct perf_event_context *ctx, ++ enum perf_event_state state); + + static void perf_put_aux_event(struct perf_event *event) + { +@@ -2179,8 +2198,7 @@ static void perf_put_aux_event(struct perf_event *event) + * state so that we don't try to schedule it again. Note + * that perf_event_enable() will clear the ERROR status. + */ +- event_sched_out(iter, ctx); +- perf_event_set_state(event, PERF_EVENT_STATE_ERROR); ++ __event_disable(iter, ctx, PERF_EVENT_STATE_ERROR); + } + } + +@@ -2238,18 +2256,6 @@ static inline struct list_head *get_event_list(struct perf_event *event) + &event->pmu_ctx->flexible_active; + } + +-/* +- * Events that have PERF_EV_CAP_SIBLING require being part of a group and +- * cannot exist on their own, schedule them out and move them into the ERROR +- * state. Also see _perf_event_enable(), it will not be able to recover +- * this ERROR state. +- */ +-static inline void perf_remove_sibling_event(struct perf_event *event) +-{ +- event_sched_out(event, event->ctx); +- perf_event_set_state(event, PERF_EVENT_STATE_ERROR); +-} +- + static void perf_group_detach(struct perf_event *event) + { + struct perf_event *leader = event->group_leader; +@@ -2285,8 +2291,15 @@ static void perf_group_detach(struct perf_event *event) + */ + list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) { + ++ /* ++ * Events that have PERF_EV_CAP_SIBLING require being part of ++ * a group and cannot exist on their own, schedule them out ++ * and move them into the ERROR state. Also see ++ * _perf_event_enable(), it will not be able to recover this ++ * ERROR state. ++ */ + if (sibling->event_caps & PERF_EV_CAP_SIBLING) +- perf_remove_sibling_event(sibling); ++ __event_disable(sibling, ctx, PERF_EVENT_STATE_ERROR); + + sibling->group_leader = sibling; + list_del_init(&sibling->sibling_list); +@@ -2545,6 +2558,15 @@ static void perf_remove_from_context(struct perf_event *event, unsigned long fla + event_function_call(event, __perf_remove_from_context, (void *)flags); + } + ++static void __event_disable(struct perf_event *event, ++ struct perf_event_context *ctx, ++ enum perf_event_state state) ++{ ++ event_sched_out(event, ctx); ++ perf_cgroup_event_disable(event, ctx); ++ perf_event_set_state(event, state); ++} ++ + /* + * Cross CPU call to disable a performance event + */ +@@ -2559,13 +2581,18 @@ static void __perf_event_disable(struct perf_event *event, + perf_pmu_disable(event->pmu_ctx->pmu); + ctx_time_update_event(ctx, event); + ++ /* ++ * When disabling a group leader, the whole group becomes ineligible ++ * to run, so schedule out the full group. ++ */ + if (event == event->group_leader) + group_sched_out(event, ctx); +- else +- event_sched_out(event, ctx); + +- perf_event_set_state(event, PERF_EVENT_STATE_OFF); +- perf_cgroup_event_disable(event, ctx); ++ /* ++ * But only mark the leader OFF; the siblings will remain ++ * INACTIVE. ++ */ ++ __event_disable(event, ctx, PERF_EVENT_STATE_OFF); + + perf_pmu_enable(event->pmu_ctx->pmu); + } +@@ -7363,6 +7390,10 @@ perf_sample_ustack_size(u16 stack_size, u16 header_size, + if (!regs) + return 0; + ++ /* No mm, no stack, no dump. */ ++ if (!current->mm) ++ return 0; ++ + /* + * Check if we fit in with the requested stack size into the: + * - TASK_SIZE +@@ -8074,6 +8105,9 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) + const u32 max_stack = event->attr.sample_max_stack; + struct perf_callchain_entry *callchain; + ++ if (!current->mm) ++ user = false; ++ + if (!kernel && !user) + return &__empty_callchain; + +diff --git a/kernel/exit.c b/kernel/exit.c +index 1b51dc099f1e05..771dd7b226c18f 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -937,6 +937,15 @@ void __noreturn do_exit(long code) + tsk->exit_code = code; + taskstats_exit(tsk, group_dead); + ++ /* ++ * Since sampling can touch ->mm, make sure to stop everything before we ++ * tear it down. ++ * ++ * Also flushes inherited counters to the parent - before the parent ++ * gets woken up by child-exit notifications. ++ */ ++ perf_event_exit_task(tsk); ++ + exit_mm(); + + if (group_dead) +@@ -953,14 +962,6 @@ void __noreturn do_exit(long code) + exit_task_work(tsk); + exit_thread(tsk); + +- /* +- * Flush inherited counters to the parent - before the parent +- * gets woken up by child-exit notifications. +- * +- * because of cgroup mode, must be called before cgroup_exit() +- */ +- perf_event_exit_task(tsk); +- + sched_autogroup_exit_task(tsk); + cgroup_exit(tsk); + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 5c6ab20240a6d6..9861c2ac5fd500 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -3399,11 +3399,12 @@ static int load_module(struct load_info *info, const char __user *uargs, + goto sysfs_cleanup; + } + ++ if (codetag_load_module(mod)) ++ goto sysfs_cleanup; ++ + /* Get rid of temporary copy. */ + free_copy(info, flags); + +- codetag_load_module(mod); +- + /* Done! */ + trace_module_load(mod); + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index d593d6612ba07e..39fac649aa142a 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -8571,7 +8571,7 @@ void __init sched_init(void) + init_cfs_bandwidth(&root_task_group.cfs_bandwidth, NULL); + #endif /* CONFIG_FAIR_GROUP_SCHED */ + #ifdef CONFIG_EXT_GROUP_SCHED +- root_task_group.scx_weight = CGROUP_WEIGHT_DFL; ++ scx_tg_init(&root_task_group); + #endif /* CONFIG_EXT_GROUP_SCHED */ + #ifdef CONFIG_RT_GROUP_SCHED + root_task_group.rt_se = (struct sched_rt_entity **)ptr; +@@ -9011,7 +9011,7 @@ struct task_group *sched_create_group(struct task_group *parent) + if (!alloc_rt_sched_group(tg, parent)) + goto err; + +- scx_group_set_weight(tg, CGROUP_WEIGHT_DFL); ++ scx_tg_init(tg); + alloc_uclamp_sched_group(tg, parent); + + return tg; +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index f5133249fd4d92..afaf49e5ecb976 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -3936,6 +3936,11 @@ bool scx_can_stop_tick(struct rq *rq) + DEFINE_STATIC_PERCPU_RWSEM(scx_cgroup_rwsem); + static bool scx_cgroup_enabled; + ++void scx_tg_init(struct task_group *tg) ++{ ++ tg->scx_weight = CGROUP_WEIGHT_DFL; ++} ++ + int scx_tg_online(struct task_group *tg) + { + int ret = 0; +diff --git a/kernel/sched/ext.h b/kernel/sched/ext.h +index 1bda96b19a1bf6..d5c02af0ef58e5 100644 +--- a/kernel/sched/ext.h ++++ b/kernel/sched/ext.h +@@ -80,6 +80,7 @@ static inline void scx_update_idle(struct rq *rq, bool idle, bool do_notify) {} + + #ifdef CONFIG_CGROUP_SCHED + #ifdef CONFIG_EXT_GROUP_SCHED ++void scx_tg_init(struct task_group *tg); + int scx_tg_online(struct task_group *tg); + void scx_tg_offline(struct task_group *tg); + int scx_cgroup_can_attach(struct cgroup_taskset *tset); +@@ -89,6 +90,7 @@ void scx_cgroup_cancel_attach(struct cgroup_taskset *tset); + void scx_group_set_weight(struct task_group *tg, unsigned long cgrp_weight); + void scx_group_set_idle(struct task_group *tg, bool idle); + #else /* CONFIG_EXT_GROUP_SCHED */ ++static inline void scx_tg_init(struct task_group *tg) {} + static inline int scx_tg_online(struct task_group *tg) { return 0; } + static inline void scx_tg_offline(struct task_group *tg) {} + static inline int scx_cgroup_can_attach(struct cgroup_taskset *tset) { return 0; } +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 0c04ed41485259..138d9f4658d5f8 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -3795,6 +3795,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, + update_entity_lag(cfs_rq, se); + se->deadline -= se->vruntime; + se->rel_deadline = 1; ++ cfs_rq->nr_queued--; + if (!curr) + __dequeue_entity(cfs_rq, se); + update_load_sub(&cfs_rq->load, se->load.weight); +@@ -3821,10 +3822,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, + + enqueue_load_avg(cfs_rq, se); + if (se->on_rq) { +- update_load_add(&cfs_rq->load, se->load.weight); + place_entity(cfs_rq, se, 0); ++ update_load_add(&cfs_rq->load, se->load.weight); + if (!curr) + __enqueue_entity(cfs_rq, se); ++ cfs_rq->nr_queued++; + + /* + * The entity's vruntime has been adjusted, so let's check +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index fa03ec3ed56a20..bfcb8b0a1e2c46 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1883,6 +1883,27 @@ static int find_lowest_rq(struct task_struct *task) + return -1; + } + ++static struct task_struct *pick_next_pushable_task(struct rq *rq) ++{ ++ struct task_struct *p; ++ ++ if (!has_pushable_tasks(rq)) ++ return NULL; ++ ++ p = plist_first_entry(&rq->rt.pushable_tasks, ++ struct task_struct, pushable_tasks); ++ ++ BUG_ON(rq->cpu != task_cpu(p)); ++ BUG_ON(task_current(rq, p)); ++ BUG_ON(task_current_donor(rq, p)); ++ BUG_ON(p->nr_cpus_allowed <= 1); ++ ++ BUG_ON(!task_on_rq_queued(p)); ++ BUG_ON(!rt_task(p)); ++ ++ return p; ++} ++ + /* Will lock the rq it finds */ + static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) + { +@@ -1913,18 +1934,16 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) + /* + * We had to unlock the run queue. In + * the mean time, task could have +- * migrated already or had its affinity changed. +- * Also make sure that it wasn't scheduled on its rq. ++ * migrated already or had its affinity changed, ++ * therefore check if the task is still at the ++ * head of the pushable tasks list. + * It is possible the task was scheduled, set + * "migrate_disabled" and then got preempted, so we must + * check the task migration disable flag here too. + */ +- if (unlikely(task_rq(task) != rq || ++ if (unlikely(is_migration_disabled(task) || + !cpumask_test_cpu(lowest_rq->cpu, &task->cpus_mask) || +- task_on_cpu(rq, task) || +- !rt_task(task) || +- is_migration_disabled(task) || +- !task_on_rq_queued(task))) { ++ task != pick_next_pushable_task(rq))) { + + double_unlock_balance(rq, lowest_rq); + lowest_rq = NULL; +@@ -1944,27 +1963,6 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) + return lowest_rq; + } + +-static struct task_struct *pick_next_pushable_task(struct rq *rq) +-{ +- struct task_struct *p; +- +- if (!has_pushable_tasks(rq)) +- return NULL; +- +- p = plist_first_entry(&rq->rt.pushable_tasks, +- struct task_struct, pushable_tasks); +- +- BUG_ON(rq->cpu != task_cpu(p)); +- BUG_ON(task_current(rq, p)); +- BUG_ON(task_current_donor(rq, p)); +- BUG_ON(p->nr_cpus_allowed <= 1); +- +- BUG_ON(!task_on_rq_queued(p)); +- BUG_ON(!rt_task(p)); +- +- return p; +-} +- + /* + * If the current CPU has more than one RT task, see if the non + * running task can migrate over to a CPU that is running a task +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index bb48498ebb5a80..6a8bc7da906263 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -310,7 +310,7 @@ static void clocksource_verify_choose_cpus(void) + { + int cpu, i, n = verify_n_cpus; + +- if (n < 0) { ++ if (n < 0 || n >= num_online_cpus()) { + /* Check all of the CPUs. */ + cpumask_copy(&cpus_chosen, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &cpus_chosen); +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 6981830c312859..6859675516f756 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -7395,9 +7395,10 @@ void ftrace_release_mod(struct module *mod) + + mutex_lock(&ftrace_lock); + +- if (ftrace_disabled) +- goto out_unlock; +- ++ /* ++ * To avoid the UAF problem after the module is unloaded, the ++ * 'mod_map' resource needs to be released unconditionally. ++ */ + list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) { + if (mod_map->mod == mod) { + list_del_rcu(&mod_map->list); +@@ -7406,6 +7407,9 @@ void ftrace_release_mod(struct module *mod) + } + } + ++ if (ftrace_disabled) ++ goto out_unlock; ++ + /* + * Each module has its own ftrace_pages, remove + * them from the list. +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 766cb3cd254e05..14e1e1ed55058d 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -6032,6 +6032,7 @@ unsigned long trace_adjust_address(struct trace_array *tr, unsigned long addr) + struct trace_module_delta *module_delta; + struct trace_scratch *tscratch; + struct trace_mod_entry *entry; ++ unsigned long raddr; + int idx = 0, nr_entries; + + /* If we don't have last boot delta, return the address */ +@@ -6045,7 +6046,9 @@ unsigned long trace_adjust_address(struct trace_array *tr, unsigned long addr) + module_delta = READ_ONCE(tr->module_delta); + if (!module_delta || !tscratch->nr_entries || + tscratch->entries[0].mod_addr > addr) { +- return addr + tr->text_delta; ++ raddr = addr + tr->text_delta; ++ return __is_kernel(raddr) || is_kernel_core_data(raddr) || ++ is_kernel_rodata(raddr) ? raddr : addr; + } + + /* Note that entries must be sorted. */ +diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c +index 2048560264bb48..cca676f651b108 100644 +--- a/kernel/trace/trace_events_filter.c ++++ b/kernel/trace/trace_events_filter.c +@@ -1335,22 +1335,137 @@ static void filter_free_subsystem_preds(struct trace_subsystem_dir *dir, + } + } + ++struct filter_list { ++ struct list_head list; ++ struct event_filter *filter; ++}; ++ ++struct filter_head { ++ struct list_head list; ++ struct rcu_head rcu; ++}; ++ ++ ++static void free_filter_list(struct rcu_head *rhp) ++{ ++ struct filter_head *filter_list = container_of(rhp, struct filter_head, rcu); ++ struct filter_list *filter_item, *tmp; ++ ++ list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) { ++ __free_filter(filter_item->filter); ++ list_del(&filter_item->list); ++ kfree(filter_item); ++ } ++ kfree(filter_list); ++} ++ ++static void free_filter_list_tasks(struct rcu_head *rhp) ++{ ++ call_rcu(rhp, free_filter_list); ++} ++ ++/* ++ * The tracepoint_synchronize_unregister() is a double rcu call. ++ * It calls synchronize_rcu_tasks_trace() followed by synchronize_rcu(). ++ * Instead of waiting for it, simply call these via the call_rcu*() ++ * variants. ++ */ ++static void delay_free_filter(struct filter_head *head) ++{ ++ call_rcu_tasks_trace(&head->rcu, free_filter_list_tasks); ++} ++ ++static void try_delay_free_filter(struct event_filter *filter) ++{ ++ struct filter_head *head; ++ struct filter_list *item; ++ ++ head = kmalloc(sizeof(*head), GFP_KERNEL); ++ if (!head) ++ goto free_now; ++ ++ INIT_LIST_HEAD(&head->list); ++ ++ item = kmalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) { ++ kfree(head); ++ goto free_now; ++ } ++ ++ item->filter = filter; ++ list_add_tail(&item->list, &head->list); ++ delay_free_filter(head); ++ return; ++ ++ free_now: ++ /* Make sure the filter is not being used */ ++ tracepoint_synchronize_unregister(); ++ __free_filter(filter); ++} ++ + static inline void __free_subsystem_filter(struct trace_event_file *file) + { + __free_filter(file->filter); + file->filter = NULL; + } + ++static inline void event_set_filter(struct trace_event_file *file, ++ struct event_filter *filter) ++{ ++ rcu_assign_pointer(file->filter, filter); ++} ++ ++static inline void event_clear_filter(struct trace_event_file *file) ++{ ++ RCU_INIT_POINTER(file->filter, NULL); ++} ++ + static void filter_free_subsystem_filters(struct trace_subsystem_dir *dir, +- struct trace_array *tr) ++ struct trace_array *tr, ++ struct event_filter *filter) + { + struct trace_event_file *file; ++ struct filter_head *head; ++ struct filter_list *item; ++ ++ head = kmalloc(sizeof(*head), GFP_KERNEL); ++ if (!head) ++ goto free_now; ++ ++ INIT_LIST_HEAD(&head->list); ++ ++ item = kmalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) ++ goto free_now; ++ ++ item->filter = filter; ++ list_add_tail(&item->list, &head->list); + + list_for_each_entry(file, &tr->events, list) { + if (file->system != dir) + continue; +- __free_subsystem_filter(file); ++ item = kmalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) ++ goto free_now; ++ item->filter = event_filter(file); ++ list_add_tail(&item->list, &head->list); ++ event_clear_filter(file); ++ } ++ ++ delay_free_filter(head); ++ return; ++ free_now: ++ tracepoint_synchronize_unregister(); ++ ++ if (head) ++ free_filter_list(&head->rcu); ++ ++ list_for_each_entry(file, &tr->events, list) { ++ if (file->system != dir || !file->filter) ++ continue; ++ __free_filter(file->filter); + } ++ __free_filter(filter); + } + + int filter_assign_type(const char *type) +@@ -2120,22 +2235,6 @@ static inline void event_set_filtered_flag(struct trace_event_file *file) + trace_buffered_event_enable(); + } + +-static inline void event_set_filter(struct trace_event_file *file, +- struct event_filter *filter) +-{ +- rcu_assign_pointer(file->filter, filter); +-} +- +-static inline void event_clear_filter(struct trace_event_file *file) +-{ +- RCU_INIT_POINTER(file->filter, NULL); +-} +- +-struct filter_list { +- struct list_head list; +- struct event_filter *filter; +-}; +- + static int process_system_preds(struct trace_subsystem_dir *dir, + struct trace_array *tr, + struct filter_parse_error *pe, +@@ -2144,11 +2243,16 @@ static int process_system_preds(struct trace_subsystem_dir *dir, + struct trace_event_file *file; + struct filter_list *filter_item; + struct event_filter *filter = NULL; +- struct filter_list *tmp; +- LIST_HEAD(filter_list); ++ struct filter_head *filter_list; + bool fail = true; + int err; + ++ filter_list = kmalloc(sizeof(*filter_list), GFP_KERNEL); ++ if (!filter_list) ++ return -ENOMEM; ++ ++ INIT_LIST_HEAD(&filter_list->list); ++ + list_for_each_entry(file, &tr->events, list) { + + if (file->system != dir) +@@ -2175,7 +2279,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir, + if (!filter_item) + goto fail_mem; + +- list_add_tail(&filter_item->list, &filter_list); ++ list_add_tail(&filter_item->list, &filter_list->list); + /* + * Regardless of if this returned an error, we still + * replace the filter for the call. +@@ -2195,31 +2299,22 @@ static int process_system_preds(struct trace_subsystem_dir *dir, + * Do a synchronize_rcu() and to ensure all calls are + * done with them before we free them. + */ +- tracepoint_synchronize_unregister(); +- list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { +- __free_filter(filter_item->filter); +- list_del(&filter_item->list); +- kfree(filter_item); +- } ++ delay_free_filter(filter_list); + return 0; + fail: + /* No call succeeded */ +- list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { +- list_del(&filter_item->list); +- kfree(filter_item); +- } ++ free_filter_list(&filter_list->rcu); + parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0); + return -EINVAL; + fail_mem: + __free_filter(filter); ++ + /* If any call succeeded, we still need to sync */ + if (!fail) +- tracepoint_synchronize_unregister(); +- list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { +- __free_filter(filter_item->filter); +- list_del(&filter_item->list); +- kfree(filter_item); +- } ++ delay_free_filter(filter_list); ++ else ++ free_filter_list(&filter_list->rcu); ++ + return -ENOMEM; + } + +@@ -2361,9 +2456,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string) + + event_clear_filter(file); + +- /* Make sure the filter is not being used */ +- tracepoint_synchronize_unregister(); +- __free_filter(filter); ++ try_delay_free_filter(filter); + + return 0; + } +@@ -2387,11 +2480,8 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string) + + event_set_filter(file, filter); + +- if (tmp) { +- /* Make sure the call is done with the filter */ +- tracepoint_synchronize_unregister(); +- __free_filter(tmp); +- } ++ if (tmp) ++ try_delay_free_filter(tmp); + } + + return err; +@@ -2417,9 +2507,7 @@ int apply_subsystem_event_filter(struct trace_subsystem_dir *dir, + filter = system->filter; + system->filter = NULL; + /* Ensure all filters are no longer used */ +- tracepoint_synchronize_unregister(); +- filter_free_subsystem_filters(dir, tr); +- __free_filter(filter); ++ filter_free_subsystem_filters(dir, tr, filter); + return 0; + } + +diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c +index 0c357a89c58e01..e9eab4a021ab74 100644 +--- a/kernel/trace/trace_functions_graph.c ++++ b/kernel/trace/trace_functions_graph.c +@@ -475,10 +475,16 @@ static int graph_trace_init(struct trace_array *tr) + return 0; + } + ++static struct tracer graph_trace; ++ + static int ftrace_graph_trace_args(struct trace_array *tr, int set) + { + trace_func_graph_ent_t entry; + ++ /* Do nothing if the current tracer is not this tracer */ ++ if (tr->current_trace != &graph_trace) ++ return 0; ++ + if (set) + entry = trace_graph_entry_args; + else +diff --git a/kernel/watchdog.c b/kernel/watchdog.c +index 9fa2af9dbf2cec..2d283e92be5abc 100644 +--- a/kernel/watchdog.c ++++ b/kernel/watchdog.c +@@ -47,6 +47,7 @@ int __read_mostly watchdog_user_enabled = 1; + static int __read_mostly watchdog_hardlockup_user_enabled = WATCHDOG_HARDLOCKUP_DEFAULT; + static int __read_mostly watchdog_softlockup_user_enabled = 1; + int __read_mostly watchdog_thresh = 10; ++static int __read_mostly watchdog_thresh_next; + static int __read_mostly watchdog_hardlockup_available; + + struct cpumask watchdog_cpumask __read_mostly; +@@ -870,12 +871,20 @@ int lockup_detector_offline_cpu(unsigned int cpu) + return 0; + } + +-static void __lockup_detector_reconfigure(void) ++static void __lockup_detector_reconfigure(bool thresh_changed) + { + cpus_read_lock(); + watchdog_hardlockup_stop(); + + softlockup_stop_all(); ++ /* ++ * To prevent watchdog_timer_fn from using the old interval and ++ * the new watchdog_thresh at the same time, which could lead to ++ * false softlockup reports, it is necessary to update the ++ * watchdog_thresh after the softlockup is completed. ++ */ ++ if (thresh_changed) ++ watchdog_thresh = READ_ONCE(watchdog_thresh_next); + set_sample_period(); + lockup_detector_update_enable(); + if (watchdog_enabled && watchdog_thresh) +@@ -888,7 +897,7 @@ static void __lockup_detector_reconfigure(void) + void lockup_detector_reconfigure(void) + { + mutex_lock(&watchdog_mutex); +- __lockup_detector_reconfigure(); ++ __lockup_detector_reconfigure(false); + mutex_unlock(&watchdog_mutex); + } + +@@ -908,27 +917,29 @@ static __init void lockup_detector_setup(void) + return; + + mutex_lock(&watchdog_mutex); +- __lockup_detector_reconfigure(); ++ __lockup_detector_reconfigure(false); + softlockup_initialized = true; + mutex_unlock(&watchdog_mutex); + } + + #else /* CONFIG_SOFTLOCKUP_DETECTOR */ +-static void __lockup_detector_reconfigure(void) ++static void __lockup_detector_reconfigure(bool thresh_changed) + { + cpus_read_lock(); + watchdog_hardlockup_stop(); ++ if (thresh_changed) ++ watchdog_thresh = READ_ONCE(watchdog_thresh_next); + lockup_detector_update_enable(); + watchdog_hardlockup_start(); + cpus_read_unlock(); + } + void lockup_detector_reconfigure(void) + { +- __lockup_detector_reconfigure(); ++ __lockup_detector_reconfigure(false); + } + static inline void lockup_detector_setup(void) + { +- __lockup_detector_reconfigure(); ++ __lockup_detector_reconfigure(false); + } + #endif /* !CONFIG_SOFTLOCKUP_DETECTOR */ + +@@ -946,11 +957,11 @@ void lockup_detector_soft_poweroff(void) + #ifdef CONFIG_SYSCTL + + /* Propagate any changes to the watchdog infrastructure */ +-static void proc_watchdog_update(void) ++static void proc_watchdog_update(bool thresh_changed) + { + /* Remove impossible cpus to keep sysctl output clean. */ + cpumask_and(&watchdog_cpumask, &watchdog_cpumask, cpu_possible_mask); +- __lockup_detector_reconfigure(); ++ __lockup_detector_reconfigure(thresh_changed); + } + + /* +@@ -984,7 +995,7 @@ static int proc_watchdog_common(int which, const struct ctl_table *table, int wr + } else { + err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (!err && old != READ_ONCE(*param)) +- proc_watchdog_update(); ++ proc_watchdog_update(false); + } + mutex_unlock(&watchdog_mutex); + return err; +@@ -1035,11 +1046,13 @@ static int proc_watchdog_thresh(const struct ctl_table *table, int write, + + mutex_lock(&watchdog_mutex); + +- old = READ_ONCE(watchdog_thresh); ++ watchdog_thresh_next = READ_ONCE(watchdog_thresh); ++ ++ old = watchdog_thresh_next; + err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + +- if (!err && write && old != READ_ONCE(watchdog_thresh)) +- proc_watchdog_update(); ++ if (!err && write && old != READ_ONCE(watchdog_thresh_next)) ++ proc_watchdog_update(true); + + mutex_unlock(&watchdog_mutex); + return err; +@@ -1060,7 +1073,7 @@ static int proc_watchdog_cpumask(const struct ctl_table *table, int write, + + err = proc_do_large_bitmap(table, write, buffer, lenp, ppos); + if (!err && write) +- proc_watchdog_update(); ++ proc_watchdog_update(false); + + mutex_unlock(&watchdog_mutex); + return err; +@@ -1080,7 +1093,7 @@ static const struct ctl_table watchdog_sysctls[] = { + }, + { + .procname = "watchdog_thresh", +- .data = &watchdog_thresh, ++ .data = &watchdog_thresh_next, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_watchdog_thresh, +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index cf620328273757..c8083dd3001670 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -3241,7 +3241,7 @@ __acquires(&pool->lock) + * point will only record its address. + */ + trace_workqueue_execute_end(work, worker->current_func); +- pwq->stats[PWQ_STAT_COMPLETED]++; ++ + lock_map_release(&lockdep_map); + if (!bh_draining) + lock_map_release(pwq->wq->lockdep_map); +@@ -3272,6 +3272,8 @@ __acquires(&pool->lock) + + raw_spin_lock_irq(&pool->lock); + ++ pwq->stats[PWQ_STAT_COMPLETED]++; ++ + /* + * In addition to %WQ_CPU_INTENSIVE, @worker may also have been marked + * CPU intensive by wq_worker_tick() if @work hogged CPU longer than +@@ -7754,7 +7756,8 @@ void __init workqueue_init_early(void) + restrict_unbound_cpumask("workqueue.unbound_cpus", &wq_cmdline_cpumask); + + cpumask_copy(wq_requested_unbound_cpumask, wq_unbound_cpumask); +- ++ cpumask_andnot(wq_isolated_cpumask, cpu_possible_mask, ++ housekeeping_cpumask(HK_TYPE_DOMAIN)); + pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); + + unbound_wq_update_pwq_attrs_buf = alloc_workqueue_attrs(); +diff --git a/lib/Kconfig b/lib/Kconfig +index 6c1b8f1842678c..37db228f70a99f 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -716,6 +716,7 @@ config GENERIC_LIB_DEVMEM_IS_ALLOWED + + config PLDMFW + bool ++ select CRC32 + default n + + config ASN1_ENCODER +diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c +index c7f602fa7b23fc..ac72849b5da93a 100644 +--- a/lib/alloc_tag.c ++++ b/lib/alloc_tag.c +@@ -618,15 +618,16 @@ static void release_module_tags(struct module *mod, bool used) + mas_unlock(&mas); + } + +-static void load_module(struct module *mod, struct codetag *start, struct codetag *stop) ++static int load_module(struct module *mod, struct codetag *start, struct codetag *stop) + { + /* Allocate module alloc_tag percpu counters */ + struct alloc_tag *start_tag; + struct alloc_tag *stop_tag; + struct alloc_tag *tag; + ++ /* percpu counters for core allocations are already statically allocated */ + if (!mod) +- return; ++ return 0; + + start_tag = ct_to_alloc_tag(start); + stop_tag = ct_to_alloc_tag(stop); +@@ -638,12 +639,13 @@ static void load_module(struct module *mod, struct codetag *start, struct codeta + free_percpu(tag->counters); + tag->counters = NULL; + } +- shutdown_mem_profiling(true); +- pr_err("Failed to allocate memory for allocation tag percpu counters in the module %s. Memory allocation profiling is disabled!\n", ++ pr_err("Failed to allocate memory for allocation tag percpu counters in the module %s\n", + mod->name); +- break; ++ return -ENOMEM; + } + } ++ ++ return 0; + } + + static void replace_module(struct module *mod, struct module *new_mod) +diff --git a/lib/codetag.c b/lib/codetag.c +index de332e98d6f5b5..650d54d7e14da6 100644 +--- a/lib/codetag.c ++++ b/lib/codetag.c +@@ -167,6 +167,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) + { + struct codetag_range range; + struct codetag_module *cmod; ++ int mod_id; + int err; + + range = get_section_range(mod, cttype->desc.section); +@@ -190,11 +191,20 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod) + cmod->range = range; + + down_write(&cttype->mod_lock); +- err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL); +- if (err >= 0) { +- cttype->count += range_size(cttype, &range); +- if (cttype->desc.module_load) +- cttype->desc.module_load(mod, range.start, range.stop); ++ mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL); ++ if (mod_id >= 0) { ++ if (cttype->desc.module_load) { ++ err = cttype->desc.module_load(mod, range.start, range.stop); ++ if (!err) ++ cttype->count += range_size(cttype, &range); ++ else ++ idr_remove(&cttype->mod_idr, mod_id); ++ } else { ++ cttype->count += range_size(cttype, &range); ++ err = 0; ++ } ++ } else { ++ err = mod_id; + } + up_write(&cttype->mod_lock); + +@@ -295,17 +305,23 @@ void codetag_module_replaced(struct module *mod, struct module *new_mod) + mutex_unlock(&codetag_lock); + } + +-void codetag_load_module(struct module *mod) ++int codetag_load_module(struct module *mod) + { + struct codetag_type *cttype; ++ int ret = 0; + + if (!mod) +- return; ++ return 0; + + mutex_lock(&codetag_lock); +- list_for_each_entry(cttype, &codetag_types, link) +- codetag_module_init(cttype, mod); ++ list_for_each_entry(cttype, &codetag_types, link) { ++ ret = codetag_module_init(cttype, mod); ++ if (ret) ++ break; ++ } + mutex_unlock(&codetag_lock); ++ ++ return ret; + } + + void codetag_unload_module(struct module *mod) +diff --git a/mm/execmem.c b/mm/execmem.c +index 6f7a2653b280ed..e6c4f5076ca8d8 100644 +--- a/mm/execmem.c ++++ b/mm/execmem.c +@@ -254,34 +254,6 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) + return ptr; + } + +-static bool execmem_cache_rox = false; +- +-void execmem_cache_make_ro(void) +-{ +- struct maple_tree *free_areas = &execmem_cache.free_areas; +- struct maple_tree *busy_areas = &execmem_cache.busy_areas; +- MA_STATE(mas_free, free_areas, 0, ULONG_MAX); +- MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX); +- struct mutex *mutex = &execmem_cache.mutex; +- void *area; +- +- execmem_cache_rox = true; +- +- mutex_lock(mutex); +- +- mas_for_each(&mas_free, area, ULONG_MAX) { +- unsigned long pages = mas_range_len(&mas_free) >> PAGE_SHIFT; +- set_memory_ro(mas_free.index, pages); +- } +- +- mas_for_each(&mas_busy, area, ULONG_MAX) { +- unsigned long pages = mas_range_len(&mas_busy) >> PAGE_SHIFT; +- set_memory_ro(mas_busy.index, pages); +- } +- +- mutex_unlock(mutex); +-} +- + static int execmem_cache_populate(struct execmem_range *range, size_t size) + { + unsigned long vm_flags = VM_ALLOW_HUGE_VMAP; +@@ -302,15 +274,9 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size) + /* fill memory with instructions that will trap */ + execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true); + +- if (execmem_cache_rox) { +- err = set_memory_rox((unsigned long)p, vm->nr_pages); +- if (err) +- goto err_free_mem; +- } else { +- err = set_memory_x((unsigned long)p, vm->nr_pages); +- if (err) +- goto err_free_mem; +- } ++ err = set_memory_rox((unsigned long)p, vm->nr_pages); ++ if (err) ++ goto err_free_mem; + + err = execmem_cache_add(p, alloc_size); + if (err) +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 6a3cf7935c1499..395857ca8118b4 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -120,7 +120,7 @@ static void hugetlb_vma_lock_free(struct vm_area_struct *vma); + static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma); + static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma); + static void hugetlb_unshare_pmds(struct vm_area_struct *vma, +- unsigned long start, unsigned long end); ++ unsigned long start, unsigned long end, bool take_locks); + static struct resv_map *vma_resv_map(struct vm_area_struct *vma); + + static void hugetlb_free_folio(struct folio *folio) +@@ -5426,26 +5426,40 @@ static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr) + { + if (addr & ~(huge_page_mask(hstate_vma(vma)))) + return -EINVAL; ++ return 0; ++} + ++void hugetlb_split(struct vm_area_struct *vma, unsigned long addr) ++{ + /* + * PMD sharing is only possible for PUD_SIZE-aligned address ranges + * in HugeTLB VMAs. If we will lose PUD_SIZE alignment due to this + * split, unshare PMDs in the PUD_SIZE interval surrounding addr now. ++ * This function is called in the middle of a VMA split operation, with ++ * MM, VMA and rmap all write-locked to prevent concurrent page table ++ * walks (except hardware and gup_fast()). + */ ++ vma_assert_write_locked(vma); ++ i_mmap_assert_write_locked(vma->vm_file->f_mapping); ++ + if (addr & ~PUD_MASK) { +- /* +- * hugetlb_vm_op_split is called right before we attempt to +- * split the VMA. We will need to unshare PMDs in the old and +- * new VMAs, so let's unshare before we split. +- */ + unsigned long floor = addr & PUD_MASK; + unsigned long ceil = floor + PUD_SIZE; + +- if (floor >= vma->vm_start && ceil <= vma->vm_end) +- hugetlb_unshare_pmds(vma, floor, ceil); ++ if (floor >= vma->vm_start && ceil <= vma->vm_end) { ++ /* ++ * Locking: ++ * Use take_locks=false here. ++ * The file rmap lock is already held. ++ * The hugetlb VMA lock can't be taken when we already ++ * hold the file rmap lock, and we don't need it because ++ * its purpose is to synchronize against concurrent page ++ * table walks, which are not possible thanks to the ++ * locks held by our caller. ++ */ ++ hugetlb_unshare_pmds(vma, floor, ceil, /* take_locks = */ false); ++ } + } +- +- return 0; + } + + static unsigned long hugetlb_vm_op_pagesize(struct vm_area_struct *vma) +@@ -7614,6 +7628,13 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, + return 0; + + pud_clear(pud); ++ /* ++ * Once our caller drops the rmap lock, some other process might be ++ * using this page table as a normal, non-hugetlb page table. ++ * Wait for pending gup_fast() in other threads to finish before letting ++ * that happen. ++ */ ++ tlb_remove_table_sync_one(); + ptdesc_pmd_pts_dec(virt_to_ptdesc(ptep)); + mm_dec_nr_pmds(mm); + return 1; +@@ -7884,9 +7905,16 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int re + spin_unlock_irq(&hugetlb_lock); + } + ++/* ++ * If @take_locks is false, the caller must ensure that no concurrent page table ++ * access can happen (except for gup_fast() and hardware page walks). ++ * If @take_locks is true, we take the hugetlb VMA lock (to lock out things like ++ * concurrent page fault handling) and the file rmap lock. ++ */ + static void hugetlb_unshare_pmds(struct vm_area_struct *vma, + unsigned long start, +- unsigned long end) ++ unsigned long end, ++ bool take_locks) + { + struct hstate *h = hstate_vma(vma); + unsigned long sz = huge_page_size(h); +@@ -7910,8 +7938,12 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, + mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, + start, end); + mmu_notifier_invalidate_range_start(&range); +- hugetlb_vma_lock_write(vma); +- i_mmap_lock_write(vma->vm_file->f_mapping); ++ if (take_locks) { ++ hugetlb_vma_lock_write(vma); ++ i_mmap_lock_write(vma->vm_file->f_mapping); ++ } else { ++ i_mmap_assert_write_locked(vma->vm_file->f_mapping); ++ } + for (address = start; address < end; address += PUD_SIZE) { + ptep = hugetlb_walk(vma, address, sz); + if (!ptep) +@@ -7921,8 +7953,10 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, + spin_unlock(ptl); + } + flush_hugetlb_tlb_range(vma, start, end); +- i_mmap_unlock_write(vma->vm_file->f_mapping); +- hugetlb_vma_unlock_write(vma); ++ if (take_locks) { ++ i_mmap_unlock_write(vma->vm_file->f_mapping); ++ hugetlb_vma_unlock_write(vma); ++ } + /* + * No need to call mmu_notifier_arch_invalidate_secondary_tlbs(), see + * Documentation/mm/mmu_notifier.rst. +@@ -7937,7 +7971,8 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, + void hugetlb_unshare_all_pmds(struct vm_area_struct *vma) + { + hugetlb_unshare_pmds(vma, ALIGN(vma->vm_start, PUD_SIZE), +- ALIGN_DOWN(vma->vm_end, PUD_SIZE)); ++ ALIGN_DOWN(vma->vm_end, PUD_SIZE), ++ /* take_locks = */ true); + } + + /* +diff --git a/mm/madvise.c b/mm/madvise.c +index b17f684322ad79..f5ddf766c8015e 100644 +--- a/mm/madvise.c ++++ b/mm/madvise.c +@@ -503,6 +503,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, + pte_offset_map_lock(mm, pmd, addr, &ptl); + if (!start_pte) + break; ++ flush_tlb_batched_pending(mm); + arch_enter_lazy_mmu_mode(); + if (!err) + nr = 0; +@@ -736,6 +737,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, + start_pte = pte; + if (!start_pte) + break; ++ flush_tlb_batched_pending(mm); + arch_enter_lazy_mmu_mode(); + if (!err) + nr = 0; +@@ -1830,7 +1832,9 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter, + + /* Drop and reacquire lock to unwind race. */ + madvise_unlock(mm, behavior); +- madvise_lock(mm, behavior); ++ ret = madvise_lock(mm, behavior); ++ if (ret) ++ goto out; + continue; + } + if (ret < 0) +@@ -1839,6 +1843,7 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter, + } + madvise_unlock(mm, behavior); + ++out: + ret = (total_len - iov_iter_count(iter)) ? : ret; + + return ret; +diff --git a/mm/page-writeback.c b/mm/page-writeback.c +index c81624bc396971..20e1d76f1eba3f 100644 +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -520,8 +520,8 @@ static int dirty_ratio_handler(const struct ctl_table *table, int write, void *b + + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (ret == 0 && write && vm_dirty_ratio != old_ratio) { +- writeback_set_ratelimit(); + vm_dirty_bytes = 0; ++ writeback_set_ratelimit(); + } + return ret; + } +diff --git a/mm/readahead.c b/mm/readahead.c +index 6a4e96b69702b3..20d36d6b055ed5 100644 +--- a/mm/readahead.c ++++ b/mm/readahead.c +@@ -690,9 +690,15 @@ EXPORT_SYMBOL_GPL(page_cache_async_ra); + + ssize_t ksys_readahead(int fd, loff_t offset, size_t count) + { ++ struct file *file; ++ const struct inode *inode; ++ + CLASS(fd, f)(fd); ++ if (fd_empty(f)) ++ return -EBADF; + +- if (fd_empty(f) || !(fd_file(f)->f_mode & FMODE_READ)) ++ file = fd_file(f); ++ if (!(file->f_mode & FMODE_READ)) + return -EBADF; + + /* +@@ -700,9 +706,15 @@ ssize_t ksys_readahead(int fd, loff_t offset, size_t count) + * that can execute readahead. If readahead is not possible + * on this file, then we must return -EINVAL. + */ +- if (!fd_file(f)->f_mapping || !fd_file(f)->f_mapping->a_ops || +- (!S_ISREG(file_inode(fd_file(f))->i_mode) && +- !S_ISBLK(file_inode(fd_file(f))->i_mode))) ++ if (!file->f_mapping) ++ return -EINVAL; ++ if (!file->f_mapping->a_ops) ++ return -EINVAL; ++ ++ inode = file_inode(file); ++ if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) ++ return -EINVAL; ++ if (IS_ANON_FILE(inode)) + return -EINVAL; + + return vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED); +diff --git a/mm/vma.c b/mm/vma.c +index a468d4c29c0cd4..81df9487cba0ee 100644 +--- a/mm/vma.c ++++ b/mm/vma.c +@@ -144,6 +144,9 @@ static void init_multi_vma_prep(struct vma_prepare *vp, + vp->file = vma->vm_file; + if (vp->file) + vp->mapping = vma->vm_file->f_mapping; ++ ++ if (vmg && vmg->skip_vma_uprobe) ++ vp->skip_vma_uprobe = true; + } + + /* +@@ -333,10 +336,13 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi, + + if (vp->file) { + i_mmap_unlock_write(vp->mapping); +- uprobe_mmap(vp->vma); + +- if (vp->adj_next) +- uprobe_mmap(vp->adj_next); ++ if (!vp->skip_vma_uprobe) { ++ uprobe_mmap(vp->vma); ++ ++ if (vp->adj_next) ++ uprobe_mmap(vp->adj_next); ++ } + } + + if (vp->remove) { +@@ -510,7 +516,14 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, + init_vma_prep(&vp, vma); + vp.insert = new; + vma_prepare(&vp); ++ ++ /* ++ * Get rid of huge pages and shared page tables straddling the split ++ * boundary. ++ */ + vma_adjust_trans_huge(vma, vma->vm_start, addr, NULL); ++ if (is_vm_hugetlb_page(vma)) ++ hugetlb_split(vma, addr); + + if (new_below) { + vma->vm_start = addr; +@@ -914,26 +927,9 @@ static __must_check struct vm_area_struct *vma_merge_existing_range( + err = dup_anon_vma(next, middle, &anon_dup); + } + +- if (err) ++ if (err || commit_merge(vmg)) + goto abort; + +- err = commit_merge(vmg); +- if (err) { +- VM_WARN_ON(err != -ENOMEM); +- +- if (anon_dup) +- unlink_anon_vmas(anon_dup); +- +- /* +- * We've cleaned up any cloned anon_vma's, no VMAs have been +- * modified, no harm no foul if the user requests that we not +- * report this and just give up, leaving the VMAs unmerged. +- */ +- if (!vmg->give_up_on_oom) +- vmg->state = VMA_MERGE_ERROR_NOMEM; +- return NULL; +- } +- + khugepaged_enter_vma(vmg->target, vmg->flags); + vmg->state = VMA_MERGE_SUCCESS; + return vmg->target; +@@ -942,6 +938,9 @@ static __must_check struct vm_area_struct *vma_merge_existing_range( + vma_iter_set(vmg->vmi, start); + vma_iter_load(vmg->vmi); + ++ if (anon_dup) ++ unlink_anon_vmas(anon_dup); ++ + /* + * This means we have failed to clone anon_vma's correctly, but no + * actual changes to VMAs have occurred, so no harm no foul - if the +@@ -1783,6 +1782,14 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + faulted_in_anon_vma = false; + } + ++ /* ++ * If the VMA we are copying might contain a uprobe PTE, ensure ++ * that we do not establish one upon merge. Otherwise, when mremap() ++ * moves page tables, it will orphan the newly created PTE. ++ */ ++ if (vma->vm_file) ++ vmg.skip_vma_uprobe = true; ++ + new_vma = find_vma_prev(mm, addr, &vmg.prev); + if (new_vma && new_vma->vm_start < addr + len) + return NULL; /* should never get here */ +diff --git a/mm/vma.h b/mm/vma.h +index 149926e8a6d1ac..7e8aa136e6f770 100644 +--- a/mm/vma.h ++++ b/mm/vma.h +@@ -19,6 +19,8 @@ struct vma_prepare { + struct vm_area_struct *insert; + struct vm_area_struct *remove; + struct vm_area_struct *remove2; ++ ++ bool skip_vma_uprobe :1; + }; + + struct unlink_vma_file_batch { +@@ -120,6 +122,11 @@ struct vma_merge_struct { + */ + bool give_up_on_oom :1; + ++ /* ++ * If set, skip uprobe_mmap upon merged vma. ++ */ ++ bool skip_vma_uprobe :1; ++ + /* Internal flags set during merge process: */ + + /* +diff --git a/net/atm/common.c b/net/atm/common.c +index 9b75699992ff92..d7f7976ea13ac6 100644 +--- a/net/atm/common.c ++++ b/net/atm/common.c +@@ -635,6 +635,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) + + skb->dev = NULL; /* for paths shared with net_device interfaces */ + if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { ++ atm_return_tx(vcc, skb); + kfree_skb(skb); + error = -EFAULT; + goto out; +diff --git a/net/atm/lec.c b/net/atm/lec.c +index ded2f0df2ee664..07c01b6f2b2bed 100644 +--- a/net/atm/lec.c ++++ b/net/atm/lec.c +@@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* Device structures */ + static struct net_device *dev_lec[MAX_LEC_ITF]; ++static DEFINE_MUTEX(lec_mutex); + + #if IS_ENABLED(CONFIG_BRIDGE) + static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) +@@ -685,6 +686,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) + int bytes_left; + struct atmlec_ioc ioc_data; + ++ lockdep_assert_held(&lec_mutex); + /* Lecd must be up in this case */ + bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); + if (bytes_left != 0) +@@ -710,6 +712,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) + + static int lec_mcast_attach(struct atm_vcc *vcc, int arg) + { ++ lockdep_assert_held(&lec_mutex); + if (arg < 0 || arg >= MAX_LEC_ITF) + return -EINVAL; + arg = array_index_nospec(arg, MAX_LEC_ITF); +@@ -725,6 +728,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) + int i; + struct lec_priv *priv; + ++ lockdep_assert_held(&lec_mutex); + if (arg < 0) + arg = 0; + if (arg >= MAX_LEC_ITF) +@@ -742,6 +746,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) + snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i); + if (register_netdev(dev_lec[i])) { + free_netdev(dev_lec[i]); ++ dev_lec[i] = NULL; + return -EINVAL; + } + +@@ -904,7 +909,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l) + v = (dev && netdev_priv(dev)) ? + lec_priv_walk(state, l, netdev_priv(dev)) : NULL; + if (!v && dev) { +- dev_put(dev); + /* Partial state reset for the next time we get called */ + dev = NULL; + } +@@ -928,6 +932,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos) + { + struct lec_state *state = seq->private; + ++ mutex_lock(&lec_mutex); + state->itf = 0; + state->dev = NULL; + state->locked = NULL; +@@ -945,8 +950,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v) + if (state->dev) { + spin_unlock_irqrestore(&state->locked->lec_arp_lock, + state->flags); +- dev_put(state->dev); ++ state->dev = NULL; + } ++ mutex_unlock(&lec_mutex); + } + + static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos) +@@ -1003,6 +1009,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + return -ENOIOCTLCMD; + } + ++ mutex_lock(&lec_mutex); + switch (cmd) { + case ATMLEC_CTRL: + err = lecd_attach(vcc, (int)arg); +@@ -1017,6 +1024,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + break; + } + ++ mutex_unlock(&lec_mutex); + return err; + } + +diff --git a/net/atm/raw.c b/net/atm/raw.c +index 2b5f78a7ec3e4a..1e6511ec842cbc 100644 +--- a/net/atm/raw.c ++++ b/net/atm/raw.c +@@ -36,7 +36,7 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb) + + pr_debug("(%d) %d -= %d\n", + vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize); +- WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc)); ++ atm_return_tx(vcc, skb); + dev_kfree_skb_any(skb); + sk->sk_write_space(sk); + } +diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c +index 1820f09ff59ceb..3f24b4ee49c274 100644 +--- a/net/bridge/br_mst.c ++++ b/net/bridge/br_mst.c +@@ -80,10 +80,10 @@ static void br_mst_vlan_set_state(struct net_bridge_vlan_group *vg, + if (br_vlan_get_state(v) == state) + return; + +- br_vlan_set_state(v, state); +- + if (v->vid == vg->pvid) + br_vlan_set_pvid_state(vg, state); ++ ++ br_vlan_set_state(v, state); + } + + int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index dcbf058de1e3b4..7e0b2362b9ee5f 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -2105,12 +2105,17 @@ static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx) + } + } + +-void br_multicast_enable_port(struct net_bridge_port *port) ++static void br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx) + { +- struct net_bridge *br = port->br; ++ struct net_bridge *br = pmctx->port->br; + + spin_lock_bh(&br->multicast_lock); +- __br_multicast_enable_port_ctx(&port->multicast_ctx); ++ if (br_multicast_port_ctx_is_vlan(pmctx) && ++ !(pmctx->vlan->priv_flags & BR_VLFLAG_MCAST_ENABLED)) { ++ spin_unlock_bh(&br->multicast_lock); ++ return; ++ } ++ __br_multicast_enable_port_ctx(pmctx); + spin_unlock_bh(&br->multicast_lock); + } + +@@ -2137,11 +2142,67 @@ static void __br_multicast_disable_port_ctx(struct net_bridge_mcast_port *pmctx) + br_multicast_rport_del_notify(pmctx, del); + } + ++static void br_multicast_disable_port_ctx(struct net_bridge_mcast_port *pmctx) ++{ ++ struct net_bridge *br = pmctx->port->br; ++ ++ spin_lock_bh(&br->multicast_lock); ++ if (br_multicast_port_ctx_is_vlan(pmctx) && ++ !(pmctx->vlan->priv_flags & BR_VLFLAG_MCAST_ENABLED)) { ++ spin_unlock_bh(&br->multicast_lock); ++ return; ++ } ++ ++ __br_multicast_disable_port_ctx(pmctx); ++ spin_unlock_bh(&br->multicast_lock); ++} ++ ++static void br_multicast_toggle_port(struct net_bridge_port *port, bool on) ++{ ++#if IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING) ++ if (br_opt_get(port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) { ++ struct net_bridge_vlan_group *vg; ++ struct net_bridge_vlan *vlan; ++ ++ rcu_read_lock(); ++ vg = nbp_vlan_group_rcu(port); ++ if (!vg) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ /* iterate each vlan, toggle vlan multicast context */ ++ list_for_each_entry_rcu(vlan, &vg->vlan_list, vlist) { ++ struct net_bridge_mcast_port *pmctx = ++ &vlan->port_mcast_ctx; ++ u8 state = br_vlan_get_state(vlan); ++ /* enable vlan multicast context when state is ++ * LEARNING or FORWARDING ++ */ ++ if (on && br_vlan_state_allowed(state, true)) ++ br_multicast_enable_port_ctx(pmctx); ++ else ++ br_multicast_disable_port_ctx(pmctx); ++ } ++ rcu_read_unlock(); ++ return; ++ } ++#endif ++ /* toggle port multicast context when vlan snooping is disabled */ ++ if (on) ++ br_multicast_enable_port_ctx(&port->multicast_ctx); ++ else ++ br_multicast_disable_port_ctx(&port->multicast_ctx); ++} ++ ++void br_multicast_enable_port(struct net_bridge_port *port) ++{ ++ br_multicast_toggle_port(port, true); ++} ++ + void br_multicast_disable_port(struct net_bridge_port *port) + { +- spin_lock_bh(&port->br->multicast_lock); +- __br_multicast_disable_port_ctx(&port->multicast_ctx); +- spin_unlock_bh(&port->br->multicast_lock); ++ br_multicast_toggle_port(port, false); + } + + static int __grp_src_delete_marked(struct net_bridge_port_group *pg) +@@ -4211,6 +4272,32 @@ static void __br_multicast_stop(struct net_bridge_mcast *brmctx) + #endif + } + ++void br_multicast_update_vlan_mcast_ctx(struct net_bridge_vlan *v, u8 state) ++{ ++#if IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING) ++ struct net_bridge *br; ++ ++ if (!br_vlan_should_use(v)) ++ return; ++ ++ if (br_vlan_is_master(v)) ++ return; ++ ++ br = v->port->br; ++ ++ if (!br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) ++ return; ++ ++ if (br_vlan_state_allowed(state, true)) ++ br_multicast_enable_port_ctx(&v->port_mcast_ctx); ++ ++ /* Multicast is not disabled for the vlan when it goes in ++ * blocking state because the timers will expire and stop by ++ * themselves without sending more queries. ++ */ ++#endif ++} ++ + void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, bool on) + { + struct net_bridge *br; +@@ -4304,9 +4391,9 @@ int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on, + __br_multicast_open(&br->multicast_ctx); + list_for_each_entry(p, &br->port_list, list) { + if (on) +- br_multicast_disable_port(p); ++ br_multicast_disable_port_ctx(&p->multicast_ctx); + else +- br_multicast_enable_port(p); ++ br_multicast_enable_port_ctx(&p->multicast_ctx); + } + + list_for_each_entry(vlan, &vg->vlan_list, vlist) +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index 4715a8d6dc3266..c41d315b09d327 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -1052,6 +1052,7 @@ void br_multicast_port_ctx_init(struct net_bridge_port *port, + struct net_bridge_vlan *vlan, + struct net_bridge_mcast_port *pmctx); + void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pmctx); ++void br_multicast_update_vlan_mcast_ctx(struct net_bridge_vlan *v, u8 state); + void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, bool on); + int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on, + struct netlink_ext_ack *extack); +@@ -1502,6 +1503,11 @@ static inline void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pm + { + } + ++static inline void br_multicast_update_vlan_mcast_ctx(struct net_bridge_vlan *v, ++ u8 state) ++{ ++} ++ + static inline void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, + bool on) + { +@@ -1862,7 +1868,9 @@ bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr, + bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range, + const struct net_bridge_vlan *v_opts); + +-/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */ ++/* vlan state manipulation helpers using *_ONCE to annotate lock-free access, ++ * while br_vlan_set_state() may access data protected by multicast_lock. ++ */ + static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v) + { + return READ_ONCE(v->state); +@@ -1871,6 +1879,7 @@ static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v) + static inline void br_vlan_set_state(struct net_bridge_vlan *v, u8 state) + { + WRITE_ONCE(v->state, state); ++ br_multicast_update_vlan_mcast_ctx(v, state); + } + + static inline u8 br_vlan_get_pvid_state(const struct net_bridge_vlan_group *vg) +diff --git a/net/core/dev.c b/net/core/dev.c +index 2b20aadaf9268d..0c66ee5358812b 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -9863,6 +9863,7 @@ int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf) + + return dev->netdev_ops->ndo_bpf(dev, bpf); + } ++EXPORT_SYMBOL_GPL(netif_xdp_propagate); + + u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode) + { +diff --git a/net/core/filter.c b/net/core/filter.c +index 357d26b76c22d9..34f91c3aacb2f1 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -3233,6 +3233,13 @@ static const struct bpf_func_proto bpf_skb_vlan_pop_proto = { + .arg1_type = ARG_PTR_TO_CTX, + }; + ++static void bpf_skb_change_protocol(struct sk_buff *skb, u16 proto) ++{ ++ skb->protocol = htons(proto); ++ if (skb_valid_dst(skb)) ++ skb_dst_drop(skb); ++} ++ + static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) + { + /* Caller already did skb_cow() with len as headroom, +@@ -3329,7 +3336,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) + } + } + +- skb->protocol = htons(ETH_P_IPV6); ++ bpf_skb_change_protocol(skb, ETH_P_IPV6); + skb_clear_hash(skb); + + return 0; +@@ -3359,7 +3366,7 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) + } + } + +- skb->protocol = htons(ETH_P_IP); ++ bpf_skb_change_protocol(skb, ETH_P_IP); + skb_clear_hash(skb); + + return 0; +@@ -3550,10 +3557,10 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff, + /* Match skb->protocol to new outer l3 protocol */ + if (skb->protocol == htons(ETH_P_IP) && + flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6) +- skb->protocol = htons(ETH_P_IPV6); ++ bpf_skb_change_protocol(skb, ETH_P_IPV6); + else if (skb->protocol == htons(ETH_P_IPV6) && + flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4) +- skb->protocol = htons(ETH_P_IP); ++ bpf_skb_change_protocol(skb, ETH_P_IP); + } + + if (skb_is_gso(skb)) { +@@ -3606,10 +3613,10 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, + /* Match skb->protocol to new outer l3 protocol */ + if (skb->protocol == htons(ETH_P_IP) && + flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6) +- skb->protocol = htons(ETH_P_IPV6); ++ bpf_skb_change_protocol(skb, ETH_P_IPV6); + else if (skb->protocol == htons(ETH_P_IPV6) && + flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4) +- skb->protocol = htons(ETH_P_IP); ++ bpf_skb_change_protocol(skb, ETH_P_IP); + + if (skb_is_gso(skb)) { + struct skb_shared_info *shinfo = skb_shinfo(skb); +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 2d9c51f480fb5f..3eabe78c93f4c2 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -836,6 +836,10 @@ static bool page_pool_napi_local(const struct page_pool *pool) + const struct napi_struct *napi; + u32 cpuid; + ++ /* On PREEMPT_RT the softirq can be preempted by the consumer */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ return false; ++ + if (unlikely(!in_softirq())) + return false; + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 74a2d886a35b51..86cc58376392b7 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6220,9 +6220,6 @@ int skb_ensure_writable(struct sk_buff *skb, unsigned int write_len) + if (!pskb_may_pull(skb, write_len)) + return -ENOMEM; + +- if (!skb_frags_readable(skb)) +- return -EFAULT; +- + if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) + return 0; + +diff --git a/net/core/skmsg.c b/net/core/skmsg.c +index 6d689918c2b390..34c51eb1a14fb4 100644 +--- a/net/core/skmsg.c ++++ b/net/core/skmsg.c +@@ -690,7 +690,8 @@ static void sk_psock_backlog(struct work_struct *work) + if (ret <= 0) { + if (ret == -EAGAIN) { + sk_psock_skb_state(psock, state, len, off); +- ++ /* Restore redir info we cleared before */ ++ skb_bpf_set_redir(skb, psock->sk, ingress); + /* Delay slightly to prioritize any + * other work that might be here. + */ +diff --git a/net/core/sock.c b/net/core/sock.c +index 5034d0fbd4a427..3e8c548cb1f878 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -4004,7 +4004,7 @@ static int assign_proto_idx(struct proto *prot) + { + prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR); + +- if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) { ++ if (unlikely(prot->inuse_idx == PROTO_INUSE_NR)) { + pr_err("PROTO_INUSE_NR exhausted\n"); + return -ENOSPC; + } +@@ -4015,7 +4015,7 @@ static int assign_proto_idx(struct proto *prot) + + static void release_proto_idx(struct proto *prot) + { +- if (prot->inuse_idx != PROTO_INUSE_NR - 1) ++ if (prot->inuse_idx != PROTO_INUSE_NR) + clear_bit(prot->inuse_idx, proto_inuse_idx); + } + #else +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 753704f75b2c65..5d7c7efea66cc6 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -189,7 +189,11 @@ const __u8 ip_tos2prio[16] = { + EXPORT_SYMBOL(ip_tos2prio); + + static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); ++#ifndef CONFIG_PREEMPT_RT + #define RT_CACHE_STAT_INC(field) raw_cpu_inc(rt_cache_stat.field) ++#else ++#define RT_CACHE_STAT_INC(field) this_cpu_inc(rt_cache_stat.field) ++#endif + + #ifdef CONFIG_PROC_FS + static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) +diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c +index 1a6b1bc5424514..dd8b60f5c5553e 100644 +--- a/net/ipv4/tcp_fastopen.c ++++ b/net/ipv4/tcp_fastopen.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + void tcp_fastopen_init_key_once(struct net *net) + { +@@ -279,6 +280,8 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, + + refcount_set(&req->rsk_refcnt, 2); + ++ sk_mark_napi_id_set(child, skb); ++ + /* Now finish processing the fastopen child socket. */ + tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, skb); + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index a35018e2d0ba27..bce2a111cc9e05 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -664,10 +664,12 @@ EXPORT_IPV6_MOD(tcp_initialize_rcv_mss); + */ + static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep) + { +- u32 new_sample = tp->rcv_rtt_est.rtt_us; +- long m = sample; ++ u32 new_sample, old_sample = tp->rcv_rtt_est.rtt_us; ++ long m = sample << 3; + +- if (new_sample != 0) { ++ if (old_sample == 0 || m < old_sample) { ++ new_sample = m; ++ } else { + /* If we sample in larger samples in the non-timestamp + * case, we could grossly overestimate the RTT especially + * with chatty applications or bulk transfer apps which +@@ -678,17 +680,9 @@ static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep) + * else with timestamps disabled convergence takes too + * long. + */ +- if (!win_dep) { +- m -= (new_sample >> 3); +- new_sample += m; +- } else { +- m <<= 3; +- if (m < new_sample) +- new_sample = m; +- } +- } else { +- /* No previous measure. */ +- new_sample = m << 3; ++ if (win_dep) ++ return; ++ new_sample = old_sample - (old_sample >> 3) + sample; + } + + tp->rcv_rtt_est.rtt_us = new_sample; +@@ -712,7 +706,7 @@ static inline void tcp_rcv_rtt_measure(struct tcp_sock *tp) + tp->rcv_rtt_est.time = tp->tcp_mstamp; + } + +-static s32 tcp_rtt_tsopt_us(const struct tcp_sock *tp) ++static s32 tcp_rtt_tsopt_us(const struct tcp_sock *tp, u32 min_delta) + { + u32 delta, delta_us; + +@@ -722,7 +716,7 @@ static s32 tcp_rtt_tsopt_us(const struct tcp_sock *tp) + + if (likely(delta < INT_MAX / (USEC_PER_SEC / TCP_TS_HZ))) { + if (!delta) +- delta = 1; ++ delta = min_delta; + delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ); + return delta_us; + } +@@ -740,9 +734,9 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, + + if (TCP_SKB_CB(skb)->end_seq - + TCP_SKB_CB(skb)->seq >= inet_csk(sk)->icsk_ack.rcv_mss) { +- s32 delta = tcp_rtt_tsopt_us(tp); ++ s32 delta = tcp_rtt_tsopt_us(tp, 0); + +- if (delta >= 0) ++ if (delta > 0) + tcp_rcv_rtt_update(tp, delta, 0); + } + } +@@ -754,8 +748,7 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, + void tcp_rcv_space_adjust(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); +- u32 copied; +- int time; ++ int time, inq, copied; + + trace_tcp_rcv_space_adjust(sk); + +@@ -766,6 +759,9 @@ void tcp_rcv_space_adjust(struct sock *sk) + + /* Number of bytes copied to user in last RTT */ + copied = tp->copied_seq - tp->rcvq_space.seq; ++ /* Number of bytes in receive queue. */ ++ inq = tp->rcv_nxt - tp->copied_seq; ++ copied -= inq; + if (copied <= tp->rcvq_space.space) + goto new_measure; + +@@ -2484,20 +2480,33 @@ static inline bool tcp_packet_delayed(const struct tcp_sock *tp) + { + const struct sock *sk = (const struct sock *)tp; + +- if (tp->retrans_stamp && +- tcp_tsopt_ecr_before(tp, tp->retrans_stamp)) +- return true; /* got echoed TS before first retransmission */ ++ /* Received an echoed timestamp before the first retransmission? */ ++ if (tp->retrans_stamp) ++ return tcp_tsopt_ecr_before(tp, tp->retrans_stamp); ++ ++ /* We set tp->retrans_stamp upon the first retransmission of a loss ++ * recovery episode, so normally if tp->retrans_stamp is 0 then no ++ * retransmission has happened yet (likely due to TSQ, which can cause ++ * fast retransmits to be delayed). So if snd_una advanced while ++ * (tp->retrans_stamp is 0 then apparently a packet was merely delayed, ++ * not lost. But there are exceptions where we retransmit but then ++ * clear tp->retrans_stamp, so we check for those exceptions. ++ */ + +- /* Check if nothing was retransmitted (retrans_stamp==0), which may +- * happen in fast recovery due to TSQ. But we ignore zero retrans_stamp +- * in TCP_SYN_SENT, since when we set FLAG_SYN_ACKED we also clear +- * retrans_stamp even if we had retransmitted the SYN. ++ /* (1) For non-SACK connections, tcp_is_non_sack_preventing_reopen() ++ * clears tp->retrans_stamp when snd_una == high_seq. + */ +- if (!tp->retrans_stamp && /* no record of a retransmit/SYN? */ +- sk->sk_state != TCP_SYN_SENT) /* not the FLAG_SYN_ACKED case? */ +- return true; /* nothing was retransmitted */ ++ if (!tcp_is_sack(tp) && !before(tp->snd_una, tp->high_seq)) ++ return false; + +- return false; ++ /* (2) In TCP_SYN_SENT tcp_clean_rtx_queue() clears tp->retrans_stamp ++ * when setting FLAG_SYN_ACKED is set, even if the SYN was ++ * retransmitted. ++ */ ++ if (sk->sk_state == TCP_SYN_SENT) ++ return false; ++ ++ return true; /* tp->retrans_stamp is zero; no retransmit yet */ + } + + /* Undo procedures. */ +@@ -3226,7 +3235,7 @@ static bool tcp_ack_update_rtt(struct sock *sk, const int flag, + */ + if (seq_rtt_us < 0 && tp->rx_opt.saw_tstamp && + tp->rx_opt.rcv_tsecr && flag & FLAG_ACKED) +- seq_rtt_us = ca_rtt_us = tcp_rtt_tsopt_us(tp); ++ seq_rtt_us = ca_rtt_us = tcp_rtt_tsopt_us(tp, 1); + + rs->rtt_us = ca_rtt_us; /* RTT of last (S)ACKed packet (or -1) */ + if (seq_rtt_us < 0) +@@ -6873,6 +6882,9 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + if (!tp->srtt_us) + tcp_synack_rtt_meas(sk, req); + ++ if (tp->rx_opt.tstamp_ok) ++ tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; ++ + if (req) { + tcp_rcv_synrecv_state_fastopen(sk); + } else { +@@ -6898,9 +6910,6 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale; + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + +- if (tp->rx_opt.tstamp_ok) +- tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; +- + if (!inet_csk(sk)->icsk_ca_ops->cong_control) + tcp_update_pacing_rate(sk); + +diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c +index 62618a058b8fad..a247bb93908bf4 100644 +--- a/net/ipv6/calipso.c ++++ b/net/ipv6/calipso.c +@@ -1207,6 +1207,10 @@ static int calipso_req_setattr(struct request_sock *req, + struct ipv6_opt_hdr *old, *new; + struct sock *sk = sk_to_full_sk(req_to_sk(req)); + ++ /* sk is NULL for SYN+ACK w/ SYN Cookie */ ++ if (!sk) ++ return -ENOMEM; ++ + if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt) + old = req_inet->ipv6_opt->hopopt; + else +@@ -1247,6 +1251,10 @@ static void calipso_req_delattr(struct request_sock *req) + struct ipv6_txoptions *txopts; + struct sock *sk = sk_to_full_sk(req_to_sk(req)); + ++ /* sk is NULL for SYN+ACK w/ SYN Cookie */ ++ if (!sk) ++ return; ++ + if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt) + return; + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 9f683f838431da..acfde525fad2fa 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -2904,7 +2904,7 @@ static int ieee80211_scan(struct wiphy *wiphy, + * the frames sent while scanning on other channel will be + * lost) + */ +- if (sdata->deflink.u.ap.beacon && ++ if (ieee80211_num_beaconing_links(sdata) && + (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || + !(req->flags & NL80211_SCAN_FLAG_AP))) + return -EOPNOTSUPP; +diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c +index a8948f4d983e5e..49061bd4151bcf 100644 +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -150,12 +150,6 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, + spin_lock_bh(&local->fq.lock); + rcu_read_lock(); + +- p += scnprintf(p, +- bufsz + buf - p, +- "target %uus interval %uus ecn %s\n", +- codel_time_to_us(sta->cparams.target), +- codel_time_to_us(sta->cparams.interval), +- sta->cparams.ecn ? "yes" : "no"); + p += scnprintf(p, + bufsz + buf - p, + "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n"); +diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c +index c94a9c7ca960ef..91444301a84a4c 100644 +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -636,7 +636,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, + mesh_path_add_gate(mpath); + } + rcu_read_unlock(); +- } else { ++ } else if (ifmsh->mshcfg.dot11MeshForwarding) { + rcu_read_lock(); + mpath = mesh_path_lookup(sdata, target_addr); + if (mpath) { +@@ -654,6 +654,8 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, + } + } + rcu_read_unlock(); ++ } else { ++ forward = false; + } + + if (reply) { +@@ -671,7 +673,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, + } + } + +- if (forward && ifmsh->mshcfg.dot11MeshForwarding) { ++ if (forward) { + u32 preq_id; + u8 hopcount; + +diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c +index 0d056db9f81e63..6a193278005410 100644 +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -990,8 +990,6 @@ int rate_control_set_rates(struct ieee80211_hw *hw, + if (sta->uploaded) + drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); + +- ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta)); +- + return 0; + } + EXPORT_SYMBOL(rate_control_set_rates); +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 248e1f63bf7397..84b18be1f0b16a 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -18,7 +18,6 @@ + #include + #include + +-#include + #include + #include "ieee80211_i.h" + #include "driver-ops.h" +@@ -701,12 +700,6 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata, + } + } + +- sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD; +- sta->cparams.target = MS2TIME(20); +- sta->cparams.interval = MS2TIME(100); +- sta->cparams.ecn = true; +- sta->cparams.ce_threshold_selector = 0; +- sta->cparams.ce_threshold_mask = 0; + + sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); + +@@ -2905,27 +2898,6 @@ unsigned long ieee80211_sta_last_active(struct sta_info *sta) + return sta->deflink.status_stats.last_ack; + } + +-static void sta_update_codel_params(struct sta_info *sta, u32 thr) +-{ +- if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) { +- sta->cparams.target = MS2TIME(50); +- sta->cparams.interval = MS2TIME(300); +- sta->cparams.ecn = false; +- } else { +- sta->cparams.target = MS2TIME(20); +- sta->cparams.interval = MS2TIME(100); +- sta->cparams.ecn = true; +- } +-} +- +-void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, +- u32 thr) +-{ +- struct sta_info *sta = container_of(pubsta, struct sta_info, sta); +- +- sta_update_codel_params(sta, thr); +-} +- + int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) + { + struct ieee80211_sub_if_data *sdata = sta->sdata; +diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h +index 07b7ec39a52f9a..7a95d8d34fca89 100644 +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -466,14 +466,6 @@ struct ieee80211_fragment_cache { + unsigned int next; + }; + +-/* +- * The bandwidth threshold below which the per-station CoDel parameters will be +- * scaled to be more lenient (to prevent starvation of slow stations). This +- * value will be scaled by the number of active stations when it is being +- * applied. +- */ +-#define STA_SLOW_THRESHOLD 6000 /* 6 Mbps */ +- + /** + * struct link_sta_info - Link STA information + * All link specific sta info are stored here for reference. This can be +@@ -626,7 +618,6 @@ struct link_sta_info { + * @sta: station information we share with the driver + * @sta_state: duplicates information about station state (for debug) + * @rcu_head: RCU head used for freeing this station struct +- * @cparams: CoDel parameters for this station. + * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) + * @amsdu_mesh_control: track the mesh A-MSDU format used by the peer: + * +@@ -717,8 +708,6 @@ struct sta_info { + struct dentry *debugfs_dir; + #endif + +- struct codel_params cparams; +- + u8 reserved_tid; + s8 amsdu_mesh_control; + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 20179db88c4a6c..695db38ccfb41a 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1402,16 +1402,9 @@ static struct sk_buff *fq_tin_dequeue_func(struct fq *fq, + + local = container_of(fq, struct ieee80211_local, fq); + txqi = container_of(tin, struct txq_info, tin); ++ cparams = &local->cparams; + cstats = &txqi->cstats; + +- if (txqi->txq.sta) { +- struct sta_info *sta = container_of(txqi->txq.sta, +- struct sta_info, sta); +- cparams = &sta->cparams; +- } else { +- cparams = &local->cparams; +- } +- + if (flow == &tin->default_flow) + cvars = &txqi->def_cvars; + else +@@ -4526,8 +4519,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); + } else if (ieee80211_vif_is_mld(&sdata->vif) && +- sdata->vif.type == NL80211_IFTYPE_AP && +- !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) { ++ ((sdata->vif.type == NL80211_IFTYPE_AP && ++ !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) || ++ (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && ++ !sdata->wdev.use_4addr))) { + ieee80211_mlo_multicast_tx(dev, skb); + } else { + normal: +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 1f63b32d76d678..aab2e79fcff045 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -81,8 +81,8 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) + + if (index < net->mpls.platform_labels) { + struct mpls_route __rcu **platform_label = +- rcu_dereference(net->mpls.platform_label); +- rt = rcu_dereference(platform_label[index]); ++ rcu_dereference_rtnl(net->mpls.platform_label); ++ rt = rcu_dereference_rtnl(platform_label[index]); + } + return rt; + } +diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c +index 0529e4ef752070..c5855069bdaba0 100644 +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -663,6 +663,9 @@ static int pipapo_realloc_mt(struct nft_pipapo_field *f, + check_add_overflow(rules, extra, &rules_alloc)) + return -EOVERFLOW; + ++ if (rules_alloc > (INT_MAX / sizeof(*new_mt))) ++ return -ENOMEM; ++ + new_mt = kvmalloc_array(rules_alloc, sizeof(*new_mt), GFP_KERNEL_ACCOUNT); + if (!new_mt) + return -ENOMEM; +@@ -1499,6 +1502,9 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) + src->groups * NFT_PIPAPO_BUCKETS(src->bb)); + + if (src->rules > 0) { ++ if (src->rules_alloc > (INT_MAX / sizeof(*src->mt))) ++ goto out_mt; ++ + dst->mt = kvmalloc_array(src->rules_alloc, + sizeof(*src->mt), + GFP_KERNEL_ACCOUNT); +diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c +index ed1508a9e093ed..aab107727f186e 100644 +--- a/net/nfc/nci/uart.c ++++ b/net/nfc/nci/uart.c +@@ -119,22 +119,22 @@ static int nci_uart_set_driver(struct tty_struct *tty, unsigned int driver) + + memcpy(nu, nci_uart_drivers[driver], sizeof(struct nci_uart)); + nu->tty = tty; +- tty->disc_data = nu; + skb_queue_head_init(&nu->tx_q); + INIT_WORK(&nu->write_work, nci_uart_write_work); + spin_lock_init(&nu->rx_lock); + + ret = nu->ops.open(nu); + if (ret) { +- tty->disc_data = NULL; + kfree(nu); ++ return ret; + } else if (!try_module_get(nu->owner)) { + nu->ops.close(nu); +- tty->disc_data = NULL; + kfree(nu); + return -ENOENT; + } +- return ret; ++ tty->disc_data = nu; ++ ++ return 0; + } + + /* ------ LDISC part ------ */ +diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c +index 77fa02f2bfcd56..a8cca549b5a2eb 100644 +--- a/net/sched/sch_sfq.c ++++ b/net/sched/sch_sfq.c +@@ -656,6 +656,14 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, + NL_SET_ERR_MSG_MOD(extack, "invalid quantum"); + return -EINVAL; + } ++ ++ if (ctl->perturb_period < 0 || ++ ctl->perturb_period > INT_MAX / HZ) { ++ NL_SET_ERR_MSG_MOD(extack, "invalid perturb period"); ++ return -EINVAL; ++ } ++ perturb_period = ctl->perturb_period * HZ; ++ + if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max, + ctl_v1->Wlog, ctl_v1->Scell_log, NULL)) + return -EINVAL; +@@ -672,14 +680,12 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt, + headdrop = q->headdrop; + maxdepth = q->maxdepth; + maxflows = q->maxflows; +- perturb_period = q->perturb_period; + quantum = q->quantum; + flags = q->flags; + + /* update and validate configuration */ + if (ctl->quantum) + quantum = ctl->quantum; +- perturb_period = ctl->perturb_period * HZ; + if (ctl->flows) + maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS); + if (ctl->divisor) { +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 14021b81232906..2b14c81a87e5c4 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1328,13 +1328,15 @@ static int taprio_dev_notifier(struct notifier_block *nb, unsigned long event, + + stab = rtnl_dereference(q->root->stab); + +- oper = rtnl_dereference(q->oper_sched); ++ rcu_read_lock(); ++ oper = rcu_dereference(q->oper_sched); + if (oper) + taprio_update_queue_max_sdu(q, oper, stab); + +- admin = rtnl_dereference(q->admin_sched); ++ admin = rcu_dereference(q->admin_sched); + if (admin) + taprio_update_queue_max_sdu(q, admin, stab); ++ rcu_read_unlock(); + + break; + } +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 53725ee7ba06d7..b301d64d9d80f3 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -9100,7 +9100,8 @@ static void __sctp_write_space(struct sctp_association *asoc) + wq = rcu_dereference(sk->sk_wq); + if (wq) { + if (waitqueue_active(&wq->wait)) +- wake_up_interruptible(&wq->wait); ++ wake_up_interruptible_poll(&wq->wait, EPOLLOUT | ++ EPOLLWRNORM | EPOLLWRBAND); + + /* Note that we try to include the Async I/O support + * here by modeling from the current TCP/UDP code. +diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c +index 7ce5e28a6c0316..131090f31e6a83 100644 +--- a/net/sunrpc/cache.c ++++ b/net/sunrpc/cache.c +@@ -135,6 +135,8 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail, + + hlist_add_head_rcu(&new->cache_list, head); + detail->entries++; ++ if (detail->nextcheck > new->expiry_time) ++ detail->nextcheck = new->expiry_time + 1; + cache_get(new); + spin_unlock(&detail->hash_lock); + +@@ -462,24 +464,21 @@ static int cache_clean(void) + } + } + ++ spin_lock(¤t_detail->hash_lock); ++ + /* find a non-empty bucket in the table */ +- while (current_detail && +- current_index < current_detail->hash_size && ++ while (current_index < current_detail->hash_size && + hlist_empty(¤t_detail->hash_table[current_index])) + current_index++; + + /* find a cleanable entry in the bucket and clean it, or set to next bucket */ +- +- if (current_detail && current_index < current_detail->hash_size) { ++ if (current_index < current_detail->hash_size) { + struct cache_head *ch = NULL; + struct cache_detail *d; + struct hlist_head *head; + struct hlist_node *tmp; + +- spin_lock(¤t_detail->hash_lock); +- + /* Ok, now to clean this strand */ +- + head = ¤t_detail->hash_table[current_index]; + hlist_for_each_entry_safe(ch, tmp, head, cache_list) { + if (current_detail->nextcheck > ch->expiry_time) +@@ -500,8 +499,10 @@ static int cache_clean(void) + spin_unlock(&cache_list_lock); + if (ch) + sunrpc_end_cache_remove_entry(ch, d); +- } else ++ } else { ++ spin_unlock(¤t_detail->hash_lock); + spin_unlock(&cache_list_lock); ++ } + + return rv; + } +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index e7f9c295d13c03..7b6ec2d4279573 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1369,7 +1369,8 @@ svc_process_common(struct svc_rqst *rqstp) + case SVC_OK: + break; + case SVC_GARBAGE: +- goto err_garbage_args; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; ++ goto err_bad_auth; + case SVC_SYSERR: + goto err_system_err; + case SVC_DENIED: +@@ -1510,14 +1511,6 @@ svc_process_common(struct svc_rqst *rqstp) + *rqstp->rq_accept_statp = rpc_proc_unavail; + goto sendit; + +-err_garbage_args: +- svc_printk(rqstp, "failed to decode RPC header\n"); +- +- if (serv->sv_stats) +- serv->sv_stats->rpcbadfmt++; +- *rqstp->rq_accept_statp = rpc_garbage_args; +- goto sendit; +- + err_system_err: + if (serv->sv_stats) + serv->sv_stats->rpcbadfmt++; +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index ca6172822b68ae..3d7f1413df0233 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -577,6 +577,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + if (newxprt->sc_qp && !IS_ERR(newxprt->sc_qp)) + ib_destroy_qp(newxprt->sc_qp); + rdma_destroy_id(newxprt->sc_cm_id); ++ rpcrdma_rn_unregister(dev, &newxprt->sc_rn); + /* This call to put will destroy the transport */ + svc_xprt_put(&newxprt->sc_xprt); + return NULL; +diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c +index 83cc095846d356..4b10ecf4c26538 100644 +--- a/net/sunrpc/xprtsock.c ++++ b/net/sunrpc/xprtsock.c +@@ -2740,6 +2740,11 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work) + } + rpc_shutdown_client(lower_clnt); + ++ /* Check for ingress data that arrived before the socket's ++ * ->data_ready callback was set up. ++ */ ++ xs_poll_check_readable(upper_transport); ++ + out_unlock: + current_restore_flags(pflags, PF_MEMALLOC); + upper_transport->clnt = NULL; +diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c +index 79f91b6ca8c847..ea5bb131ebd060 100644 +--- a/net/tipc/crypto.c ++++ b/net/tipc/crypto.c +@@ -425,7 +425,7 @@ static void tipc_aead_free(struct rcu_head *rp) + } + free_percpu(aead->tfm_entry); + kfree_sensitive(aead->key); +- kfree(aead); ++ kfree_sensitive(aead); + } + + static int tipc_aead_users(struct tipc_aead __rcu *aead) +diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c +index 108a4cc2e00107..258d6aa4f21ae4 100644 +--- a/net/tipc/udp_media.c ++++ b/net/tipc/udp_media.c +@@ -489,7 +489,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb) + + rtnl_lock(); + b = tipc_bearer_find(net, bname); +- if (!b) { ++ if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) { + rtnl_unlock(); + return -EINVAL; + } +@@ -500,7 +500,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb) + + rtnl_lock(); + b = rtnl_dereference(tn->bearer_list[bid]); +- if (!b) { ++ if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) { + rtnl_unlock(); + return -EINVAL; + } +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index 784a2d124749f5..614b58cb26ab71 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -178,11 +178,27 @@ static inline int verify_replay(struct xfrm_usersa_info *p, + "Replay seq and seq_hi should be 0 for output SA"); + return -EINVAL; + } +- if (rs->oseq_hi && !(p->flags & XFRM_STATE_ESN)) { +- NL_SET_ERR_MSG( +- extack, +- "Replay oseq_hi should be 0 in non-ESN mode for output SA"); +- return -EINVAL; ++ ++ if (!(p->flags & XFRM_STATE_ESN)) { ++ if (rs->oseq_hi) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay oseq_hi should be 0 in non-ESN mode for output SA"); ++ return -EINVAL; ++ } ++ if (rs->oseq == U32_MAX) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay oseq should be less than 0xFFFFFFFF in non-ESN mode for output SA"); ++ return -EINVAL; ++ } ++ } else { ++ if (rs->oseq == U32_MAX && rs->oseq_hi == U32_MAX) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay oseq and oseq_hi should be less than 0xFFFFFFFF for output SA"); ++ return -EINVAL; ++ } + } + if (rs->bmp_len) { + NL_SET_ERR_MSG(extack, "Replay bmp_len should 0 for output SA"); +@@ -196,11 +212,27 @@ static inline int verify_replay(struct xfrm_usersa_info *p, + "Replay oseq and oseq_hi should be 0 for input SA"); + return -EINVAL; + } +- if (rs->seq_hi && !(p->flags & XFRM_STATE_ESN)) { +- NL_SET_ERR_MSG( +- extack, +- "Replay seq_hi should be 0 in non-ESN mode for input SA"); +- return -EINVAL; ++ if (!(p->flags & XFRM_STATE_ESN)) { ++ if (rs->seq_hi) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay seq_hi should be 0 in non-ESN mode for input SA"); ++ return -EINVAL; ++ } ++ ++ if (rs->seq == U32_MAX) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay seq should be less than 0xFFFFFFFF in non-ESN mode for input SA"); ++ return -EINVAL; ++ } ++ } else { ++ if (rs->seq == U32_MAX && rs->seq_hi == U32_MAX) { ++ NL_SET_ERR_MSG( ++ extack, ++ "Replay seq and seq_hi should be less than 0xFFFFFFFF for input SA"); ++ return -EINVAL; ++ } + } + } + +diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler +index f4fcc1eaaeaee8..65cfa72e376be0 100644 +--- a/scripts/Makefile.compiler ++++ b/scripts/Makefile.compiler +@@ -43,7 +43,7 @@ as-instr = $(call try-run,\ + # __cc-option + # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586) + __cc-option = $(call try-run,\ +- $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4)) ++ $(1) -Werror $(2) $(3:-Wno-%=-W%) -c -x c /dev/null -o "$$TMP",$(3),$(4)) + + # cc-option + # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) +@@ -57,7 +57,7 @@ cc-option-yn = $(if $(call cc-option,$1),y,n) + + # cc-disable-warning + # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) +-cc-disable-warning = $(if $(call cc-option,-W$(strip $1)),-Wno-$(strip $1)) ++cc-disable-warning = $(call cc-option,-Wno-$(strip $1)) + + # gcc-min-version + # Usage: cflags-$(call gcc-min-version, 70100) += -foo +diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c +index 90ec4ef1b082f9..61d56b0c2be138 100644 +--- a/security/selinux/xfrm.c ++++ b/security/selinux/xfrm.c +@@ -94,7 +94,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, + + ctx->ctx_doi = XFRM_SC_DOI_LSM; + ctx->ctx_alg = XFRM_SC_ALG_SELINUX; +- ctx->ctx_len = str_len; ++ ctx->ctx_len = str_len + 1; + memcpy(ctx->ctx_str, &uctx[1], str_len); + ctx->ctx_str[str_len] = '\0'; + rc = security_context_to_sid(ctx->ctx_str, str_len, +diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c +index 61d2314834e7b1..d8249d997c2a0b 100644 +--- a/sound/pci/hda/cs35l41_hda_property.c ++++ b/sound/pci/hda/cs35l41_hda_property.c +@@ -31,6 +31,9 @@ struct cs35l41_config { + }; + + static const struct cs35l41_config cs35l41_config_table[] = { ++ { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, ++ { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, ++ { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 }, +@@ -452,6 +455,9 @@ struct cs35l41_prop_model { + static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { + { "CLSA0100", NULL, lenovo_legion_no_acpi }, + { "CLSA0101", NULL, lenovo_legion_no_acpi }, ++ { "CSC3551", "10251826", generic_dsd_config }, ++ { "CSC3551", "1025182C", generic_dsd_config }, ++ { "CSC3551", "10251844", generic_dsd_config }, + { "CSC3551", "10280B27", generic_dsd_config }, + { "CSC3551", "10280B28", generic_dsd_config }, + { "CSC3551", "10280BEB", generic_dsd_config }, +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index 512fb22f5e5eb9..77a2984c3741de 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -2276,6 +2276,8 @@ static const struct snd_pci_quirk power_save_denylist[] = { + SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0), + /* Dell ALC3271 */ + SND_PCI_QUIRK(0x1028, 0x0962, "Dell ALC3271", 0), ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=220210 */ ++ SND_PCI_QUIRK(0x17aa, 0x5079, "Lenovo Thinkpad E15", 0), + {} + }; + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 20ab1fb2195ff6..02a424b7a99204 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -8029,6 +8029,7 @@ enum { + ALC283_FIXUP_DELL_HP_RESUME, + ALC294_FIXUP_ASUS_CS35L41_SPI_2, + ALC274_FIXUP_HP_AIO_BIND_DACS, ++ ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2, + }; + + /* A special fixup for Lenovo C940 and Yoga Duet 7; +@@ -9301,6 +9302,12 @@ static const struct hda_fixup alc269_fixups[] = { + { } + } + }, ++ [ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = cs35l41_fixup_i2c_two, ++ .chained = true, ++ .chain_id = ALC255_FIXUP_PREDATOR_SUBWOOFER ++ }, + [ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -10456,6 +10463,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), ++ SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), + SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), +@@ -10499,6 +10509,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), + SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), + SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), ++ SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), +@@ -10777,6 +10788,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), +@@ -10830,6 +10842,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), ++ SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), +@@ -10894,6 +10907,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), ++ SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), + SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), + SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2), +diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +index 2020c5cfb3d5d7..582c68aee6e589 100644 +--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +@@ -272,7 +272,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, + + /* generate DAI links by each sdw link */ + while (soc_dais->initialised) { +- int current_be_id; ++ int current_be_id = 0; + + ret = create_sdw_dailink(card, soc_dais, dai_links, + ¤t_be_id, codec_conf, sdw_platform_component); +diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c +index c09b1f118a6cc1..75bdd843ca3681 100644 +--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c ++++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c +@@ -219,7 +219,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, + + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { +- int current_be_id; ++ int current_be_id = 0; + + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_be_id, codec_conf); +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index e632f16c910250..3d9da93d22ee84 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -311,6 +311,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "83AS"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83HN"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +@@ -360,7 +367,7 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"), + } + }, +- { ++ { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), +diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c +index 7f219df8be7046..8de7e94d4ba478 100644 +--- a/sound/soc/codecs/tas2770.c ++++ b/sound/soc/codecs/tas2770.c +@@ -156,11 +156,37 @@ static const struct snd_kcontrol_new isense_switch = + static const struct snd_kcontrol_new vsense_switch = + SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1); + ++static int sense_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); ++ struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); ++ ++ /* ++ * Powering up ISENSE/VSENSE requires a trip through the shutdown state. ++ * Do that here to ensure that our changes are applied properly, otherwise ++ * we might end up with non-functional IVSENSE if playback started earlier, ++ * which would break software speaker protection. ++ */ ++ switch (event) { ++ case SND_SOC_DAPM_PRE_REG: ++ return snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, ++ TAS2770_PWR_CTRL_MASK, ++ TAS2770_PWR_CTRL_SHUTDOWN); ++ case SND_SOC_DAPM_POST_REG: ++ return tas2770_update_pwr_ctrl(tas2770); ++ default: ++ return 0; ++ } ++} ++ + static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux), +- SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch), +- SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch), ++ SND_SOC_DAPM_SWITCH_E("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch, ++ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), ++ SND_SOC_DAPM_SWITCH_E("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch, ++ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("OUT"), +diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c +index dd2045a5d26d23..6101d52a73b85e 100644 +--- a/sound/soc/codecs/wcd937x.c ++++ b/sound/soc/codecs/wcd937x.c +@@ -91,7 +91,6 @@ struct wcd937x_priv { + struct regmap_irq_chip *wcd_regmap_irq_chip; + struct regmap_irq_chip_data *irq_chip; + struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; +- struct regulator *buck_supply; + struct snd_soc_jack *jack; + unsigned long status_mask; + s32 micb_ref[WCD937X_MAX_MICBIAS]; +@@ -2945,10 +2944,8 @@ static int wcd937x_probe(struct platform_device *pdev) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); + + ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); +- if (ret) { +- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); ++ if (ret) + return dev_err_probe(dev, ret, "Failed to enable supplies\n"); +- } + + wcd937x_dt_parse_micbias_info(dev, wcd937x); + +@@ -2984,7 +2981,6 @@ static int wcd937x_probe(struct platform_device *pdev) + + err_disable_regulators: + regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); +- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + + return ret; + } +@@ -3001,7 +2997,6 @@ static void wcd937x_remove(struct platform_device *pdev) + pm_runtime_dont_use_autosuspend(dev); + + regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); +- regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + } + + #if defined(CONFIG_OF) +diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c +index 3ae2a212a2e38a..355f7ec8943c24 100644 +--- a/sound/soc/generic/simple-card-utils.c ++++ b/sound/soc/generic/simple-card-utils.c +@@ -1119,12 +1119,16 @@ int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep, + args.np = ep; + dai = snd_soc_get_dai_via_args(&args); + if (dai) { ++ const char *dai_name = snd_soc_dai_name_get(dai); ++ const struct of_phandle_args *dai_args = snd_soc_copy_dai_args(dev, &args); ++ + ret = -ENOMEM; ++ if (!dai_args) ++ goto err; ++ + dlc->of_node = node; +- dlc->dai_name = snd_soc_dai_name_get(dai); +- dlc->dai_args = snd_soc_copy_dai_args(dev, &args); +- if (!dlc->dai_args) +- goto end; ++ dlc->dai_name = dai_name; ++ dlc->dai_args = dai_args; + + goto parse_dai_end; + } +@@ -1154,16 +1158,17 @@ int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep, + * if he unbinded CPU or Codec. + */ + ret = snd_soc_get_dlc(&args, dlc); +- if (ret < 0) { +- of_node_put(node); +- goto end; +- } ++ if (ret < 0) ++ goto err; + + parse_dai_end: + if (is_single_link) + *is_single_link = of_graph_get_endpoint_count(node) == 1; + ret = 0; +-end: ++err: ++ if (ret < 0) ++ of_node_put(node); ++ + return simple_ret(priv, ret); + } + EXPORT_SYMBOL_GPL(graph_util_parse_dai); +diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c +index cfc7f6e41ab5c4..68531183fb60ca 100644 +--- a/sound/soc/meson/meson-card-utils.c ++++ b/sound/soc/meson/meson-card-utils.c +@@ -231,7 +231,7 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, + const char *p)) + { + /* If property is not provided, don't fail ... */ +- if (!of_property_read_bool(card->dev->of_node, propname)) ++ if (!of_property_present(card->dev->of_node, propname)) + return 0; + + /* ... but do fail if it is provided and the parsing fails */ +diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c +index fcc7df75346fc1..a233b80049ee74 100644 +--- a/sound/soc/qcom/sdm845.c ++++ b/sound/soc/qcom/sdm845.c +@@ -91,6 +91,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, + else + ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, + tx_ch, 0, NULL); ++ if (ret != 0 && ret != -ENOTSUPP) { ++ dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret); ++ return ret; ++ } + } + + return 0; +diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c +index 0538c252ba69b1..83c2368170cb5e 100644 +--- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c ++++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c +@@ -190,7 +190,7 @@ int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc + const struct snd_soc_dapm_route *rt_amp_map; + char codec_name[CODEC_NAME_SIZE]; + struct snd_soc_dai *codec_dai; +- int ret; ++ int ret = -EINVAL; + int i; + + rt_amp_map = get_codec_name_and_route(dai, codec_name); +diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c +index 99683f292b5d84..ae4965a9f7649e 100644 +--- a/sound/soc/tegra/tegra210_ahub.c ++++ b/sound/soc/tegra/tegra210_ahub.c +@@ -1359,6 +1359,8 @@ static int tegra_ahub_probe(struct platform_device *pdev) + return -ENOMEM; + + ahub->soc_data = of_device_get_match_data(&pdev->dev); ++ if (!ahub->soc_data) ++ return -ENODEV; + + platform_set_drvdata(pdev, ahub); + +diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c +index 0e9b5431a47f20..faac7df1fbcf02 100644 +--- a/sound/usb/mixer_maps.c ++++ b/sound/usb/mixer_maps.c +@@ -383,6 +383,13 @@ static const struct usbmix_name_map ms_usb_link_map[] = { + { 0 } /* terminator */ + }; + ++/* KTMicro USB */ ++static struct usbmix_name_map s31b2_0022_map[] = { ++ { 23, "Speaker Playback" }, ++ { 18, "Headphone Playback" }, ++ { 0 } ++}; ++ + /* ASUS ROG Zenith II with Realtek ALC1220-VB */ + static const struct usbmix_name_map asus_zenith_ii_map[] = { + { 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */ +@@ -692,6 +699,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { + .id = USB_ID(0x045e, 0x083c), + .map = ms_usb_link_map, + }, ++ { ++ /* KTMicro USB */ ++ .id = USB_ID(0X31b2, 0x0022), ++ .map = s31b2_0022_map, ++ }, + { 0 } /* terminator */ + }; + +diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c +index 3f1d6be512151d..944ebe21a2169a 100644 +--- a/tools/bpf/bpftool/cgroup.c ++++ b/tools/bpf/bpftool/cgroup.c +@@ -318,11 +318,11 @@ static int show_bpf_progs(int cgroup_fd, enum bpf_attach_type type, + + static int do_show(int argc, char **argv) + { +- enum bpf_attach_type type; + int has_attached_progs; + const char *path; + int cgroup_fd; + int ret = -1; ++ unsigned int i; + + query_flags = 0; + +@@ -370,14 +370,14 @@ static int do_show(int argc, char **argv) + "AttachFlags", "Name"); + + btf_vmlinux = libbpf_find_kernel_btf(); +- for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { ++ for (i = 0; i < ARRAY_SIZE(cgroup_attach_types); i++) { + /* + * Not all attach types may be supported, so it's expected, + * that some requests will fail. + * If we were able to get the show for at least one + * attach type, let's return 0. + */ +- if (show_bpf_progs(cgroup_fd, type, 0) == 0) ++ if (show_bpf_progs(cgroup_fd, cgroup_attach_types[i], 0) == 0) + ret = 0; + } + +@@ -400,9 +400,9 @@ static int do_show(int argc, char **argv) + static int do_show_tree_fn(const char *fpath, const struct stat *sb, + int typeflag, struct FTW *ftw) + { +- enum bpf_attach_type type; + int has_attached_progs; + int cgroup_fd; ++ unsigned int i; + + if (typeflag != FTW_D) + return 0; +@@ -434,8 +434,8 @@ static int do_show_tree_fn(const char *fpath, const struct stat *sb, + } + + btf_vmlinux = libbpf_find_kernel_btf(); +- for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) +- show_bpf_progs(cgroup_fd, type, ftw->level); ++ for (i = 0; i < ARRAY_SIZE(cgroup_attach_types); i++) ++ show_bpf_progs(cgroup_fd, cgroup_attach_types[i], ftw->level); + + if (errno == EINVAL) + /* Last attach type does not support query. +diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c +index 38bc6b14b0666a..39b18521d5472c 100644 +--- a/tools/lib/bpf/btf.c ++++ b/tools/lib/bpf/btf.c +@@ -996,7 +996,7 @@ static struct btf *btf_new_empty(struct btf *base_btf) + if (base_btf) { + btf->base_btf = base_btf; + btf->start_id = btf__type_cnt(base_btf); +- btf->start_str_off = base_btf->hdr->str_len; ++ btf->start_str_off = base_btf->hdr->str_len + base_btf->start_str_off; + btf->swapped_endian = base_btf->swapped_endian; + } + +@@ -4390,6 +4390,19 @@ static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id + return true; + } + ++static bool btf_dedup_identical_ptrs(struct btf_dedup *d, __u32 id1, __u32 id2) ++{ ++ struct btf_type *t1, *t2; ++ ++ t1 = btf_type_by_id(d->btf, id1); ++ t2 = btf_type_by_id(d->btf, id2); ++ ++ if (!btf_is_ptr(t1) || !btf_is_ptr(t2)) ++ return false; ++ ++ return t1->type == t2->type; ++} ++ + /* + * Check equivalence of BTF type graph formed by candidate struct/union (we'll + * call it "candidate graph" in this description for brevity) to a type graph +@@ -4522,6 +4535,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, + */ + if (btf_dedup_identical_structs(d, hypot_type_id, cand_id)) + return 1; ++ /* A similar case is again observed for PTRs. */ ++ if (btf_dedup_identical_ptrs(d, hypot_type_id, cand_id)) ++ return 1; + return 0; + } + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 147964bb64c8f4..30cf210261032e 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -14078,6 +14078,12 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) + } + + link = map_skel->link; ++ if (!link) { ++ pr_warn("map '%s': BPF map skeleton link is uninitialized\n", ++ bpf_map__name(map)); ++ continue; ++ } ++ + if (*link) + continue; + +diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py +index dcc2c6b298d603..61deb592306711 100644 +--- a/tools/net/ynl/pyynl/lib/ynl.py ++++ b/tools/net/ynl/pyynl/lib/ynl.py +@@ -231,14 +231,7 @@ class NlMsg: + self.extack['unknown'].append(extack) + + if attr_space: +- # We don't have the ability to parse nests yet, so only do global +- if 'miss-type' in self.extack and 'miss-nest' not in self.extack: +- miss_type = self.extack['miss-type'] +- if miss_type in attr_space.attrs_by_val: +- spec = attr_space.attrs_by_val[miss_type] +- self.extack['miss-type'] = spec['name'] +- if 'doc' in spec: +- self.extack['miss-type-doc'] = spec['doc'] ++ self.annotate_extack(attr_space) + + def _decode_policy(self, raw): + policy = {} +@@ -264,6 +257,18 @@ class NlMsg: + policy['mask'] = attr.as_scalar('u64') + return policy + ++ def annotate_extack(self, attr_space): ++ """ Make extack more human friendly with attribute information """ ++ ++ # We don't have the ability to parse nests yet, so only do global ++ if 'miss-type' in self.extack and 'miss-nest' not in self.extack: ++ miss_type = self.extack['miss-type'] ++ if miss_type in attr_space.attrs_by_val: ++ spec = attr_space.attrs_by_val[miss_type] ++ self.extack['miss-type'] = spec['name'] ++ if 'doc' in spec: ++ self.extack['miss-type-doc'] = spec['doc'] ++ + def cmd(self): + return self.nl_type + +@@ -277,12 +282,12 @@ class NlMsg: + + + class NlMsgs: +- def __init__(self, data, attr_space=None): ++ def __init__(self, data): + self.msgs = [] + + offset = 0 + while offset < len(data): +- msg = NlMsg(data, offset, attr_space=attr_space) ++ msg = NlMsg(data, offset) + offset += msg.nl_len + self.msgs.append(msg) + +@@ -594,7 +599,7 @@ class YnlFamily(SpecFamily): + scalar_selector = self._get_scalar(attr, value["selector"]) + attr_payload = struct.pack("II", scalar_value, scalar_selector) + elif attr['type'] == 'sub-message': +- msg_format = self._resolve_selector(attr, search_attrs) ++ msg_format, _ = self._resolve_selector(attr, search_attrs) + attr_payload = b'' + if msg_format.fixed_header: + attr_payload += self._encode_struct(msg_format.fixed_header, value) +@@ -712,10 +717,10 @@ class YnlFamily(SpecFamily): + raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'") + + spec = sub_msg_spec.formats[value] +- return spec ++ return spec, value + + def _decode_sub_msg(self, attr, attr_spec, search_attrs): +- msg_format = self._resolve_selector(attr_spec, search_attrs) ++ msg_format, _ = self._resolve_selector(attr_spec, search_attrs) + decoded = {} + offset = 0 + if msg_format.fixed_header: +@@ -787,7 +792,7 @@ class YnlFamily(SpecFamily): + + return rsp + +- def _decode_extack_path(self, attrs, attr_set, offset, target): ++ def _decode_extack_path(self, attrs, attr_set, offset, target, search_attrs): + for attr in attrs: + try: + attr_spec = attr_set.attrs_by_val[attr.type] +@@ -801,26 +806,37 @@ class YnlFamily(SpecFamily): + if offset + attr.full_len <= target: + offset += attr.full_len + continue +- if attr_spec['type'] != 'nest': ++ ++ pathname = attr_spec.name ++ if attr_spec['type'] == 'nest': ++ sub_attrs = self.attr_sets[attr_spec['nested-attributes']] ++ search_attrs = SpaceAttrs(sub_attrs, search_attrs.lookup(attr_spec['name'])) ++ elif attr_spec['type'] == 'sub-message': ++ msg_format, value = self._resolve_selector(attr_spec, search_attrs) ++ if msg_format is None: ++ raise Exception(f"Can't resolve sub-message of {attr_spec['name']} for extack") ++ sub_attrs = self.attr_sets[msg_format.attr_set] ++ pathname += f"({value})" ++ else: + raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack") + offset += 4 +- subpath = self._decode_extack_path(NlAttrs(attr.raw), +- self.attr_sets[attr_spec['nested-attributes']], +- offset, target) ++ subpath = self._decode_extack_path(NlAttrs(attr.raw), sub_attrs, ++ offset, target, search_attrs) + if subpath is None: + return None +- return '.' + attr_spec.name + subpath ++ return '.' + pathname + subpath + + return None + +- def _decode_extack(self, request, op, extack): ++ def _decode_extack(self, request, op, extack, vals): + if 'bad-attr-offs' not in extack: + return + + msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set), op) + offset = self.nlproto.msghdr_size() + self._struct_size(op.fixed_header) ++ search_attrs = SpaceAttrs(op.attr_set, vals) + path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, +- extack['bad-attr-offs']) ++ extack['bad-attr-offs'], search_attrs) + if path: + del extack['bad-attr-offs'] + extack['bad-attr'] = path +@@ -1012,7 +1028,7 @@ class YnlFamily(SpecFamily): + for (method, vals, flags) in ops: + op = self.ops[method] + msg = self._encode_message(op, vals, flags, req_seq) +- reqs_by_seq[req_seq] = (op, msg, flags) ++ reqs_by_seq[req_seq] = (op, vals, msg, flags) + payload += msg + req_seq += 1 + +@@ -1023,13 +1039,14 @@ class YnlFamily(SpecFamily): + op_rsp = [] + while not done: + reply = self.sock.recv(self._recv_size) +- nms = NlMsgs(reply, attr_space=op.attr_set) ++ nms = NlMsgs(reply) + self._recv_dbg_print(reply, nms) + for nl_msg in nms: + if nl_msg.nl_seq in reqs_by_seq: +- (op, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq] ++ (op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq] + if nl_msg.extack: +- self._decode_extack(req_msg, op, nl_msg.extack) ++ nl_msg.annotate_extack(op.attr_set) ++ self._decode_extack(req_msg, op, nl_msg.extack, vals) + else: + op = None + req_flags = [] +diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c +index 1d5759d0814174..3a2a8438f9af1b 100644 +--- a/tools/perf/tests/tests-scripts.c ++++ b/tools/perf/tests/tests-scripts.c +@@ -260,6 +260,7 @@ static void append_scripts_in_dir(int dir_fd, + continue; /* Skip scripts that have a separate driver. */ + fd = openat(dir_fd, ent->d_name, O_PATH); + append_scripts_in_dir(fd, result, result_sz); ++ close(fd); + } + for (i = 0; i < n_dirs; i++) /* Clean up */ + zfree(&entlist[i]); +diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c +index a786cbfb0ff56a..83aaf7cda63590 100644 +--- a/tools/perf/util/print-events.c ++++ b/tools/perf/util/print-events.c +@@ -268,6 +268,7 @@ bool is_event_supported(u8 type, u64 config) + ret = evsel__open(evsel, NULL, tmap) >= 0; + } + ++ evsel__close(evsel); + evsel__delete(evsel); + } + +diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile +index 28422c32cc8ff4..334ac9cbb5cd45 100644 +--- a/tools/testing/selftests/x86/Makefile ++++ b/tools/testing/selftests/x86/Makefile +@@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie) + + TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ + check_initial_reg_state sigreturn iopl ioperm \ +- test_vsyscall mov_ss_trap \ ++ test_vsyscall mov_ss_trap sigtrap_loop \ + syscall_arg_fault fsgsbase_restore sigaltstack + TARGETS_C_BOTHBITS += nx_stack + TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ +diff --git a/tools/testing/selftests/x86/sigtrap_loop.c b/tools/testing/selftests/x86/sigtrap_loop.c +new file mode 100644 +index 00000000000000..9d065479e89f94 +--- /dev/null ++++ b/tools/testing/selftests/x86/sigtrap_loop.c +@@ -0,0 +1,101 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2025 Intel Corporation ++ */ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __x86_64__ ++# define REG_IP REG_RIP ++#else ++# define REG_IP REG_EIP ++#endif ++ ++static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags) ++{ ++ struct sigaction sa; ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_sigaction = handler; ++ sa.sa_flags = SA_SIGINFO | flags; ++ sigemptyset(&sa.sa_mask); ++ ++ if (sigaction(sig, &sa, 0)) ++ err(1, "sigaction"); ++ ++ return; ++} ++ ++static void sigtrap(int sig, siginfo_t *info, void *ctx_void) ++{ ++ ucontext_t *ctx = (ucontext_t *)ctx_void; ++ static unsigned int loop_count_on_same_ip; ++ static unsigned long last_trap_ip; ++ ++ if (last_trap_ip == ctx->uc_mcontext.gregs[REG_IP]) { ++ printf("\tTrapped at %016lx\n", last_trap_ip); ++ ++ /* ++ * If the same IP is hit more than 10 times in a row, it is ++ * _considered_ an infinite loop. ++ */ ++ if (++loop_count_on_same_ip > 10) { ++ printf("[FAIL]\tDetected SIGTRAP infinite loop\n"); ++ exit(1); ++ } ++ ++ return; ++ } ++ ++ loop_count_on_same_ip = 0; ++ last_trap_ip = ctx->uc_mcontext.gregs[REG_IP]; ++ printf("\tTrapped at %016lx\n", last_trap_ip); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ sethandler(SIGTRAP, sigtrap, 0); ++ ++ /* ++ * Set the Trap Flag (TF) to single-step the test code, therefore to ++ * trigger a SIGTRAP signal after each instruction until the TF is ++ * cleared. ++ * ++ * Because the arithmetic flags are not significant here, the TF is ++ * set by pushing 0x302 onto the stack and then popping it into the ++ * flags register. ++ * ++ * Four instructions in the following asm code are executed with the ++ * TF set, thus the SIGTRAP handler is expected to run four times. ++ */ ++ printf("[RUN]\tSIGTRAP infinite loop detection\n"); ++ asm volatile( ++#ifdef __x86_64__ ++ /* ++ * Avoid clobbering the redzone ++ * ++ * Equivalent to "sub $128, %rsp", however -128 can be encoded ++ * in a single byte immediate while 128 uses 4 bytes. ++ */ ++ "add $-128, %rsp\n\t" ++#endif ++ "push $0x302\n\t" ++ "popf\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "push $0x202\n\t" ++ "popf\n\t" ++#ifdef __x86_64__ ++ "sub $-128, %rsp\n\t" ++#endif ++ ); ++ ++ printf("[OK]\tNo SIGTRAP infinite loop detected\n"); ++ return 0; ++} +diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h +index 572ab2cea763f5..90eccd19098505 100644 +--- a/tools/testing/vma/vma_internal.h ++++ b/tools/testing/vma/vma_internal.h +@@ -793,6 +793,8 @@ static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, + (void)next; + } + ++static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {} ++ + static inline void vma_iter_free(struct vma_iterator *vmi) + { + mas_destroy(&vmi->mas); +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index 4995d35cf3ec6e..d6ab15dcb4907e 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -227,6 +227,8 @@ long parse_ns_duration(char *val) + # define __NR_sched_setattr 355 + # elif __s390x__ + # define __NR_sched_setattr 345 ++# elif __loongarch__ ++# define __NR_sched_setattr 274 + # endif + #endif +